|
Re: Maybe I can answer
|
Posted: Jan 18, 2006 7:20 AM
|
|
> Well the code snippets would behave less the same, but you lead me to an error > I made. The Renamer object was a temporary, so b would have been left referring to > a temorary Renamer object which would have been deleted at the end of the statement.
Yeah, I though of that too, but I dismissed it as not probable (because of the way you used it) and instead thought that you somehow made Renamer(a) to be allocated on heap.
def main() { CA a; TB b = Renamer(a); b.whatever(); // runtime error (or worse, UB) }
> > def main() { > > CA x; > > Renamer *y = new Renamer(x); > > TB z = *y; > > > > delete y; > > > > //will this work? > > z.b(); > > }
> The answer is not in the current version of HeronFront, but I plan on making > it possible in later versions.
This is like the difference between heaven and hell. If programmer has to worry about correct lifetime of object pointed to by "y", then it will turn into a nightmare (even with strong/weak references). The programs are usually filled with examples like this (and usually hidden as function calls that accept pointer-to-interface), it will be impossible to do any big projects in Heron.
If it works, than thats great. It's like adapter but better. I'm even considering if this is subtyping a-posteriori, but if it isn't, then it's very close.
Now, answer to your previous post:
> > method names of M1 and M2 don't match, but also M2 misses > > some functions that M1 has (that can be easily > > implemented given public interface of M2), and M1 misses > > some functions that M2 has (that can be easily > > implemented given public interface of M1).
> You said they are the same type, but with different methods can you really say > they are the same type? Perhaps they share characteristics and internal structure, > but I can't see how one can claim they are the same type, or subtypes of each other.
Maybe I could have said that M1 is inherently subtype of M2 (and vice versa). "Inherently subtype" means that M1 could be made to be subtype of M2 by adding subtype specification and writing missing methods. For example:
class StackA { //.. fields public: void pop() {
} int top() {
} void push(int element) {
} };
class StackB { //.. fields public: int pop_and_return() {
} void push(int element) {
} }; Now, StackB isn't subtype of StackA (yet). But I could make it to be, if I had proper language facilities. I could write this (notice the keyword "augments"):
augment StackB : public StackA { public: void pop() { pop_and_return(); } int top() {int x=pop_and_return(); push(x); return x; } };
Also, this is how I would like subtyping a-posteriori to look like.
> Anyway I see no problem here, I would use a wrapper trait like I describe above. > A wrapper trait can change, or even introduce new behaviour.
[example cut] This looks good. I have two minor objections (not too important): - Programmer must explicitly write T2toT1(y) each time he needs the conversion. Automatic conversion would be better (less code=less bugs). - If M1 has subtypes then you have to write adapter similar to trait T2toT1 for every subtype of M1. If you take my example above with stack and "augments" keyword, there not only does StackB get augmented, but also all of the subtypes of StackB.
> > First thing is that I like renaming.
>Renaming is completely possible within the proposed Heron traits system:
[example cut] I can think of too much problems with renaming as in your example, but I could also say that Heron does have some basic renaming, and stop there. It's no problem for me to continue this discussion, if you want, but I dont know is this renaming issue important to you or not. But I would like to summarize this whole trait discussion like this:
With planned additions, I think, it will be good. Probably better than C++. There are some issues that could be looked after, but nothing too serious.
Oh, and I forgot to answer first question:
> You keep talking about comparing the traits mechanism > I am proposing with multiple inheritance. Inheritance and > subtyping are fundamentally different ideas. Any subtyping > mechanism which depends on inheritance is flawed because it > results in undesirable structural dependencies between subtypes.
We use slightly different terminology. When I say inheritance, I mean both inheritance of implementation and subtyping(inheritance of interface). I understand the difference between inheritance of implementation and subtyping perfectly, and I agree they are fundamentally different ideas.
What happens with subtyping is that, in most cases, programmer wants to inherit implementation along. In order to save typing, this can be done as default by the programming language.
But, I absolutely agree that, if programmer wants it, he must be able to separate subtyping from inheritance of implementation. C++ doesn't allow this, but the problem is circumvented by creating multiple classes, one for interface, one for implementation and maybe more. This is, of course, tedious.
I think you are wrong when saying that subtyping in multiple inheritance depends on inheritance of implementation. This is just the way contemporary languages do it. It is easy to completely separate subtyping and inheritance of implementation with a few additional keywords. I even made a concrete proposal; you can read it here, with a few examples:
http://www.artima.com/forums/flat.jsp?forum=106&thread=142527&start=17&msRange=15
To conclude, I think you are wrong: multiple inheritance does not inherently depend on inheritance of implementation, so it is not flawed.
|
|