Defining some stuff for each class in turn

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Thu Oct 1 10:53:46 PDT 2009


Jarrett Billingsley wrote:
> On Thu, Oct 1, 2009 at 12:25 PM, Andrei Alexandrescu
> <SeeWebsiteForEmail at erdani.org> wrote:
[code injection]
>> What do you think?
> 
> I think it sounds interesting enough, but I can't help but wonder if
> this is a feature that you've really thought through (especially wrt.
> how it interacts with mechanisms such as template mixins and normal
> symbol inheritance), or if you just want it to support some pattern
> you want to use in Phobos 2.

I've known for a long time this was in store if we want to define decent 
reflection. It's also been a perennial source of trouble with a lot of 
code that needs to inject members.

Let me give another example. When we discussed opCmp around here, people 
said that's the old way of doing things and that the right way is to use 
an interface Comparator!T, akin to Java's Comparator<T>:

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html

That only solves exactly one level of inheritance. It's a more elaborate 
solution that doesn't quite help that much. Consider:

interface Comparator(T)
{
     int opCmp(T rhs); // yum, exact type
}

class Widget : Comparator!Widget
{
     override opCmp(Widget rhs) { ... } // yum, exact type
}

class Gadget : Widget
{
     override opCmp(Gadget rhs) { ... } // ERROR!!!!!!!!
}

Of course that didn't work. Gadget.opCmp doesn't override anything. 
Gadget needs to remember to inherit Comparator!Gadget:

class Gadget : Widget, Comparator!Gadget
{
     override opCmp(Gadget rhs) { ... } // oh ok
}

So any class X in Widget's hierarchy that forgets to inherit 
Comparator!X undergoes the risk of having the wrong opCmp called for it.

With injection, Comparator can be made to work for any interface:

interface Comparator(T)
{
     int opCmp(Comparator!T rhs);
     mixin(Impl) // for each implementation Impl
     {
         int opCmp(Impl rhs);
         override int opCmp(Comparator!T rhs)
         {
             return opCmp(cast(Impl) rhs);
         }
     }
}

class Widget : Comparator!Widget { ... }

Now every derived class of Widget, including Widget itself, commits to 
define a opCmp with the proper signature (failure to do so results in a 
linker error), and also defines the interface function in terms of it.


Andrei



More information about the Digitalmars-d mailing list