Thread overview
property magic for inerfaces (please!)
Nov 18, 2006
Hasan Aljudy
Nov 19, 2006
Daniel Keep
Nov 19, 2006
Reiner Pope
Nov 19, 2006
Hasan Aljudy
Nov 19, 2006
Lionello Lunesu
Nov 19, 2006
Reiner Pope
Nov 19, 2006
Hasan Aljudy
Nov 19, 2006
Kristian Kilpi
November 18, 2006
Consider the following hypothetical interface:

interface IPerson
{
    IPerson getFather();
    IPerson getMother();
    IPerson[] getSiblings();
    IPerson[] getChildren();
}

For practical purposes, it would be nice to have some methods defined in that interface, such as:

bool hasChildren()
{
    return getChildren().length != 0;
}

but it's not possible to define this method right in the interface. (Suppose say we really have to have the thing as an interface and not as an abstract class).

A possible solution is to add it to the interface without defining it,

interface IPerson
{
    IPerson getFather();
    IPerson getMother();
    IPerson[] getSiblings();
    IPerson[] getChildren();

    bool hasChildren();
}

while hoping that all classes implemeting this interface would define the method in the same way, i.e.
bool hasChildren()
{
    return getChildren().length != 0;
}
The main problem with this is that it's not practical more complicated functions.

Another solution is to define the function outside of the interface,

bool hasChildren(IPerson dude)
{
    return dude.getChildren().length != 0;
}

The problem with this is that it doesn't feel quiet right when you use it.
...
IPerson guy = .... //something
..
if( hasChildren(guy) )
{
 ....
}

It would be nice if the compiler would allow you to call this method as a property (like with arrays)

if( guy.hasChildren() )
{
 ....
}

Can we have this feature before v1.0?
Basically, a function that takes an interface as a first parameter can be considered a property of that interface.
November 19, 2006

Hasan Aljudy wrote:
> Consider the following hypothetical interface:
> 
> interface IPerson
> {
>     IPerson getFather();
>     IPerson getMother();
>     IPerson[] getSiblings();
>     IPerson[] getChildren();
> }
> 
> For practical purposes, it would be nice to have some methods defined in that interface, such as:
> 
> bool hasChildren()
> {
>     return getChildren().length != 0;
> }
> 
> but it's not possible to define this method right in the interface. (Suppose say we really have to have the thing as an interface and not as an abstract class).
> 
> A possible solution is to add it to the interface without defining it,
> 
> interface IPerson
> {
>     IPerson getFather();
>     IPerson getMother();
>     IPerson[] getSiblings();
>     IPerson[] getChildren();
> 
>     bool hasChildren();
> }
> 
> while hoping that all classes implemeting this interface would define
> the method in the same way, i.e.
> bool hasChildren()
> {
>     return getChildren().length != 0;
> }
> ...

There are two ways of doing this, depending on the situation.

The first is to have an abstract base class, which allows you to add partial implementation.

The other is to provide a mixin for the "default" implementation of certain methods.  For example:

> interface IPerson
> {
>     IPerson getFather();
>     IPerson getMother();
>     IPerson[] getSiblings();
>     IPerson[] getChildren();
>
>     bool hasChildren();
> }
>
> template MPerson
> {
>     bool hasChildren()
>     {
>         return this.getChildren.length != 0;
>     }
> }
>
> class SomePerson : IPerson
> {
>     mixin MPerson;
>
>     // ...
> }

In this case, SomePerson needs to implement the first four methods, but hasChildren is implemented by the mixin.  Ruby does something similar for implementing things like comparison operators, sorting, etc.

Of course, extension methods would be *even cooler*, but this works right now :)

	-- Daniel

-- 
Unlike Knuth, I have neither proven or tried the above; it may not even make sense.

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
November 19, 2006
== Quote from Daniel Keep (daniel.keep.lists@gmail.com)'s article
> There are two ways of doing this, depending on the situation.
> The first is to have an abstract base class, which allows you to add
> partial implementation.
> The other is to provide a mixin for the "default" implementation of
> certain methods.
The problem with both of these solutions is that they are conceptually wrong, since they involve adding hasChildren to the vtbl, meaning it could have any implementation. What Hasan was asking for was the ability for interfaces to declare final methods in interfaces, which would mean they can't be overridden.

To achieve this the "proper" way you either need to support final methods in interfaces or extension methods. Of course, the latter is already partly implemented, and is a much more powerful feature, so I think it should be added to D in any case.
November 19, 2006

Reiner Pope wrote:
> == Quote from Daniel Keep (daniel.keep.lists@gmail.com)'s article
>> There are two ways of doing this, depending on the situation.
>> The first is to have an abstract base class, which allows you to add
>> partial implementation.
>> The other is to provide a mixin for the "default" implementation of
>> certain methods.

That's a possible solution, but it's still adds the inconvenience of having to know which mixins go with the interface whenever you want to implement it.

> The problem with both of these solutions is that they are conceptually wrong,
> since they involve adding hasChildren to the vtbl, meaning it could have any
> implementation. What Hasan was asking for was the ability for interfaces to
> declare final methods in interfaces, which would mean they can't be overridden.
> 
> To achieve this the "proper" way you either need to support final methods in
> interfaces or extension methods. Of course, the latter is already partly
> implemented, and is a much more powerful feature, so I think it should be added to
> D in any case.

Maybe final methods would work better ..

Imagine a class that implements IPerson

class Kid : IPerson
{
    ...
}

Without final methods, "Kid" won't really have access to the magic properties of IPerson.

Kid k = ...
...
if( k.hasChildren() ) //ops, no such property for class Kid
{
    ...
}

November 19, 2006
"Hasan Aljudy" <hasan.aljudy@gmail.com> wrote in message news:ejo4sm$h6$1@digitaldaemon.com...
> Consider the following hypothetical interface:
>
> interface IPerson
> {
>     IPerson getFather();
>     IPerson getMother();
>     IPerson[] getSiblings();
>     IPerson[] getChildren();
> }
>
> For practical purposes, it would be nice to have some methods defined in that interface, such as:
>
> bool hasChildren()
> {
>     return getChildren().length != 0;
> }
>
> but it's not possible to define this method right in the interface. (Suppose say we really have to have the thing as an interface and not as an abstract class).
>
> A possible solution is to add it to the interface without defining it,
>
> interface IPerson
> {
>     IPerson getFather();
>     IPerson getMother();
>     IPerson[] getSiblings();
>     IPerson[] getChildren();
>
>     bool hasChildren();
> }
>
> while hoping that all classes implemeting this interface would define the
> method in the same way, i.e.
> bool hasChildren()
> {
>     return getChildren().length != 0;
> }
> The main problem with this is that it's not practical more complicated
> functions.

What if getChildren() is a costly function, that, say, does an SELECT on a remote database? You would not want it to have that particular implementation since it would not need to collect the children first, just to check whether there are any.

Unfortunately, the only correct way to work with interfaces *is* declaring all the functions virtual. You want to do getChildren().length because you already know the implementation of getChildren, which is not a fair way to look at it.

L.


November 19, 2006
== Quote from Lionello Lunesu (lionello@lunesu.remove.com)'s article
> What if getChildren() is a costly function, that, say, does an SELECT on a
> remote database? You would not want it to have that particular
> implementation since it would not need to collect the children first, just
> to check whether there are any.
> Unfortunately, the only correct way to work with interfaces *is* declaring
> all the functions virtual. You want to do getChildren().length because you
> already know the implementation of getChildren, which is not a fair way to
> look at it.
> L.

But you could apply this sort of argument ("we want to allow people to implement it differently") everywhere so, by that logic, we shouldn't have final methods, since there *might* sometime be a reason to reimplement them (and you could even extend this argument to disallow every function which isn't a class, since none of them involve a virtual function lookup!). There is a limit to how much flexibility can be achieved in an API, and it is sometimes useful to final methods. If the interface expects that getChildren will run in a reasonable time, then it violates the Liskov Substitution principle if an implementing class takes too long on it.

Cheers,

Reiner
November 19, 2006

Reiner Pope wrote:
> == Quote from Lionello Lunesu (lionello@lunesu.remove.com)'s article
>> What if getChildren() is a costly function, that, say, does an SELECT on a
>> remote database? You would not want it to have that particular
>> implementation since it would not need to collect the children first, just
>> to check whether there are any.
>> Unfortunately, the only correct way to work with interfaces *is* declaring
>> all the functions virtual. You want to do getChildren().length because you
>> already know the implementation of getChildren, which is not a fair way to
>> look at it.
>> L.
> 
> But you could apply this sort of argument ("we want to allow people to implement
> it differently") everywhere so, by that logic, we shouldn't have final methods,
> since there *might* sometime be a reason to reimplement them (and you could even
> extend this argument to disallow every function which isn't a class, since none of
> them involve a virtual function lookup!). There is a limit to how much flexibility
> can be achieved in an API, and it is sometimes useful to final methods. If the
> interface expects that getChildren will run in a reasonable time, then it violates
> the Liskov Substitution principle if an implementing class takes too long on it.
> 
> Cheers,
> 
> Reiner

Yeah, and it's not like the interface is sooo abstract that it doesn't define anything at all! It does define something; it defines "what" should be done.
November 19, 2006
On Sun, 19 Nov 2006 13:27:14 +0200, Reiner Pope <reiner.pope@gmail.REMOVE.com> wrote:

> == Quote from Lionello Lunesu (lionello@lunesu.remove.com)'s article
>> What if getChildren() is a costly function, that, say, does an SELECT on a
>> remote database? You would not want it to have that particular
>> implementation since it would not need to collect the children first, just
>> to check whether there are any.
>> Unfortunately, the only correct way to work with interfaces *is* declaring
>> all the functions virtual. You want to do getChildren().length because you
>> already know the implementation of getChildren, which is not a fair way to
>> look at it.
>> L.
>
> But you could apply this sort of argument ("we want to allow people to implement
> it differently") everywhere so, by that logic, we shouldn't have final methods,
> since there *might* sometime be a reason to reimplement them (and you could even
> extend this argument to disallow every function which isn't a class, since none of
> them involve a virtual function lookup!). There is a limit to how much flexibility
> can be achieved in an API, and it is sometimes useful to final methods. If the
> interface expects that getChildren will run in a reasonable time, then it violates
> the Liskov Substitution principle if an implementing class takes too long on it.
>
> Cheers,
>
> Reiner


Well said.

But why should functions defined in an interface to be final? They could be 'copied' to a class creating virtual functions just like mixins do.

This way you could use interfaces to create final functions and default implemenations for virtual functions. No need to split an interface to a mixin + interface definitions.