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