www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Informal interfaces

reply Fredrik Olsson <peylow gmail.com> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

An interface is a definition of what *must* be implemented.
An informal interface is a definition of what *could* be implemented.


Java's awt uses the EventListener interface for defining delegate object 
that can handle UI controls events. The idea is sound, but the 
implementation has a few flaws.

As it uses events, all methods must be implemented, even if only a 
single event is of interest. To solve this there are classes for most 
interfaces that implements all methods with dummy methods, and then you 
just override what you need. As Jave (And D) does not have multiple 
inheritance this add another restriction; a delegate object can only 
handle a single control (or type of control), not a whole window.


In Cocoa (Objecive-C) interfaces are called protocols, different name, 
same thing. Cocoa also have informal protocols. Event listening 
protocols are informal. An informal protocol only declare what methods 
can be implemented, without enforcing them. Not implementing a method 
simply means that you are not interested int hat event, and the runtime 
will filter it for you.


I suggest that D add support for informal interfaces using one new 
keyword, and one new property on all objects.


First methods in interfaces could be marked with he keyword "optional". 
Marking a method as optional in an interface will make the interface 
informal, just as marking a method abstract in a class will make the 
class abstract. A method marked as optional would have two properties:
1. Not even a warning if unimplemented by a class implementing the 
interface,
2. Calling the method if unimplemented will do nothing if void, or 
return a default value if any other type.
Example:
interface FooDelegate {
   optional void doA();
   optional int askB();
   optional bool isC() = true;
}
All three methods are optional. If doA() is unimplemented nothing will 
happen if it is called. if askB() is called then int.init will be 
returned. And if isC() is called true will be returned.

If any or all of the three are implemented then it is naturaly up to the 
implementation to return a proper value.


I attach a file with a longer example fo how it could be useful and work 
in a real world example.


All problems from Java EventListener paradigm are solved; no need to 
implement unneeded methods, a delegate object can listen to any number 
of objects, the object declaring the informal protocol is also free to 
declare the defaults.


I believe the actual implementation can be very simple. All optional 
methods need to be virtual. Optional methods and unimplemented methods 
have a NULL entry int the virtual method table. A method dispatch that 
normally would be (I use 68k asm for readability :) ):
   move.l 16(a1),a0
   jsr    (a0)
Would now become:
   move.l 16(a1),a0
   beq.s  .skip
   jsr    (a0)
.skip:

A small price to pay, slightly more for non voids. Non default return 
values, anything different from type.init could be a problem, at least 
if no access to the original source. The value to use must be available 
somehow. I have though about letting the optional methods have dumy 
implementation returning the value, that could then be an expression and 
not a constant. But I think the testing for implemented methods would 
become more complex, and calling a method could be more costly that 
testing for NULL and branch, todays CPUs are good at branch prediction.


Secondly all objects need a new property, a simple property to test for 
the availability of a method on objects. I suggest this:

public bool implements(method_signature);

And it would be used something along this line:
if (someObject.implements(doSomething(int))) {
   // prepare some costly stuff stuff
   someObject.doSomething(the_costly_result);
}



// Fredrik Olsson
Oct 02 2006
next sibling parent reply BLS <nanali wanadoo.fr> writes:
Fredrik Olsson schrieb:

I like this idea.

  As Jave (And D) does not have multiple
 inheritance this add another restriction; a delegate object can only 
 handle a single control (or type of control), not a whole window.

Using the *Twin pattern* allow us to model multiple inheritance in languages like D, Java. A pretty straightforward example in Java is available at : http://www.ssw.uni-linz.ac.at/Research/Papers/Moe99/Paper.pdf Björn
Oct 02 2006
parent Josh Stern <josh_usenet phadd.net> writes:
On Mon, 02 Oct 2006 11:57:37 +0200, BLS wrote:

 Fredrik Olsson schrieb:
 
 I like this idea.
 
   As Jave (And D) does not have multiple
 inheritance this add another restriction; a delegate object can only 
 handle a single control (or type of control), not a whole window.

Using the *Twin pattern* allow us to model multiple inheritance in languages like D, Java. A pretty straightforward example in Java is available at : http://www.ssw.uni-linz.ac.at/Research/Papers/Moe99/Paper.pdf

The twin pattern seem like an unattractive last resort for someone faced with an existing language and class hierarchy. If one were designing solutions for the problems related to multiple inheritance, starting from D as it is now, I'd suggest the following: 1) the flexible general solution with a small run-time overhead - allow functions to be written using interfaces as arguments. Implementation could save space on the stack for what would basically be a run-time determined vtable and lazily fill in the values as needed by the function body; 2) efficient (time) code solution - use templates; for extra safety, allow a mechanism for compile time checking that the template argument actually implements the given interface rather than just having a name collision; member templates would make this more convenient, but are not really necessary.
Oct 02 2006
prev sibling next sibling parent Kristian <kjkilpi gmail.com> writes:
On Mon, 02 Oct 2006 11:42:43 +0300, Fredrik Olsson <peylow gmail.com>  
wrote:
 An interface is a definition of what *must* be implemented.
 An informal interface is a definition of what *could* be implemented.

I think informal interfaces would be good to have.
 A small price to pay, slightly more for non voids. Non default return
 values, anything different from type.init could be a problem, at least
 if no access to the original source. The value to use must be available
 somehow. I have though about letting the optional methods have dumy
 implementation returning the value, that could then be an expression and
 not a constant. But I think the testing for implemented methods would
 become more complex, and calling a method could be more costly that
 testing for NULL and branch, todays CPUs are good at branch prediction.

Hmm, if an interface would have a 'static vtable' containing addresses for the default functions (that return the default values), then the calling of functions could be done as follows: 1) Get the address of an function to be called to ADDR. 2) If ADDR is not null, goto case 4. 3) Get the address of the corresponding default function of the interface to ADDR. 4) Call the function pointed by ADDR. (Of course, instead of using static table for function addresses, an interface could have a table pointing to the default values directly.)
Oct 02 2006
prev sibling parent Fredrik Olsson <peylow gmail.com> writes:
Fredrik Olsson skrev:
 I attach a file with a longer example fo how it could be useful and work 
 in a real world example.

Some other places where an informal protocol could be useful could be for a URL-request delegate: interface URLRequestDelegate { optional bool acceptUnsignedCertificateForURL(char[] url) = true optional void userCredentials(char[] url, out char[] usr, out char[] pwd); } Delegating the work would be an easy task, be it automagic, or simply asking the user. And best of all the the delegate informal interfaces would be very clear views of what a class expects of the world. Self-documenting, and easy to model code. Or as a data source delegate for a table view: interface CellValue { char[] toString(); optional void drawInRect(Rect); } interface TableViewDatasource { uint numberOfRows(); CellValue getCellValue(uint row, uint col); optional void setCellValue(CellValue cv, uint row, uint col); } Where implementing numberOfRows and getCellValue are required, and would make a read only table. Optionally implementing setCellValue would make the table view editable as well. // Fredrik Olsson
Oct 02 2006