Defining some stuff for each class in turn

Denis Koroskin 2korden at gmail.com
Thu Oct 1 12:13:34 PDT 2009


On Thu, 01 Oct 2009 20:25:03 +0400, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:

> I am becoming increasingly aware that we need to provide some means to  
> define certain members (data and functions) for each class as if they  
> were pasted there.
>
> Right now that right is reserved to the compiler, which generates e.g.  
> one static classinfo object for each class. But users would want to also  
> define members for each class automatically. This is often the case with  
> contravariant-argument functions (that we discussed recently) and other  
> important cases such as factories and cloning.
>
> For starters, assume I want to define one static int for each class in a  
> hierarchy.
>
> class Counted {
>      static uint counter;
>      ...
> }
>
> Then subclasses of Counted would all share counter, something I don't  
> want. I want each subclass to have its own counter, so I need to ask  
> derived classes to *also* define counter:
>
> class A : Counted {
>      static uint counter;
>      ...
> }
>
> With the suggested feature, there would be the ability to define counter  
>   for each class in turn.
>
> class Counted {
>      mixin(Derived)
>      {
>          // Insert here stuff that must be "pasted" for each subclass
>          // of Counted (including Counted itself).
>          // Use "Derived" as the name of the current subtype of Counter
>          static uint counter;
>          static if (is(Counted == Derived))
>              ref uint getCounter() { return counter; }
>          else
>              override ref uint getCounter() { return counter; }
>      }
>      ...
> }
>
> The code above does something quite neat - it defines an overridable  
> function Counted.getCounter in the base class, and then overrides it in  
> *every* class inheriting that base class, to return that class' own  
> counter.
>
> The same should go in interface definitions - the feature should allow  
> you to
>
> There are quite a few immediate applications of this: opEquals, opCmp,  
> clone, various factories and object pools, and most importantly  
> reflection. To enable custom reflection with today's D, we'd have to  
> require each class to insert some code inside the class body. With the  
> mechanism described above, we allow the base class or an interface (e.g.  
> Reflectable) to inject the code into the derived class' body.
>
> What do you think?
>
>
> Andrei

This is cool. I'd also add Serialization task to the application list  
(currently I manually insert "mixin Serializable!();" into every class.

There is one thing that I dislike about it, though. I believe mixin(Foo)  
{} syntax is a bit far-fetched, it is not obvious that Foo represents  
derived type inside a mixin scope.

I'd like to remind you that we could just use typeof(this) instead of  
Foo/Derived/etc:

static if (is (typeof(this) == Counted) {
     ref uint getCounter() { return counter; }
} else {
     override ref uint getCounter() { return counter; }
}

If you remember, we had a similar discussion about a half year ago. It was  
about ICloneable interface that forces all derived class to implement  
proper clone() method. We could define it as:

// forces implementor class and all the derivatives to implement proper  
clone() method
interface ICloneable
{
     scope mixin {	// alternative syntax
         typeof(this) clone();
     }
}

and also be able to declare a method non-recursively (so that derived  
class don't have to implement that method):

interface ICloneableNonRecursive
{
     typeof(this) clone();
}

Other possible solution could be to use a special "derived" keyword. We  
already have a class-level compile-time constant - "super". We could also  
introduce its counter-part ("derived"), which will expand into a concrete  
derived class type. This will simplify the syntax a bit and will allow to  
get rid of mixin and an addition level of indentation:

interface ICloneable
{
     derived clone();
}

interface IComparable
{
     int opCmp(derived other);
}

As a downside, I don't know how to define a field in every class this way  
("int derived.counter;" maybe?).



More information about the Digitalmars-d mailing list