www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Inheriting constructors

reply Sean Kelly <sean f4.ca> writes:
Until recently I have been against the idea of inheriting constructors, 
but I've changed my mind.  Inheriting constructors would allow for an 
entire class of generic programming that simply isn't possible right 
now.  The basic rule would be simple and much like the function lookup 
rules already in place: if a class contains no constructors then it 
inherits the constructors of the nearest parent where some are defined. 
  Defining even a single constructor, however, effectively occludes 
superclass constructors and disables this behavior (the workaround being 
an alias, like with function lookup, except that it's currently 
impossible to explicitly reference a class constructor).

The original motivation for this idea was a need for some way to attach 
"on destruct" behavior to an arbitrary class:

     class PrintOnDestruct( T ) :
         public T
     {
         ~this()
         {
             printf( "dtor: %.*s\n", super.classinfo.name );
         }
     }

     class MyClass
     {
         this( int a, int b, int c ) {}
     }

     auto c = new PrintOnDestruct!(MyClass)( a, b, c );

As far as I know, the only way this is currently possible is to 
explicitly write all relevant constructors in PrintOnDestruct.

I believe this feature may also obviate the need for language support of 
placement new:

     class Placed( T ) :
         public T
     {
         new( void* p, size_t sz )
         {
             return p;
         }
     }

     class MyClass
     {
         this( int x ) { val = x; }
         private int val;
     }

     auto p = new(loc) Placed!(MyClass)( 0 );

I can think of other examples as well, but these are the two most 
relevant to what prompted this post in the first place.


On a semi-related note, it would also be nice if there were some way to 
obtain the ParameterTypeTuple for class constructors in general.  Since 
there is currently no way to explicitly reference constructors, this 
sort of thing isn't possible:

     class MyClass
     {
         this( int x ) {}
     }

     alias ParametersOf!(MyClass.this) CtorParams;

The most obvious use case here would be object factories.  Let's say I 
want to be able to generate objects with the same set of parameters each 
time:

     struct TupleInst( Types... )
     {
         Tuple!(Types) data;
     }

     class Factory!( T )
     {
         this( ParametersOf!(T.this) args )
         {
             foreach( i, arg; args )
             {
                 store.data[i] = arg;
             }
         }

         T generate()
         {
             return new T( store.data );
         }

         private TupleInst!(ParametersOf!(T.this)) store;
     }

     class MyClass
     {
         this( int x ) {}
     }

     auto fact = new Factory!(MyClass)( 0 );
     auto objA = fact.generate();
     auto objB = fact.generate();

So something roughly like parameter binding but for constructors.  This 
latter idea likely has less utility than constructor inheritance, but 
I've run into one or two places where it would have been very useful, 
and I had to hack a solution.  Both were essentially similar to the 
example above, but with a different goal in mind.


Sean
Jun 01 2007
next sibling parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Sean Kelly wrote:

A bit off-topic (sorry), but you're using protection modifiers here:

      class PrintOnDestruct( T ) :
          public T
and here
      class Placed( T ) :
          public T
Are you also suggesting that D should support those like C++ does?
Jun 02 2007
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Jari-Matti Mäkelä wrote:
 Sean Kelly wrote:
 
 A bit off-topic (sorry), but you're using protection modifiers here:
 
      class PrintOnDestruct( T ) :
          public T
and here
      class Placed( T ) :
          public T
Are you also suggesting that D should support those like C++ does?
Actually, they are already allowed. Check the grammar at the online docs: http://digitalmars.com/d/class.html You will see that it allows both 'SuperClass' and 'InterfaceClass' to be preceded by a 'Protection'. That said, I don't know that I've ever seen anyone actually bother using this in D, nor am I sure of its utility. -- Chris Nicholson-Sauls
Jun 02 2007
next sibling parent reply Frank Benoit <keinfarbton googlemail.com> writes:
I think, the protection here is a language mistake.

If a class inherits protected or private from a superclass, the class
loses its object.Object compatibility.

And what sense can it make, in a language without multiple inheritance?
Jun 02 2007
parent reply Sean Kelly <sean f4.ca> writes:
Frank Benoit wrote:
 I think, the protection here is a language mistake.
 
 If a class inherits protected or private from a superclass, the class
 loses its object.Object compatibility.
Is this the case in Java as well? Sean
Jul 10 2007
parent Mike Parker <aldacron gmail.com> writes:
Sean Kelly wrote:
 Frank Benoit wrote:
 I think, the protection here is a language mistake.

 If a class inherits protected or private from a superclass, the class
 loses its object.Object compatibility.
Is this the case in Java as well? Sean
There is no private/protected inheritance in Java.
Jul 10 2007
prev sibling parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Chris Nicholson-Sauls wrote:

 Jari-Matti Mäkelä wrote:
 Sean Kelly wrote:
 
 A bit off-topic (sorry), but you're using protection modifiers here:
 
      class PrintOnDestruct( T ) :
          public T
and here
      class Placed( T ) :
          public T
Are you also suggesting that D should support those like C++ does?
Actually, they are already allowed. Check the grammar at the online docs: http://digitalmars.com/d/class.html You will see that it allows both 'SuperClass' and 'InterfaceClass' to be preceded by a 'Protection'. That said, I don't know that I've ever seen anyone actually bother using this in D, nor am I sure of its utility.
They have been there and I have asked this previously, yes. However, the compiler does not use them (yet?). I think they cause problems: // module 1 interface foo { void method(); } class base : foo { void method() {} } class moo: private base {} // module 2 void main() { foo m = new moo(); m.method(); // bang, runtime error } others ways to do this. And I think the inheritance model in D is closer to Java than C++ so that's why it feels weird to me.
 
 -- Chris Nicholson-Sauls
Jun 02 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Jari-Matti Mäkelä wrote:
 Chris Nicholson-Sauls wrote:
 
 Jari-Matti Mäkelä wrote:
 Sean Kelly wrote:

 A bit off-topic (sorry), but you're using protection modifiers here:

      class PrintOnDestruct( T ) :
          public T
and here
      class Placed( T ) :
          public T
Are you also suggesting that D should support those like C++ does?
Actually, they are already allowed. Check the grammar at the online docs: http://digitalmars.com/d/class.html You will see that it allows both 'SuperClass' and 'InterfaceClass' to be preceded by a 'Protection'. That said, I don't know that I've ever seen anyone actually bother using this in D, nor am I sure of its utility.
They have been there and I have asked this previously, yes. However, the compiler does not use them (yet?). I think they cause problems: // module 1 interface foo { void method(); } class base : foo { void method() {} } class moo: private base {} // module 2 void main() { foo m = new moo(); m.method(); // bang, runtime error } others ways to do this. And I think the inheritance model in D is closer to Java than C++ so that's why it feels weird to me.
Well, that's sort of the whole point of private base classes. You're using the base as an implementation detail. To the outside world it should look more or less like you DON'T derive from base. But such a thing definitely doesn't make as much sense when you only have single inheritance. A private mixin would probably make more sense in D. Of course if you're trying to re-use something that wasn't a template mixin to begin with, then you're out of luck. Which is why the C++ is handy if you have multiple inheritance. It basically lets you mixin a pre-exising class privately. --bb
Jun 02 2007
prev sibling parent Sean Kelly <sean f4.ca> writes:
Jari-Matti Mäkelä wrote:
 Sean Kelly wrote:
 
 A bit off-topic (sorry), but you're using protection modifiers here:
 
      class PrintOnDestruct( T ) :
          public T
and here
      class Placed( T ) :
          public T
Are you also suggesting that D should support those like C++ does?
I thought it already did? But it's not a feature I use often, so who knows. Sean
Jun 02 2007
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Now that the const discussion has died down a bit, I don't suppose 
anyone else is interested in this feature?  (As an aside, I'm coming to 
feel that we may need real placement new support after all, along with 
something like my .isizeof proposal--it's not always feasible to change 
the type using a wrapper as described below).


Sean

Sean Kelly wrote:
 Until recently I have been against the idea of inheriting constructors, 
 but I've changed my mind.  Inheriting constructors would allow for an 
 entire class of generic programming that simply isn't possible right 
 now.  The basic rule would be simple and much like the function lookup 
 rules already in place: if a class contains no constructors then it 
 inherits the constructors of the nearest parent where some are defined. 
  Defining even a single constructor, however, effectively occludes 
 superclass constructors and disables this behavior (the workaround being 
 an alias, like with function lookup, except that it's currently 
 impossible to explicitly reference a class constructor).
 
 The original motivation for this idea was a need for some way to attach 
 "on destruct" behavior to an arbitrary class:
 
     class PrintOnDestruct( T ) :
         public T
     {
         ~this()
         {
             printf( "dtor: %.*s\n", super.classinfo.name );
         }
     }
 
     class MyClass
     {
         this( int a, int b, int c ) {}
     }
 
     auto c = new PrintOnDestruct!(MyClass)( a, b, c );
 
 As far as I know, the only way this is currently possible is to 
 explicitly write all relevant constructors in PrintOnDestruct.
 
 I believe this feature may also obviate the need for language support of 
 placement new:
 
     class Placed( T ) :
         public T
     {
         new( void* p, size_t sz )
         {
             return p;
         }
     }
 
     class MyClass
     {
         this( int x ) { val = x; }
         private int val;
     }
 
     auto p = new(loc) Placed!(MyClass)( 0 );
 
 I can think of other examples as well, but these are the two most 
 relevant to what prompted this post in the first place.
 
 
 On a semi-related note, it would also be nice if there were some way to 
 obtain the ParameterTypeTuple for class constructors in general.  Since 
 there is currently no way to explicitly reference constructors, this 
 sort of thing isn't possible:
 
     class MyClass
     {
         this( int x ) {}
     }
 
     alias ParametersOf!(MyClass.this) CtorParams;
 
 The most obvious use case here would be object factories.  Let's say I 
 want to be able to generate objects with the same set of parameters each 
 time:
 
     struct TupleInst( Types... )
     {
         Tuple!(Types) data;
     }
 
     class Factory!( T )
     {
         this( ParametersOf!(T.this) args )
         {
             foreach( i, arg; args )
             {
                 store.data[i] = arg;
             }
         }
 
         T generate()
         {
             return new T( store.data );
         }
 
         private TupleInst!(ParametersOf!(T.this)) store;
     }
 
     class MyClass
     {
         this( int x ) {}
     }
 
     auto fact = new Factory!(MyClass)( 0 );
     auto objA = fact.generate();
     auto objB = fact.generate();
 
 So something roughly like parameter binding but for constructors.  This 
 latter idea likely has less utility than constructor inheritance, but 
 I've run into one or two places where it would have been very useful, 
 and I had to hack a solution.  Both were essentially similar to the 
 example above, but with a different goal in mind.
 
 
 Sean
Jul 10 2007
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Sean Kelly wrote:
 Now that the const discussion has died down a bit, I don't suppose 
 anyone else is interested in this feature?  (As an aside, I'm coming to 
 feel that we may need real placement new support after all, along with 
 something like my .isizeof proposal--it's not always feasible to change 
 the type using a wrapper as described below).
 
 
 Sean
 
 Sean Kelly wrote:
 Until recently I have been against the idea of inheriting 
 constructors, but I've changed my mind.  Inheriting constructors would 
 allow for an entire class of generic programming that simply isn't 
 possible right now.  The basic rule would be simple and much like the 
 function lookup rules already in place: if a class contains no 
 constructors then it inherits the constructors of the nearest parent 
 where some are defined.  Defining even a single constructor, however, 
 effectively occludes superclass constructors and disables this 
 behavior (the workaround being an alias, like with function lookup, 
 except that it's currently impossible to explicitly reference a class 
 constructor).

 The original motivation for this idea was a need for some way to 
 attach "on destruct" behavior to an arbitrary class:

     class PrintOnDestruct( T ) :
         public T
     {
         ~this()
         {
             printf( "dtor: %.*s\n", super.classinfo.name );
         }
     }

     class MyClass
     {
         this( int a, int b, int c ) {}
     }

     auto c = new PrintOnDestruct!(MyClass)( a, b, c );

 As far as I know, the only way this is currently possible is to 
 explicitly write all relevant constructors in PrintOnDestruct.

 I believe this feature may also obviate the need for language support 
 of placement new:

     class Placed( T ) :
         public T
     {
         new( void* p, size_t sz )
         {
             return p;
         }
     }

     class MyClass
     {
         this( int x ) { val = x; }
         private int val;
     }

     auto p = new(loc) Placed!(MyClass)( 0 );

 I can think of other examples as well, but these are the two most 
 relevant to what prompted this post in the first place.


 On a semi-related note, it would also be nice if there were some way 
 to obtain the ParameterTypeTuple for class constructors in general.  
 Since there is currently no way to explicitly reference constructors, 
 this sort of thing isn't possible:

     class MyClass
     {
         this( int x ) {}
     }

     alias ParametersOf!(MyClass.this) CtorParams;

 The most obvious use case here would be object factories.  Let's say I 
 want to be able to generate objects with the same set of parameters 
 each time:

     struct TupleInst( Types... )
     {
         Tuple!(Types) data;
     }

     class Factory!( T )
     {
         this( ParametersOf!(T.this) args )
         {
             foreach( i, arg; args )
             {
                 store.data[i] = arg;
             }
         }

         T generate()
         {
             return new T( store.data );
         }

         private TupleInst!(ParametersOf!(T.this)) store;
     }

     class MyClass
     {
         this( int x ) {}
     }

     auto fact = new Factory!(MyClass)( 0 );
     auto objA = fact.generate();
     auto objB = fact.generate();

 So something roughly like parameter binding but for constructors.  
 This latter idea likely has less utility than constructor inheritance, 
 but I've run into one or two places where it would have been very 
 useful, and I had to hack a solution.  Both were essentially similar 
 to the example above, but with a different goal in mind.


 Sean
Since you asked, I agree (those semantics are more useful, and more consistent), but what does it matter... -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jul 11 2007
prev sibling parent Serg Kovrov <kovrov bugmenot.com> writes:
I like idea of inheriting constructors.
votes++

--serg
Jul 11 2007