www.digitalmars.com         C & C++   DMDScript  

D - [Idea] Extendable properties

reply J Anderson <REMOVEanderson badmama.com.au> writes:
Parhaps something for 2.0.

class A {}

class B : A { }

class D { A a; }

class E : D
{
   a : B;  //A is extended to b
}

It would be useful for creating things like static virtual methods and 
for changing properties in classes the user doesn't have control over.  
This would of course probably need to be extended for getters and 
setters as well.

For course at the moment this can be simulated (and has been simulated) 
with a whole load of casting but that's not nice.

--

-Anderson: http://badmama.com.au/~anderson/
Mar 18 2004
parent reply "Matthew" <matthew stlsoft.org> writes:
Haven't the faculties to really think about it at the mo, but it seems
attractive.

Maybe Ilya can point out some important flaws in it, or even that aren't. ;)


"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3cs6c$1bls$1 digitaldaemon.com...
 Parhaps something for 2.0.

 class A {}

 class B : A { }

 class D { A a; }

 class E : D
 {
    a : B;  //A is extended to b
 }

 It would be useful for creating things like static virtual methods and
 for changing properties in classes the user doesn't have control over.
 This would of course probably need to be extended for getters and
 setters as well.

 For course at the moment this can be simulated (and has been simulated)
 with a whole load of casting but that's not nice.

 --

 -Anderson: http://badmama.com.au/~anderson/
Mar 18 2004
next sibling parent reply "Jeroen van Bemmel" <someone somewhere.com> writes:
The idea is not bad, although it somehow feels like a can of wurms. I'm not
quite sure why

One potential issue is order of construction of objects. Class E in your
example would need an allocating constructor that reserves enough memory for
E, plus sizeof(B) memory for a. Then, normally, the base class D
initializing constructor would be called, which initializes the 'A' part of
a. Then, the extended 'B' part of a is initialized as part of E's
constructor.

The problem is, that for the latter partial construction of a, 'B' needs to
have a separate constructor that initializes B member variables but does not
call the baseclass constructor in A. This is needed for all derived classes
that may potentially be used as extended properties, so each derived class
now gets 3 different constructors: (1) allocating constructor, (2)
initializing constructor, and (3) partial constructor. These could call each
other, so (1) calls (2) which calls base.(2) followed by (3)

Walter: in general you cannot call virtual methods from a constructor,
right? Since otherwise you would be able to call a method on an object that
is not properly initialized yet, eg when the D constructor would call
D.virtualMethod() which is overridden in E

 "J Anderson" <REMOVEanderson badmama.com.au> wrote in message
 news:c3cs6c$1bls$1 digitaldaemon.com...
 Parhaps something for 2.0.

 class A {}

 class B : A { }

 class D { A a; }

 class E : D
 {
    a : B;  //A is extended to b
 }

 It would be useful for creating things like static virtual methods and
 for changing properties in classes the user doesn't have control over.
 This would of course probably need to be extended for getters and
 setters as well.

 For course at the moment this can be simulated (and has been simulated)
 with a whole load of casting but that's not nice.

 --

 -Anderson: http://badmama.com.au/~anderson/
Mar 18 2004
next sibling parent reply Stephan Wienczny <wienczny web.de> writes:
Jeroen van Bemmel wrote:

 Walter: in general you cannot call virtual methods from a constructor,
 right? Since otherwise you would be able to call a method on an object that
 is not properly initialized yet, eg when the D constructor would call
 D.virtualMethod() which is overridden in E
 
I think it is possible. When you create an object d of a given class D, D's vtbl is copied into d.classinfo.vtbl. Then the constructor of the class you created is called. At this stage all member variables are already initialized using the types base value or its basic value (e.g. int a = 5). Then you can use 'super()' to call the base class constructors. If you call a virtual method before super() you shouldn't expect any initialisation in super class constructors ;-) Did I get your point? Stephan
Mar 18 2004
parent "Jeroen van Bemmel" <someone somewhere.com> writes:
"Stephan Wienczny" <wienczny web.de> wrote in message
news:c3dg4l$2evb$1 digitaldaemon.com...
 Jeroen van Bemmel wrote:

 Walter: in general you cannot call virtual methods from a constructor,
 right? Since otherwise you would be able to call a method on an object
that
 is not properly initialized yet, eg when the D constructor would call
 D.virtualMethod() which is overridden in E
I think it is possible. When you create an object d of a given class D, D's vtbl is copied into d.classinfo.vtbl.
I would expect that d gets a pointer to the vtbl in D, but ok
 Then the constructor of the class you created is
 called. At this stage all member variables are already initialized using
   the types base value or its basic value (e.g. int a = 5).
 Then you can use 'super()' to call the base class constructors.
 If you call a virtual method before super() you shouldn't expect any
 initialisation in super class constructors ;-)

 Did I get your point?
Yes and no. This looks like a workaround, but a) is it enforced? it heavily depends on developer knowledge, and it's easy to make mistakes and get strange errors b) it's counter intuitive (eg C++ does it differently) In general, I would expect base class initialization to finish before subclass initialization.
Mar 18 2004
prev sibling next sibling parent J Anderson <REMOVEanderson badmama.com.au> writes:
Jeroen van Bemmel wrote:

The idea is not bad, although it somehow feels like a can of wurms. I'm not
quite sure why

One potential issue is order of construction of objects. Class E in your
example would need an allocating constructor that reserves enough memory for
E, plus sizeof(B) memory for a. Then, normally, the base class D
initializing constructor would be called, which initializes the 'A' part of
a. Then, the extended 'B' part of a is initialized as part of E's
constructor.

The problem is, that for the latter partial construction of a, 'B' needs to
have a separate constructor that initializes B member variables but does not
call the baseclass constructor in A. This is needed for all derived classes
that may potentially be used as extended properties, so each derived class
now gets 3 different constructors: (1) allocating constructor, (2)
initializing constructor, and (3) partial constructor. These could call each
other, so (1) calls (2) which calls base.(2) followed by (3)

Walter: in general you cannot call virtual methods from a constructor,
right? Since otherwise you would be able to call a method on an object that
is not properly initialized yet, eg when the D constructor would call
D.virtualMethod() which is overridden in E
  
Good point, all of which also show the difficultly in doing something simular manually also. -- -Anderson: http://badmama.com.au/~anderson/
Mar 18 2004
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
How about this code which is ALMOST legal:

class A {}
class B : A {)

class D {
   this(A a)
     in { assert(a !== null); assert(a); }
   body {
     this.a = a;
   }
   this() {
     this(new A);
   }
   A a;
}
class E : D {
   this() {
     super(new B);
   }
   B a()
     out(retval) {
       assert(ret !== null);
       assert(retval);
     }
   body {
     return cast(B)super.a;
   }
}



The problem, of course, is that the return value B from E.a() does not 
match the type of D.a.  However, it seems to me that there is no reason 
why this should not be legal.  Anybody who is interfacing to an E object 
through a reference of type D will be expecting that the D.a be of type 
A; certainly if we return an object of type B, we fulfill this 
requirement.  People accessing the object through a reference of type E 
will know about the newer, more specific function, and will be able to 
make use of it.



Jeroen van Bemmel wrote:
 The idea is not bad, although it somehow feels like a can of wurms. I'm not
 quite sure why
 
 One potential issue is order of construction of objects. Class E in your
 example would need an allocating constructor that reserves enough memory for
 E, plus sizeof(B) memory for a. Then, normally, the base class D
 initializing constructor would be called, which initializes the 'A' part of
 a. Then, the extended 'B' part of a is initialized as part of E's
 constructor.
 
 The problem is, that for the latter partial construction of a, 'B' needs to
 have a separate constructor that initializes B member variables but does not
 call the baseclass constructor in A. This is needed for all derived classes
 that may potentially be used as extended properties, so each derived class
 now gets 3 different constructors: (1) allocating constructor, (2)
 initializing constructor, and (3) partial constructor. These could call each
 other, so (1) calls (2) which calls base.(2) followed by (3)
 
 Walter: in general you cannot call virtual methods from a constructor,
 right? Since otherwise you would be able to call a method on an object that
 is not properly initialized yet, eg when the D constructor would call
 D.virtualMethod() which is overridden in E
 
 
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3cs6c$1bls$1 digitaldaemon.com...

Parhaps something for 2.0.

class A {}

class B : A { }

class D { A a; }

class E : D
{
   a : B;  //A is extended to b
}

It would be useful for creating things like static virtual methods and
for changing properties in classes the user doesn't have control over.
This would of course probably need to be extended for getters and
setters as well.

For course at the moment this can be simulated (and has been simulated)
with a whole load of casting but that's not nice.

--

-Anderson: http://badmama.com.au/~anderson/
Mar 18 2004
parent J Anderson <REMOVEanderson badmama.com.au> writes:
Russ Lewis wrote:

 How about this code which is ALMOST legal:

 class A {}
 class B : A {)

 class D {
   this(A a)
     in { assert(a !== null); assert(a); }
   body {
     this.a = a;
   }
   this() {
     this(new A);
   }
   A a;
 }
 class E : D {
   this() {
     super(new B);
   }
   B a()
     out(retval) {
       assert(ret !== null);
       assert(retval);
     }
   body {
     return cast(B)super.a;
   }
 }



 The problem, of course, is that the return value B from E.a() does not 
 match the type of D.a.  However, it seems to me that there is no 
 reason why this should not be legal.  Anybody who is interfacing to an 
 E object through a reference of type D will be expecting that the D.a 
 be of type A; certainly if we return an object of type B, we fulfill 
 this requirement.  People accessing the object through a reference of 
 type E will know about the newer, more specific function, and will be 
 able to make use of it.
This is the kinda workaround I mentioned before that I don't like. I still think a post-constructor would make life so much easier. 2 lines as opposed to 20 (although I'd say most of those asserts aren't absolutely nessary). This is pretty close to what I suggested anyway (ie support for getters and setters as well). The other problem with this is that the parent class has to be prepared. Consider you don't have access to the parent class. -- -Anderson: http://badmama.com.au/~anderson/
Mar 18 2004
prev sibling parent J Anderson <REMOVEanderson badmama.com.au> writes:
Matthew wrote:

Haven't the faculties to really think about it at the mo, but it seems
attractive.

Maybe Ilya can point out some important flaws in it, or even that aren't. ;)
  
If the object is initialized (and I'm not suggesting that this should be allowed), what is the order? class A {} class B : A { } class D { A a = new A; } class E : D { a : B = new B; //??? - What to do here. } You'd end up with two constructions or B being constructed twice. Construction has to occur somewhere. I guess a something like a vtable could be used and variables for overload would be indicated. That way when construction occurs it would call the vtable function instead. class A {} class B : A { } class D { virtual A a = new A; //The constructor is looked up } class E : D { a : B = new B; //new B is called, not new A } It then would require another entry in the vtable but only one for construction of all virtual objects. The problem I see is that like in C++, programmers will not put virtual. Therefore the vtable thing may need to be mandatory :( Parhaps it could be optimised out some way? Of course if its always has to be null then the problem is moved else where (possibly the constructor -> which could be confusing to some users). Another way would be to have a special function for construction that is only called at the top level (this can be simulated). That would be useful for other things also. It would also easily be simulated by virtual method if a post construction function was available. -- -Anderson: http://badmama.com.au/~anderson/
Mar 18 2004