www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Weird (?) problem

reply mike <vertex gmx.at> writes:
Hi!

I've run into a big problem in my project, it's not really a problem wit=
h  =

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 whi=
ch  =

holds a single instance, like that:

' class TypeFoo : TypeBase
' {
'     static TypeBase instance =3D null;
'     static this() { instance =3D 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 th=
e  =

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 decid=
ed  =

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 ve=
ry  =

moment ... so: access violation.

' class TypeType : TypeBase
' {
'     TypeBase instance =3D null;
'	static this() { instance =3D 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=E4rem E-Mail-Modul: http://www.opera.com/=
mail/
Aug 09 2006
next sibling parent reply Ary Manzana <asterite gmail.com> writes:
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
Aug 10 2006
parent reply mike <vertex gmx.at> writes:
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 =3D 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 ther=
e  =

another way?

-Mike


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

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

 Like this:

 ' class TypeType : TypeBase
 ' {
 '     TypeBase instance =3D null;
 '     static this() {
 '         instance =3D 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=E4rem E-Mail-Modul: http://www.opera.com/= mail/
Aug 10 2006
parent Ary Manzana <asterite gmail.com> writes:
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/

Aug 10 2006
prev sibling parent James Dunne <james.jdunne gmail.com> writes:
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
Aug 10 2006