Thread overview
Weird (?) problem
Aug 09, 2006
mike
Aug 10, 2006
Ary Manzana
Aug 10, 2006
mike
Aug 10, 2006
Ary Manzana
Aug 10, 2006
James Dunne
August 09, 2006
Hi!

I've run into a big problem in my project, it's not really a problem with D, more a problem with ... you'll see.

Anyway: I've got a couple of classes in my project which represent type information (like MIDI notes, audio output, sample data, etc. - it'll be an audio app written in D). Basically it's a reflection system with some extras that are specific to this project.

Now, the idea is that every of these type classes has a static field which holds a single instance, like that:

' class TypeFoo : TypeBase
' {
'     static TypeBase instance = null;
'     static this() { instance = new TypeFoo(); }
' }

I've got a static opCall to return that instance:

' static TypeBase opCall() { return instance; }

Now everywhere I need to call an overloaded constructor or tell some object which type of other objects it can process, I just can call

' TypeFoo()

and get my type class.

Next is, I've got a namespace- or registry-like tree system, where all objects are stored into. That's where I store the information of "I can process objects of type X" too. It's somehow like:

' getObject("foo").setType(TypeFoo());
' getObject("foo").addCanProcess(TypeBar());

Now the thing is that the type classes need to identify themselves to the rest of the system as type classes. Therefore I've got a TypeType class. Which also resides in that tree.

Up until now I set up this information on my type classes via a "construct"-function, which was called at a point where the class instances already exist. But I'm a bit fed up of having to maintain two pieces of code (class definition and the construct-function), so I decided to make the type classes able to set up themselves. And here the trouble starts.

So: In the TypeType static c'tor, I make a new instance of that class. Then the normal c'tor is called, trying to setup itself in the tree system, telling everybody that it is indead a type. So ... it needs the very instance of the TypeType class that is being constructed at that very moment ... so: access violation.

' class TypeType : TypeBase
' {
'     TypeBase instance = null;
'	static this() { instance = new TypeType(); }
'     static TypeBase opCall() { return instance; }
'     this()
'     {
'          addObject("typetype");
'          getObject("typetype").setType(TypeType()); // crashes: access violation
'     }
' }

It's a bit of a chicken and egg problem. I can't new an instance of that class unless there's already one instance there. Is it possible to solve that somehow? Something like an "after_this()" or the like? I guess I've outsmarted myself there and I have no idea what to do about it besides reverting to the old system with that stupid, ugly construct function (shudder).

Any ideas would be really appreciated.

-Mike

-- 
Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/
August 10, 2006
mike wrote:
> Hi!
> 
> I've run into a big problem in my project, it's not really a problem with D, more a problem with ... you'll see.
> 
> Anyway: I've got a couple of classes in my project which represent type information (like MIDI notes, audio output, sample data, etc. - it'll be an audio app written in D). Basically it's a reflection system with some extras that are specific to this project.
> 
> Now, the idea is that every of these type classes has a static field which holds a single instance, like that:
> 
> ' class TypeFoo : TypeBase
> ' {
> '     static TypeBase instance = null;
> '     static this() { instance = new TypeFoo(); }
> ' }
> 
> I've got a static opCall to return that instance:
> 
> ' static TypeBase opCall() { return instance; }
> 
> Now everywhere I need to call an overloaded constructor or tell some object which type of other objects it can process, I just can call
> 
> ' TypeFoo()
> 
> and get my type class.
> 
> Next is, I've got a namespace- or registry-like tree system, where all objects are stored into. That's where I store the information of "I can process objects of type X" too. It's somehow like:
> 
> ' getObject("foo").setType(TypeFoo());
> ' getObject("foo").addCanProcess(TypeBar());
> 
> Now the thing is that the type classes need to identify themselves to the rest of the system as type classes. Therefore I've got a TypeType class. Which also resides in that tree.
> 
> Up until now I set up this information on my type classes via a "construct"-function, which was called at a point where the class instances already exist. But I'm a bit fed up of having to maintain two pieces of code (class definition and the construct-function), so I decided to make the type classes able to set up themselves. And here the trouble starts.
> 
> So: In the TypeType static c'tor, I make a new instance of that class. Then the normal c'tor is called, trying to setup itself in the tree system, telling everybody that it is indead a type. So ... it needs the very instance of the TypeType class that is being constructed at that very moment ... so: access violation.
> 
> ' class TypeType : TypeBase
> ' {
> '     TypeBase instance = null;
> '    static this() { instance = new TypeType(); }
> '     static TypeBase opCall() { return instance; }
> '     this()
> '     {
> '          addObject("typetype");
> '          getObject("typetype").setType(TypeType()); // crashes: access violation
> '     }
> ' }
> 
> It's a bit of a chicken and egg problem. I can't new an instance of that class unless there's already one instance there. Is it possible to solve that somehow? Something like an "after_this()" or the like? I guess I've outsmarted myself there and I have no idea what to do about it besides reverting to the old system with that stupid, ugly construct function (shudder).
> 
> Any ideas would be really appreciated.
> 
> -Mike
> 
> --Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/

Have you tried placing code after "instance = new TypeType()"?

Like this:

' class TypeType : TypeBase
' {
'     TypeBase instance = null;
'     static this() {
'         instance = new TypeType();
'         // I don't know whether addObject is a function
'         // or a member of TypeType, but you get the point
'         instance.addObject("typetype");
'         instance.getObject("typetype").setType(instance);
'     }
'     static TypeBase opCall() { return instance; }
'     this()
'     {
'     }
' }

Hope that helps (and works).
Ary
August 10, 2006
mike wrote:
> [snip]
> 
> So: In the TypeType static c'tor, I make a new instance of that class.  Then the normal c'tor is called, trying to setup itself in the tree  system, telling everybody that it is indead a type. So ... it needs the  very instance of the TypeType class that is being constructed at that very  moment ... so: access violation.
> 
> ' class TypeType : TypeBase
> ' {
> '     TypeBase instance = null;
> '    static this() { instance = new TypeType(); }
> '     static TypeBase opCall() { return instance; }
> '     this()
> '     {
> '          addObject("typetype");
> '          getObject("typetype").setType(TypeType()); // crashes: access  violation
> '     }
> ' }
> 
> It's a bit of a chicken and egg problem. I can't new an instance of that  class unless there's already one instance there. Is it possible to solve  that somehow? Something like an "after_this()" or the like? I guess I've  outsmarted myself there and I have no idea what to do about it besides  reverting to the old system with that stupid, ugly construct function  (shudder).
> 
> Any ideas would be really appreciated.
> 
> -Mike
> 

Create two constructors for your TypeType classes.

One private c'tor with a dummy parameter to differentiate it from the normal public c'tor.

Call that private c'tor in your static c'tor; the private c'tor should obviously _not_ call into your registration system.

The normal public c'tor should call the registration system, just like in your code above.

class TypeType : TypeBase {
    TypeBase instance = null;

    static this() {
        instance = new TypeType(true);
        addObject("typetype");
        addObject("typetype").setType(instance);
    }
    static TypeBase opCall() { return instance; }

    public this() {
        addObject("typetype");
        getObject("typetype").setType(TypeType());
    }

    private this(bool dummy) {
        // Just a dummy to suppress infinite recursion in constructor
        // calls...
    }
}

I'm curious as to the purpose of the multiple registration of the "typetype" named instance in your registry system.  I hope you get the basic idea of what I'm proposing so you can fix these issues yourself. :)

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/MU/S d-pu s:+ a-->? C++++$ UL+++ P--- L+++ !E W-- N++ o? K? w--- O M--@ V? PS PE Y+ PGP- t+ 5 X+ !R tv-->!tv b- DI++(+) D++ G e++>e h>--->++ r+++ y+++
------END GEEK CODE BLOCK------

James Dunne
August 10, 2006
Thanks, it works! :-)

I still need one little workaround, but that's ok.

Funny thing is: Thinking about it a little bit more I got that idea:

' class TypeFoo : TypeBase
' {
'     public:
'         static this() { instance = new Bar(); }
'
'     private:
'         void setup() { /* add object, setup */ }
'         TypeBase instance;
'
'     unittest
'     {
'         instance.setup();
'     }
' }

since the unittest will be executed after ALL static this()'s are done, and it's the only piece of code that is tied to a class and called automatically (besides the constructors) - but I don't want to be that evil :-)

Another question:

Is there a way to prevent a derived class from calling super()? I solved this currently with an empty this(int) and calling super(0), but is there another way?

-Mike


Am 10.08.2006, 14:14 Uhr, schrieb Ary Manzana <asterite@gmail.com>:

> Have you tried placing code after "instance = new TypeType()"?
>
> Like this:
>
> ' class TypeType : TypeBase
> ' {
> '     TypeBase instance = null;
> '     static this() {
> '         instance = new TypeType();
> '         // I don't know whether addObject is a function
> '         // or a member of TypeType, but you get the point
> '         instance.addObject("typetype");
> '         instance.getObject("typetype").setType(instance);
> '     }
> '     static TypeBase opCall() { return instance; }
> '     this()
> '     {
> '     }
> ' }
>
> Hope that helps (and works).
> Ary



-- 
Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/
August 10, 2006
mike wrote:
> Thanks, it works! :-)
> 
> I still need one little workaround, but that's ok.
> 
> Funny thing is: Thinking about it a little bit more I got that idea:
> 
> ' class TypeFoo : TypeBase
> ' {
> '     public:
> '         static this() { instance = new Bar(); }
> '
> '     private:
> '         void setup() { /* add object, setup */ }
> '         TypeBase instance;
> '
> '     unittest
> '     {
> '         instance.setup();
> '     }
> ' }
> 
> since the unittest will be executed after ALL static this()'s are done, and it's the only piece of code that is tied to a class and called automatically (besides the constructors) - but I don't want to be that evil :-)

Watch out!! Unit tests are only for debug purposes, once you compile your code with the "release" flag, no unit test will ever be invoked.

> 
> Another question:
> 
> Is there a way to prevent a derived class from calling super()? I solved this currently with an empty this(int) and calling super(0), but is there another way?

I believe not, and it's because of the OOP philosophy... But you can always make a protected constructor for your derived classes, although this increases code dependency between classes, and I don't recommend it.

> 
> -Mike
> 
> 
> Am 10.08.2006, 14:14 Uhr, schrieb Ary Manzana <asterite@gmail.com>:
> 
>> Have you tried placing code after "instance = new TypeType()"?
>>
>> Like this:
>>
>> ' class TypeType : TypeBase
>> ' {
>> '     TypeBase instance = null;
>> '     static this() {
>> '         instance = new TypeType();
>> '         // I don't know whether addObject is a function
>> '         // or a member of TypeType, but you get the point
>> '         instance.addObject("typetype");
>> '         instance.getObject("typetype").setType(instance);
>> '     }
>> '     static TypeBase opCall() { return instance; }
>> '     this()
>> '     {
>> '     }
>> ' }
>>
>> Hope that helps (and works).
>> Ary
> 
> 
> 
> --Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/