August 19, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | "Sean L. Palmer" <palmer.sean@verizon.net> wrote in message news:bhsle2$g5c$1@digitaldaemon.com... > It's an issue that comes up more than you might think, and not only with constructors. It's similar to the issue of forwarding functions in general. > It sucks to be forced to explicitly type in lots of "glue" code. Code that > chains one function to another. You get this alot in any interface work. It's a maintenance problem because the more code you have to type, the more > code that the maintenance programmers must maintain. And, to use your own argument, more than 60% of all coding is in the maintenance phase. > > Say you have a class that has a bug. Say this class has 50 constructors. This invalidates your argument. I can conceive of no well-designed class that would contain 50 constructors. Show me a valid example of such. > You want to subclass this class and fix the bug in your version of the class > (the class is someone else's library, you can't change it). To do so you have to manually, and tediously, write forwarding constructors for all 50 or > you lose functionality! Plus if the base class later gets new ctors, your class won't get them. You now have a situation where you have to manually maintain 50 direct links to the base class. > > It's not a non-issue. When moving classes around in the hierarchy due to fluctuating designs, you often have to type such glue code. I'd rather be doing something more productive, save the slave labor. > > It's almost as bad as cut and paste programming, but in this case it's interfaces that are getting copied over and over, instead of commands. Still hard to maintain. > > Sean > > "Matthew Wilson" <matthew@stlsoft.org> wrote in message news:bhrgfi$1ri6$1@digitaldaemon.com... > > > > "Jeroen van Bemmel" <anonymous@somewhere.com> wrote in message news:bhqtk7$ukn$1@digitaldaemon.com... > > > Perhaps, as a compromise, add a keyword 'inherited' to a constructor, > > which > > > indicates that the constructor is automatically inherited by derived > > > classes? > > > I don't think implicit behavior would be good here, but an explicit > > keyword > > > is ok. Drawback is that you cannot see this constructor by reading the derived class' code; perhaps it would be better to add a special > > constructor > > > to the derived class instead (something like 'inherited this( char[] > > msg )') > > > and no body > > > > But is such a case, where's the effort in just calling the base ctor? > > > > Remember, more than 60% of all coding is in the maintenance phase (Robert > > Glass, 2003), so why does anyone care about a few characters typed at creation time? > > > > This is a non-issue. > > |
August 19, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | > > You probably want one to match any useful constructor in string. All I really wanted to do, though, is expose string's constructors and add one of > my own: > > class pathname : public string > { > using string.this(); > using string.this(char[] s); > using string.this(wchar[] s); > using string.this(char* p, uint len); > this(pathname f) { super.this(cast(string)f); } > } > > But that's almost as wordy as overriding them. Some way to just import all > the superclass constructors would be nice. You automatically get all the superclass methods, why not constructors? At least if there was a way to get them... > > Sean > I like the idea as in the example above. I think we should also be able to do something like: class pathname : public string { public: using public string.this(...); private: using private string.this(...); } Here we could uses (...) for the parameters. Anything that does not match a constructor in pathname will check in string. This case will have the less priority. Adding public (or other access modifier) would allows to only import methods with the proper access (in case we have overload with different access). In fact, this should also be allowed for any inherited functions and even for delegation (for delegation, we should also support import all methods (except operators, constructors and destructors) maybe by specifying * for the method name... Allowing using base constructor is great if we want a class hierarchy where most object have their distinct type: class pathname : public string... class drivename : public string... class dirname : public string... class filename : public string... class extentionname : public string... This allows to then have code that accept only the proper object type: pathname merge(drivename dr, dirname di, filename fi, extentionname ex) and this help making type-safe code without the burden of writting a lot of constructor. I think this is an example of well designed code where it could be usefull to have distinct type... Another case where it would be usefull is if the derived class need some extra initialisation (without any args) because it has some few added members (for ex. a counter of created objects). |
August 19, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew Wilson | It was hypothetical. Ok, I don't know about 50, but I've definitely seen classes like Vector3D and std::string that have like 10 to 15 ctors, and all of them are necessary. ;) You're so quick to dismiss. "It's a non-issue." "I'm not going to listen to your argument because it has a bug." Have some respect. Sean "Matthew Wilson" <matthew@stlsoft.org> wrote in message news:bhso2v$jti$1@digitaldaemon.com... > > "Sean L. Palmer" <palmer.sean@verizon.net> wrote in message news:bhsle2$g5c$1@digitaldaemon.com... > > It's an issue that comes up more than you might think, and not only with constructors. It's similar to the issue of forwarding functions in > general. > > It sucks to be forced to explicitly type in lots of "glue" code. Code > that > > chains one function to another. You get this alot in any interface work. > > It's a maintenance problem because the more code you have to type, the > more > > code that the maintenance programmers must maintain. And, to use your own > > argument, more than 60% of all coding is in the maintenance phase. > > > > Say you have a class that has a bug. Say this class has 50 constructors. > > This invalidates your argument. I can conceive of no well-designed class that would contain 50 constructors. Show me a valid example of such. > > > You want to subclass this class and fix the bug in your version of the > class > > (the class is someone else's library, you can't change it). To do so you > > have to manually, and tediously, write forwarding constructors for all 50 > or > > you lose functionality! Plus if the base class later gets new ctors, your > > class won't get them. You now have a situation where you have to manually > > maintain 50 direct links to the base class. > > > > It's not a non-issue. When moving classes around in the hierarchy due to > > fluctuating designs, you often have to type such glue code. I'd rather be > > doing something more productive, save the slave labor. > > > > It's almost as bad as cut and paste programming, but in this case it's interfaces that are getting copied over and over, instead of commands. Still hard to maintain. > > > > Sean > > > > "Matthew Wilson" <matthew@stlsoft.org> wrote in message news:bhrgfi$1ri6$1@digitaldaemon.com... > > > > > > "Jeroen van Bemmel" <anonymous@somewhere.com> wrote in message news:bhqtk7$ukn$1@digitaldaemon.com... > > > > Perhaps, as a compromise, add a keyword 'inherited' to a constructor, > > > which > > > > indicates that the constructor is automatically inherited by derived > > > > classes? > > > > I don't think implicit behavior would be good here, but an explicit > > > keyword > > > > is ok. Drawback is that you cannot see this constructor by reading the > > > > derived class' code; perhaps it would be better to add a special > > > constructor > > > > to the derived class instead (something like 'inherited this( char[] > > > msg )') > > > > and no body > > > > > > But is such a case, where's the effort in just calling the base ctor? > > > > > > Remember, more than 60% of all coding is in the maintenance phase > (Robert > > > Glass, 2003), so why does anyone care about a few characters typed at creation time? > > > > > > This is a non-issue. |
August 20, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Mori | "Philippe Mori" <philippe_mori@hotmail.com> wrote in message news:bhtcvp$1hq6$1@digitaldaemon.com... > > > > You probably want one to match any useful constructor in string. All I really wanted to do, though, is expose string's constructors and add one > of > > my own: > > > > class pathname : public string > > { > > using string.this(); > > using string.this(char[] s); > > using string.this(wchar[] s); > > using string.this(char* p, uint len); > > this(pathname f) { super.this(cast(string)f); } > > } > > > > But that's almost as wordy as overriding them. Some way to just import > all > > the superclass constructors would be nice. You automatically get all the > > superclass methods, why not constructors? At least if there was a way to > > get them... > > > > Sean > > > > I like the idea as in the example above. I think we should also be able to do something like: > > class pathname : public string > { > public: > using public string.this(...); > > private: > using private string.this(...); > } > D already has (imho) one nice change to class defs ... it uses `this` for the constructor; would it not be better to use `super` rather than the super classes name as in. class pathname : public string { public: using public super( char [] ); } or to get them all class pathname : public string { public: using public super.this; } from sean's example class pathname : public string { using super(); using super(char[] s); using super(wchar[] s); using super(char* p, uint len); // this(pathname f) { super.this(cast(string)f); } // is already in D as `this(pathname f) { super(cast(string)f); }` using super( string ); // replaces the above } I believe that you can drop the using ... without breaking the parser so becomes class pathname : public string { super(); // imports this() from super ... etc ... super() { } would be an error super(char[] s); super(wchar[] s); super(char* p, uint len); // this(pathname f) { super.this(cast(string)f); } // is already in D as `this(pathname f) { super(cast(string)f); }` super( string ); // replaces the above } the code `super.this;` would import all constructors |
August 21, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | I had considered using super in that way, a little bit. Wow that really helps, Mike! Looks cleaner. Thanks! Sean "Mike Wynn" <mike.wynn@l8night.co.uk> wrote in message news:bi0mg3$8l1$1@digitaldaemon.com... > > "Philippe Mori" <philippe_mori@hotmail.com> wrote in message news:bhtcvp$1hq6$1@digitaldaemon.com... > > > > > > You probably want one to match any useful constructor in string. All I > > > really wanted to do, though, is expose string's constructors and add one > > of > > > my own: > > > > > > class pathname : public string > > > { > > > using string.this(); > > > using string.this(char[] s); > > > using string.this(wchar[] s); > > > using string.this(char* p, uint len); > > > this(pathname f) { super.this(cast(string)f); } > > > } > > > > > > But that's almost as wordy as overriding them. Some way to just import > > all > > > the superclass constructors would be nice. You automatically get all > the > > > superclass methods, why not constructors? At least if there was a way > to > > > get them... > > > > > > Sean > > > > > > > I like the idea as in the example above. I think we should also be able to do something like: > > > > class pathname : public string > > { > > public: > > using public string.this(...); > > > > private: > > using private string.this(...); > > } > > > D already has (imho) one nice change to class defs ... it uses `this` for > the constructor; > would it not be better to use `super` rather than the super classes name as > in. > > class pathname : public string > { > public: > using public super( char [] ); > } > > or to get them all > > > class pathname : public string > { > public: > using public super.this; > } > > from sean's example > class pathname : public string > { > using super(); > using super(char[] s); > using super(wchar[] s); > using super(char* p, uint len); > // this(pathname f) { super.this(cast(string)f); } > // is already in D as `this(pathname f) { super(cast(string)f); }` > using super( string ); // replaces the above > } > I believe that you can drop the using ... without breaking the parser so > becomes > class pathname : public string > { > super(); // imports this() from super ... etc ... super() { } would be > an error > super(char[] s); > super(wchar[] s); > super(char* p, uint len); > // this(pathname f) { super.this(cast(string)f); } > // is already in D as `this(pathname f) { super(cast(string)f); }` > super( string ); // replaces the above > } > > the code `super.this;` would import all constructors |
October 01, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | Why don't make constructor act like any ordinary method? If you write a class with no constructors it will inherit its parent's ones. If you write any constructor it will inherit no one. . class Base . { . this() {} . this(int a) {} . } . . class A : Base . { . // inherit super() and super(int) . } . . class B : Base . { . this(int a) {super(a);} . // only "inherits" super(int) . // this() won't be inherited . } . . class C : Base . { . this() { super(); } . this(int a) { super(a); } . this(float a) { super(cast(int) a); } . // "inherit" super() and super(int) . // and add this(float) constructor . } The only problem in this solution is that if you only want to add a constructor to the parent's ones, you'll have to rewrite the latters. But this is also a problem with methods, not only with constructors: what if the parent class has a set of overloaded methods and you want the derived class to have all the parent's method PLUS a new one? You have to write wrappers for the overloaded methods! Mike Wynn: >Philippe Mori: >>Sean: >>>You probably want one to match any useful constructor in string. All I really wanted to do, though, is expose string's constructors and add one of >>>my own: >>>class pathname : public string >>>using string.this(); >>> using string.this(char[] s); >>> using string.this(wchar[] s); >>> using string.this(char* p, uint len); >>> this(pathname f) { super.this(cast(string)f); } >>>} >>But that's almost as wordy as overriding them. Some way to just import all >>the superclass constructors would be nice. You automatically get all the >>superclass methods, why not constructors? At least if there was a way to >>get them... >>Sean >>I like the idea as in the example above. I think we should also be able >>to do something like: >>class pathname : public string >>{ >>public: >> using public string.this(...); >> >>private: >> using private string.this(...); >>} >D already has (imho) one nice change to class defs ... it uses `this` for >the constructor; >would it not be better to use `super` rather than the super classes name as >in. >class pathname : public string >{ >public: > using public super( char [] ); >} > >or to get them all >class pathname : public string >{ >public: > using public super.this; >} > >from sean's example >class pathname : public string >{ > using super(); > using super(char[] s); > using super(wchar[] s); > using super(char* p, uint len); > // this(pathname f) { super.this(cast(string)f); } > // is already in D as `this(pathname f) { super(cast(string)f); }` > using super( string ); // replaces the above >} >I believe that you can drop the using ... without breaking the parser so >becomes >class pathname : public string >{ > super(); // imports this() from super ... etc ... super() { } would be an error > super(char[] s); > super(wchar[] s); > super(char* p, uint len); > // this(pathname f) { super.this(cast(string)f); } > // is already in D as `this(pathname f) { super(cast(string)f); }` > super( string ); // replaces the above >} > the code `super.this;` would import all constructors |
October 01, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dario | In article <blf176$1tuk$1@digitaldaemon.com>, Dario wrote: > Why don't make constructor act like any ordinary method? I agree that ctors should indeed behave like other methods at least in the sense that they should be inherited, and that they should be overloaded with the same semantics. Let's call it a gut feeling. But I disagree with this: > If you write a class with no constructors it will inherit its parent's ones. If you write any constructor it will inherit no one. This would, actually, be different from ordinary methods. In D, overriding function <func> in a derived class does not hide overloaded <func>'s from the parent class. This is unlike C++, where the following is illegal: struct A { void func(); void func(int); }; struct B : A { void func(); }; void f(B* b) { b->func(1); // error: no matching function for call to `B::func(int)' } // This however works, and is probably the reason why the situation is // in D as it is: void g(B* b) { ((A*) b)->func(1); } On the other hand, suppose that derived constructors wouldn't hide their predecessors with the same name. Then the one who makes the derived class would not necessarily have the confidence that he is the only one who can control the creation of the class. But who cares? The situation is the same with all other methods, too! The superclass's method may violate the invariant. What are ctors anyway? I'd actually go as far as to make them just ordinary methods with no pre- and postconditions (except that they expect nothing and ensure that the invariant is true when exiting the constructor - just like any other method.) They are called differently than usual methods, yes. But how differently? A a = new A; should be more or less identical to: A a; *((void**)A) = malloc(sizeof A); a.__ptr_to_vtbl = __vtbl_of_A; a.this(); (right?) So actually it is just the calling of constructors that is usually done together with memory allocation and vtable initialization. Therefore special syntax, "new X(args)", is ok there. But the ctor call could be just like any other method call (except that the object is assumed to be rubbish before and a good object afterwards). Its name could even be something less special, like "ctor" or "init". "this" (which is a keyword) seems arbitrary. Before someone starts to pull out good old 42kg C++ programming language manual and point out that ctors are not really methods, let me rant a bit -- I've always detested that argument because they look like methods, they are used like methods (ok you can't call them directly, like dtors, but still). Why not? I don't remember all the arguments why ctors are not methods but I recall them being along the lines "We need them to be treated as if they were MAGIC because you might use them to construct a base class of a virtually derived class and pass hidden bool parameters to note whether it has already been constructed. So now be a good girl/boy and remember not to even utter the name 'member function' in the same sentence with constructors." Yeah. -Antti (Thought of the day, one of those you get when you have enough sleep: I started out writing this by merely agreeing with the original poster, but ended up writing a stronger proposition. Not totally unlike having a strengthened postcondition in a derived class.) |
October 01, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Antti Sykäri | I agree, I actually like the way Objective-C constructors are formed. -(id)init; // equivalent to this(); -(MyClass)init; // equivalent to this(); -(MyClass)initWithObject:(NSObject *)obj; // equivalent to this(Object obj); If the same where applied to D the constructor for thread would be Thus. Thread this() { this = super(); return this; } NB. this allows for implementation of singletons without requiring static methods. static MyObject obj = new MyObject(); MyObject this() { if ( !obj ) { this = super(); } else { this = obj; } return this; } // Don't hate me because i'm different. The this is semantically significant enough to identify the method as a constructor, although I would much prefer a name like init; alloc; className; call me an objective-c fan if you will but having a method this and the reference this seems a little to overloaded to me, likewise the dtor could be similally named otherwise. void dealloc(); void finalize(); void ~className(); Another functional part of objective-C that would be really useful is the inheritance of class functions. Within a static function it is my belief that this should refer to the class since instances are irrelevant. Imagine the following factory method; static Object createInstance() { return this.init(); } I'll stop now before categories come up <smile/>. In article <slrnbnmcgu.q95.jsykari@pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says... > >In article <blf176$1tuk$1@digitaldaemon.com>, Dario wrote: >> Why don't make constructor act like any ordinary method? > >I agree that ctors should indeed behave like other methods at least in the sense that they should be inherited, and that they should be overloaded with the same semantics. Let's call it a gut feeling. But I disagree with this: > >> If you write a class with no constructors it will inherit its parent's ones. If you write any constructor it will inherit no one. > >This would, actually, be different from ordinary methods. In D, overriding function <func> in a derived class does not hide overloaded <func>'s from the parent class. This is unlike C++, where the following is illegal: > >struct A { > void func(); > void func(int); >}; > >struct B : A { > void func(); >}; > >void f(B* b) { > b->func(1); // error: no matching function for call to `B::func(int)' >} > >// This however works, and is probably the reason why the situation is // in D as it is: > >void g(B* b) { > ((A*) b)->func(1); >} > >On the other hand, suppose that derived constructors wouldn't hide their predecessors with the same name. Then the one who makes the derived class would not necessarily have the confidence that he is the only one who can control the creation of the class. But who cares? The situation is the same with all other methods, too! The superclass's method may violate the invariant. > >What are ctors anyway? > >I'd actually go as far as to make them just ordinary methods with no pre- and postconditions (except that they expect nothing and ensure that the invariant is true when exiting the constructor - just like any other method.) > >They are called differently than usual methods, yes. But how differently? > >A a = new A; > >should be more or less identical to: > >A a; >*((void**)A) = malloc(sizeof A); >a.__ptr_to_vtbl = __vtbl_of_A; >a.this(); > >(right?) > >So actually it is just the calling of constructors that is usually done together with memory allocation and vtable initialization. Therefore special syntax, "new X(args)", is ok there. But the ctor call could be just like any other method call (except that the object is assumed to be rubbish before and a good object afterwards). Its name could even be something less special, like "ctor" or "init". "this" (which is a keyword) seems arbitrary. > >Before someone starts to pull out good old 42kg C++ programming language manual and point out that ctors are not really methods, let me rant a bit -- I've always detested that argument because they look like methods, they are used like methods (ok you can't call them directly, like dtors, but still). Why not? > >I don't remember all the arguments why ctors are not methods but I recall them being along the lines "We need them to be treated as if they were MAGIC because you might use them to construct a base class of a virtually derived class and pass hidden bool parameters to note whether it has already been constructed. So now be a good girl/boy and remember not to even utter the name 'member function' in the same sentence with constructors." Yeah. > >-Antti > >(Thought of the day, one of those you get when you have enough sleep: >I started out writing this by merely agreeing with the original poster, >but ended up writing a stronger proposition. Not totally unlike having a >strengthened postcondition in a derived class.) > |
October 01, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Antti Sykäri | Antti Sykäri:
> This would, actually, be different from ordinary methods. In D, overriding function <func> in a derived class does not hide overloaded <func>'s from the parent class. This is unlike C++...
No, D's like C++.
module test;
class A
{
void func() {}
void func(int n) {}
}
class B
{
void func(int n) {}
}
void main()
{
B b = new B;
b.func();
}
test.d(14): function func (int a) does not match argument types ()
|
October 02, 2003 Re: constructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Antti Sykäri | "Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbnmcgu.q95.jsykari@pulu.hut.fi... > In article <blf176$1tuk$1@digitaldaemon.com>, Dario wrote: > > Why don't make constructor act like any ordinary method? > > I agree that ctors should indeed behave like other methods at least in the sense that they should be inherited, and that they should be overloaded with the same semantics. Let's call it a gut feeling. But I disagree with this: I don't see why they have to be so special either. Now if we could just make Factories easily enough why would you even need new or ctor syntax at all? As sugar to aid implementing the factories I guess. You could also think of a constructor as a typecast from void to the class type, and a destructor as typecast to void. But ctors can take parameters, so just make a factory that uses typecast from void to produce a valid object (unitialized except for the vtable and any class operator void->class) and then runs some method to initialize it. The C++ concept of constructor most certainly is not the only way to look at object creation. Sean |
Copyright © 1999-2021 by the D Language Foundation