digitalmars.D - Inheritance for structs
- Uwe Salomon (8/8) May 12 2005 Hi,
- Andrew Fedoniouk (31/39) May 12 2005 "Has this been a discussion subject before?"
- Chris Sauls (28/28) May 12 2005 Andrew's use of mixins is one good method. Another is to use inner
- Uwe Salomon (9/13) May 12 2005 If i needed virtual functions and all that stuff, i would use a class. I...
- Ben Hinkle (4/18) May 12 2005 I'm curious about the context - can you describe the problem in more det...
- Uwe Salomon (58/72) May 13 2005 :) Well, the idea behind it is just the same as with MinTL: Containers
- Ben Hinkle (41/114) May 13 2005 ok, that makes sense to me now. I actually thought you had wanted to inh...
- Uwe Salomon (8/15) May 13 2005 :)
Hi, what exactly are the objections against simple inheritance mechanisms (without virtual functions, RTTI or something like that) for structs? That would make it easy to base a struct upon an existing one without the need to rewrite/delegate existing functions. Has this been a discussion subject before? Thanks uwe
May 12 2005
"Has this been a discussion subject before?" I am pretty sure - yes. If I need two structures to have common members then I am using mixins for defininig common parts of such structures. Well, of course it is a palliative , but mostly works. Sample: template BrickT() { ushort type; short posx; short posy; ushort dimx; ushort dimy; short ascent; rect place() { return rect( pos, dim ); } point pos() { return point( posx, posy); } size dim() { return size( dimx, dimy); } } align(2) struct Brick // non breakable layout element { mixin BrickT; } align(2) struct Word // word or space { mixin BrickT; ushort length; // total length in wchars // wchars are here.... } Andrew. "Uwe Salomon" <post uwesalomon.de> wrote in message news:op.sqnsqpu96yjbe6 sandmann.maerchenwald.net...Hi, what exactly are the objections against simple inheritance mechanisms (without virtual functions, RTTI or something like that) for structs? That would make it easy to base a struct upon an existing one without the need to rewrite/delegate existing functions. Has this been a discussion subject before? Thanks uwe
May 12 2005
Andrew's use of mixins is one good method. Another is to use inner structs and aliases. For example: The one thing that is missing from either method, and is therefore the one thing I personally would like to see struct-inheritance for, is hierarchial type resolution. In other words, I couldn't declare a function to take a parameter of type Size and then pass it a Rect. I think the real stopping point probably boils down to virtual functions, but there might be another way? -- Chris Sauls
May 12 2005
In other words, I couldn't declare a function to take a parameter of type Size and then pass it a Rect. I think the real stopping point probably boils down to virtual functions, but there might be another way?If i needed virtual functions and all that stuff, i would use a class. I think it is a good idea that structs don't have that ballast. All i am talking of is a simple way to base a struct upon another struct. If it were just for three member variables and a function, i would use aliases. But i have structs with a lot of functions, 30 or 50 or so. They are structs because they *need* value semantics. I don't want to write aliases for all these functions, for all these structs. And using mixins is just so clumsy with 2000 lines of code in them, and not very clear style either. uwe
May 12 2005
"Uwe Salomon" <post uwesalomon.de> wrote in message news:op.sqoid3tj6yjbe6 sandmann.maerchenwald.net...I'm curious about the context - can you describe the problem in more detail? That's a pretty honkin' struct.In other words, I couldn't declare a function to take a parameter of type Size and then pass it a Rect. I think the real stopping point probably boils down to virtual functions, but there might be another way?If i needed virtual functions and all that stuff, i would use a class. I think it is a good idea that structs don't have that ballast. All i am talking of is a simple way to base a struct upon another struct. If it were just for three member variables and a function, i would use aliases. But i have structs with a lot of functions, 30 or 50 or so. They are structs because they *need* value semantics. I don't want to write aliases for all these functions, for all these structs. And using mixins is just so clumsy with 2000 lines of code in them, and not very clear style either. uwe
May 12 2005
:) Well, the idea behind it is just the same as with MinTL: Containers should be structs to reduce overhead and, more important, to gain value semantics. That makes containers in containers possible: Map!(char[], Vector!(int)) funnyMap; If Vector was a template class, all the vectors would need initialization (-- not sure if this is correct grammar, i have problems with the conjunctive... --), because they are null by default. That fact made all my containers (Vector, List, LinkedList, Map) structs, just like yours in MinTL. They are quite big, as you can imagine (lots of convenience functions and algorithms, sorting, etc.). Now if i want to write a Queue for example, that's just a special LinkedList (though that's not the best way to implement a queue, yes): struct Queue(T) : LinkedList!(T) { public void enqueue(T value) { append(value); } // Or better, with aliases: alias takeLast dequeue; } That gives me a nice queue, with minimal effort and all the good things from LinkedList. This could be realized with the technique you used, yes (enqueue and dequeue in LinkedList, and Queue is just an alias), but look at the following example: struct StringList : public List!(char[]) // Actually, char[] would be a struct String. { public char[] join() { // Not bad, but could be implemented a bit better: size_t fullLength = 0; foreach (char[] str; *this) fullLength += str.length; char[] result; result.length = fullLength; fullLength = 0; foreach (char[] str; *this) { result[fullLength .. (fullLength + str.length)] = str[]; fullLength += str.length; } } // Other functions, like join(char[] sep) ... } I cannot program that functionality into List, neither do i want to reimplement List!(char[]). All i have left is extracting the List implementation into a mixin, and inserting this mixin into List and StringList (or mess around with partial specialization, even worse). Though that is possible, it is not very straightforward and clear style. The above is such a simple idea, but to realize it i need to come up with complex templates, mixins and whatever is possible in D. That's why i asked for struct inheritance. But, as it is unlikely that Walter changes it, are there some clever solutions for the StringList that come to your mind? As i see it, it is not possible to imitate the behaviour of QStringList here... :( Ciao uweIf i needed virtual functions and all that stuff, i would use a class. I think it is a good idea that structs don't have that ballast. All i am talking of is a simple way to base a struct upon another struct. If it were just for three member variables and a function, i would use aliases. But i have structs with a lot of functions, 30 or 50 or so. They are structs because they *need* value semantics. I don't want to write aliases for all these functions, for all these structs. And using mixins is just so clumsy with 2000 lines of code in them, and not very clear style either.I'm curious about the context - can you describe the problem in more detail? That's a pretty honkin' struct.
May 13 2005
"Uwe Salomon" <post uwesalomon.de> wrote in message news:op.sqppz5wb6yjbe6 sandmann.maerchenwald.net...ok, that makes sense to me now. I actually thought you had wanted to inherit data members and not function members. You are right that it would be useful to allow "virtual functions" for structs. I guess:) Well, the idea behind it is just the same as with MinTL: Containers should be structs to reduce overhead and, more important, to gain value semantics. That makes containers in containers possible: Map!(char[], Vector!(int)) funnyMap; If Vector was a template class, all the vectors would need initialization (-- not sure if this is correct grammar, i have problems with the conjunctive... --), because they are null by default. That fact made all my containers (Vector, List, LinkedList, Map) structs, just like yours in MinTL. They are quite big, as you can imagine (lots of convenience functions and algorithms, sorting, etc.).If i needed virtual functions and all that stuff, i would use a class. I think it is a good idea that structs don't have that ballast. All i am talking of is a simple way to base a struct upon another struct. If it were just for three member variables and a function, i would use aliases. But i have structs with a lot of functions, 30 or 50 or so. They are structs because they *need* value semantics. I don't want to write aliases for all these functions, for all these structs. And using mixins is just so clumsy with 2000 lines of code in them, and not very clear style either.I'm curious about the context - can you describe the problem in more detail? That's a pretty honkin' struct.Now if i want to write a Queue for example, that's just a special LinkedList (though that's not the best way to implement a queue, yes): struct Queue(T) : LinkedList!(T) { public void enqueue(T value) { append(value); } // Or better, with aliases: alias takeLast dequeue;hmm - MinTL has "removeLast"... I think I actually like "takeLast" better.} That gives me a nice queue, with minimal effort and all the good things from LinkedList. This could be realized with the technique you used, yes (enqueue and dequeue in LinkedList, and Queue is just an alias), but look at the following example: struct StringList : public List!(char[]) // Actually, char[] would be a struct String. { public char[] join() { // Not bad, but could be implemented a bit better: size_t fullLength = 0; foreach (char[] str; *this) fullLength += str.length; char[] result; result.length = fullLength; fullLength = 0; foreach (char[] str; *this) { result[fullLength .. (fullLength + str.length)] = str[]; fullLength += str.length; } } // Other functions, like join(char[] sep) ... }Thinking off the top of my head to write join() today you'd have to put it on the top level instead, correct? Generalizing it to join any container of lists might not be a bad things, though. If the container supports foreach one could write template join(T, Container) { T[] join(Container c){ size_t n=0; foreach(T[] val; c) { n += val.length; } T[] res = new T[n]; n = 0; foreach(T[] val; c) { res[n .. n+val.length] = val[]; n+= val.length; } return res; } } and then call it like alias List!(char[]) StringList; alias join!(char,StringList) strjoin; // for simpler user code StringList strs; ... char[] together = strjoin(strs); ArrayList!(int[]) ints; ... int[] together2 = join!(int,typeof(ints))(ints); I might include some handy things like that into MinTL.I cannot program that functionality into List, neither do i want to reimplement List!(char[]). All i have left is extracting the List implementation into a mixin, and inserting this mixin into List and StringList (or mess around with partial specialization, even worse). Though that is possible, it is not very straightforward and clear style. The above is such a simple idea, but to realize it i need to come up with complex templates, mixins and whatever is possible in D. That's why i asked for struct inheritance.I don't completely agree that mixins are not straightforward or have a clear style (if I understand your position). It's pretty much the same to me if a type gets features from inheritance or from a mixin. The difference is only syntactic, really: struct Foo : Bar { } struct Foo { mixin Bar } unless you want to allow Foos to be implicitly cast to Bars (mixins wouldn't be able to do that).But, as it is unlikely that Walter changes it, are there some clever solutions for the StringList that come to your mind? As i see it, it is not possible to imitate the behaviour of QStringList here... :( Ciao uwe
May 13 2005
:) I have both of 'em, removeLast only removes, takeLast removes and returns it.// Or better, with aliases: alias takeLast dequeue;hmm - MinTL has "removeLast"... I think I actually like "takeLast" better.char[] together = strjoin(strs);I have to admit that this is really neat. :)It's pretty much the same to me if a type gets features from inheritance or from a mixin.Perhaps i will go this way, then. Or make it global. Ah, well, D is not C++, and Indigo is not Qt. Thanks & ciao uwe
May 13 2005