digitalmars.D - "The last feature": overridable methods in interfaces
- Andrei Alexandrescu (30/30) Feb 07 2010 Walter has now implemented final methods in interfaces and also
- Lars T. Kyllingstad (5/39) Feb 08 2010 What happens when two interfaces implement the same method? I thought
- Andrei Alexandrescu (4/44) Feb 08 2010 Interfaces do foster multiple inheritance!
- Jacob Carlborg (7/37) Feb 08 2010 I only see two differences with abstract classes: interfaces can't have
- Trass3r (4/9) Feb 08 2010 Yeah, providing default functionality that can be overridden is exactly ...
- Andrei Alexandrescu (6/18) Feb 08 2010 Abstract classes are a kludge meant to put state in a partially
- Andrei Alexandrescu (7/51) Feb 08 2010 I think lack of state is indeed the only difference. The multiple
- Jacob Carlborg (6/57) Feb 08 2010 The obvious solution as I see it would have been using "regular"
- retard (7/58) Feb 08 2010 I really wonder why you're doing this. NIH. Ever heard or Scala and
- Michel Fortin (16/30) Feb 08 2010 Hum, where did Andrei claimed he invented this?
- retard (10/41) Feb 08 2010 No, I don't know the original source. Multiple inheritance is an old and...
- Michel Fortin (9/18) Feb 08 2010 From what I can read, traits in Scala are much than adding function
- Andrei Alexandrescu (7/65) Feb 08 2010 This one really takes the cake. Do you really believe I'm in this for
- retard (38/41) Feb 08 2010 I apologize for being so rude. If I read the proposal correctly, traits
- Andrei Alexandrescu (8/56) Feb 08 2010 That's a nice surprise (what about the backlog? :o)). Just a note, to me...
- grauzone (3/8) Feb 08 2010 When will work on D3 be started?
- Andrei Alexandrescu (3/11) Feb 08 2010 You may start it any time now.
- Walter Bright (8/14) Feb 08 2010 Member functions with bodies is what C++ has with multiple inheritance.
- Steven Schveighoffer (38/67) Feb 08 2010 You forgot to return result :)
- Don (8/45) Feb 08 2010 I don't understand this. How does belowTop() know how to call top()? It
- Andrei Alexandrescu (4/44) Feb 08 2010 It calls top() through the normal interface mechanism. Inside
- Steven Schveighoffer (43/85) Feb 08 2010 Actually, I think Don has a point here. A virtual function (even on an ...
- Andrei Alexandrescu (6/56) Feb 08 2010 That is done via an adjustment of the reference. In the case of an
- Steven Schveighoffer (14/30) Feb 08 2010 void foo(Stack!T st)
- Andrei Alexandrescu (4/38) Feb 08 2010 If an object overrode the default implementation, the pointer to method
- Steven Schveighoffer (17/52) Feb 08 2010 If I understand this correctly, calling such a "default implementation" ...
- Andrei Alexandrescu (5/57) Feb 08 2010 Yes, but let's not forget that each object stores more than one vptrs.
- Steven Schveighoffer (48/103) Feb 08 2010 Yes, but I think it's happening at the call site and not inside the
- Don (7/43) Feb 08 2010 I have a strong suspicion that it's exactly the same as multiple
- Andrei Alexandrescu (6/50) Feb 08 2010 I think it's only data. The problem is that you end up storing multiple
- dsimcha (26/56) Feb 08 2010 If we're going to do this, then why not allow (biggest oxymoron of all t...
Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. Andrei
Feb 07 2010
Andrei Alexandrescu wrote:Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome.What happens when two interfaces implement the same method? I thought multiple subtyping without multiple inheritance was the raison d'être for interfaces. -Lars
Feb 08 2010
Lars T. Kyllingstad wrote:Andrei Alexandrescu wrote:Ambiguity error.Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome.What happens when two interfaces implement the same method?I thought multiple subtyping without multiple inheritance was the raison d'être for interfaces.Interfaces do foster multiple inheritance! Andrei
Feb 08 2010
On 2/8/10 06:37, Andrei Alexandrescu wrote:Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance? /Jacob Carlborg
Feb 08 2010
I only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance?Yeah, providing default functionality that can be overridden is exactly what abstract classes are for. Interfaces were introduced to circumvent all those multiple inheritance problems!
Feb 08 2010
Trass3r wrote:Abstract classes are a kludge meant to put state in a partially implemented class. I don't think mentioning abstract classes is a counter-argument to defining methods to interfaces.I only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance?Yeah, providing default functionality that can be overridden is exactly what abstract classes are for.Interfaces were introduced to circumvent all those multiple inheritance problems!Yes; a problem that abstract classes are not solving. Andrei
Feb 08 2010
Jacob Carlborg wrote:On 2/8/10 06:37, Andrei Alexandrescu wrote:I think lack of state is indeed the only difference. The multiple inheritance bit makes all the difference, so I think abstract classes are not enough. A designer who wants to define some methods in an interface is forced at design time to choose an abstract class over an interface, thus severely limiting clients. AndreiWalter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance?
Feb 08 2010
On 2/8/10 14:03, Andrei Alexandrescu wrote:Jacob Carlborg wrote:The obvious solution as I see it would have been using "regular" interfaces and template mixins. But that fails since the mixed in methods can't overload on the already present methods. Have traits (http://en.wikipedia.org/wiki/Trait_%28computer_science%29) ever been considered?On 2/8/10 06:37, Andrei Alexandrescu wrote:I think lack of state is indeed the only difference. The multiple inheritance bit makes all the difference, so I think abstract classes are not enough. A designer who wants to define some methods in an interface is forced at design time to choose an abstract class over an interface, thus severely limiting clients. AndreiWalter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance?
Feb 08 2010
Mon, 08 Feb 2010 07:03:43 -0600, Andrei Alexandrescu wrote:Jacob Carlborg wrote:I really wonder why you're doing this. NIH. Ever heard or Scala and traits? I'm sorry, but you didn't invent this feature - giving some kind of attribution would be honest. I can imagine how this proposal goes forward. Suddenly D 2 gets almost exactly the same feature (+ contracts) as Scala has had for a long time and somehow you get all the credit in the practical (C++/D) PL community.On 2/8/10 06:37, Andrei Alexandrescu wrote:I think lack of state is indeed the only difference. The multiple inheritance bit makes all the difference, so I think abstract classes are not enough. A designer who wants to define some methods in an interface is forced at design time to choose an abstract class over an interface, thus severely limiting clients.Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance?
Feb 08 2010
On 2010-02-08 11:58:53 -0500, retard <re tard.com.invalid> said:Mon, 08 Feb 2010 07:03:43 -0600, Andrei Alexandrescu wrote:Hum, where did Andrei claimed he invented this? To me who knows well Objective-C, this looks like an adaptation to D of the informal protocol concept, which was then superseded by optional methods in formal protocols in Objective-C 2.0. This pattern is used a lot in Objective-C, even though it's implemented differently and is more powerful due to categories. Also, I don't know much about SmallTalk, but given SmallTalk was the inspiration for Objective-C I wouldn't be surprised to see this there too. It's nice to give attribution, but where do we stop? Can you say you know for sure what was the real inspiration for this? -- Michel Fortin michel.fortin michelf.com http://michelf.com/I think lack of state is indeed the only difference. The multiple inheritance bit makes all the difference, so I think abstract classes are not enough. A designer who wants to define some methods in an interface is forced at design time to choose an abstract class over an interface, thus severely limiting clients.I really wonder why you're doing this. NIH. Ever heard or Scala and traits? I'm sorry, but you didn't invent this feature - giving some kind of attribution would be honest. I can imagine how this proposal goes forward. Suddenly D 2 gets almost exactly the same feature (+ contracts) as Scala has had for a long time and somehow you get all the credit in the practical (C++/D) PL community.
Feb 08 2010
Mon, 08 Feb 2010 12:59:33 -0500, Michel Fortin wrote:On 2010-02-08 11:58:53 -0500, retard <re tard.com.invalid> said:No, I don't know the original source. Multiple inheritance is an old and widely known problem. I just meant that instead of bikeshedding here and reinventing everything from scratch, everyone interested in the topic should take a look at Scala's traits since traits basically are interfaces extended with function bodies. Scala also has a solution to the conflicting multiply inherited methods. I just mentioned Scala because it's also a C inspired object oriented language and this feature proposal is more or less 90% the same concept as traits, both syntactically and semantically.Mon, 08 Feb 2010 07:03:43 -0600, Andrei Alexandrescu wrote:Hum, where did Andrei claimed he invented this? To me who knows well Objective-C, this looks like an adaptation to D of the informal protocol concept, which was then superseded by optional methods in formal protocols in Objective-C 2.0. This pattern is used a lot in Objective-C, even though it's implemented differently and is more powerful due to categories. Also, I don't know much about SmallTalk, but given SmallTalk was the inspiration for Objective-C I wouldn't be surprised to see this there too. It's nice to give attribution, but where do we stop? Can you say you know for sure what was the real inspiration for this?I think lack of state is indeed the only difference. The multiple inheritance bit makes all the difference, so I think abstract classes are not enough. A designer who wants to define some methods in an interface is forced at design time to choose an abstract class over an interface, thus severely limiting clients.I really wonder why you're doing this. NIH. Ever heard or Scala and traits? I'm sorry, but you didn't invent this feature - giving some kind of attribution would be honest. I can imagine how this proposal goes forward. Suddenly D 2 gets almost exactly the same feature (+ contracts) as Scala has had for a long time and somehow you get all the credit in the practical (C++/D) PL community.
Feb 08 2010
On 2010-02-08 13:04:37 -0500, retard <re tard.com.invalid> said:No, I don't know the original source. Multiple inheritance is an old and widely known problem. I just meant that instead of bikeshedding here and reinventing everything from scratch, everyone interested in the topic should take a look at Scala's traits since traits basically are interfaces extended with function bodies. Scala also has a solution to the conflicting multiply inherited methods. I just mentioned Scala because it's also a C inspired object oriented language and this feature proposal is more or less 90% the same concept as traits, both syntactically and semantically.From what I can read, traits in Scala are much than adding function definitions. You can add member variables and inherit from a base class. It acts much like an interface + a mixin. It's quite nice really. <http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5> -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 08 2010
retard wrote:Mon, 08 Feb 2010 07:03:43 -0600, Andrei Alexandrescu wrote:This one really takes the cake. Do you really believe I'm in this for snatching credit? Sheesh. I know of Scala's traits. They are different from overridable methods in interfaces, which are not nearly interesting enough to bring fame and fortune to anyone. AndreiJacob Carlborg wrote:I really wonder why you're doing this. NIH. Ever heard or Scala and traits? I'm sorry, but you didn't invent this feature - giving some kind of attribution would be honest. I can imagine how this proposal goes forward. Suddenly D 2 gets almost exactly the same feature (+ contracts) as Scala has had for a long time and somehow you get all the credit in the practical (C++/D) PL community.On 2/8/10 06:37, Andrei Alexandrescu wrote:I think lack of state is indeed the only difference. The multiple inheritance bit makes all the difference, so I think abstract classes are not enough. A designer who wants to define some methods in an interface is forced at design time to choose an abstract class over an interface, thus severely limiting clients.Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI only see two differences with abstract classes: interfaces can't have instance (and class?) variables and you can inherit from multiple interfaces. Am I missing something? Is this really necessary? Isn't abstract classes enough? Does this have similar problems (or the same) as multiple inheritance?
Feb 08 2010
Mon, 08 Feb 2010 11:34:10 -0800, Andrei Alexandrescu wrote:I know of Scala's traits. They are different from overridable methods in interfaces, which are not nearly interesting enough to bring fame and fortune to anyone.I apologize for being so rude. If I read the proposal correctly, traits are its generalization: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); return result; } } vs trait Stack[T] { def push(t: T): Unit def pop: Unit def top: T // do not know how to port properties def empty: Boolean def belowTop: T { val t = top pop val result = top push(t) result } } But with these kind of features D's interfaces are getting closer and closer to traits. What's missing? The linearization system, type members, and member variables inside interfaces. OTOH Scala is lacking the contract system.
Feb 08 2010
retard wrote:Mon, 08 Feb 2010 11:34:10 -0800, Andrei Alexandrescu wrote:That's a nice surprise (what about the backlog? :o)). Just a note, to me apologizing entails I plan to not repeat whatever it is I'm apologizing for.I know of Scala's traits. They are different from overridable methods in interfaces, which are not nearly interesting enough to bring fame and fortune to anyone.I apologize for being so rude.If I read the proposal correctly, traits are its generalization: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); return result; } } vs trait Stack[T] { def push(t: T): Unit def pop: Unit def top: T // do not know how to port properties def empty: Boolean def belowTop: T { val t = top pop val result = top push(t) result } } But with these kind of features D's interfaces are getting closer and closer to traits. What's missing? The linearization system, type members, and member variables inside interfaces. OTOH Scala is lacking the contract system.Traits indeed offer more than interfaces. We're looking at sensible things to do within the time constraints we're having; traits would be a major effort, whereas methods in interfaces are just eliminating an artificial limitation. Traits are a possible addition to D3. Andrei
Feb 08 2010
Andrei Alexandrescu wrote:Traits indeed offer more than interfaces. We're looking at sensible things to do within the time constraints we're having; traits would be a major effort, whereas methods in interfaces are just eliminating an artificial limitation. Traits are a possible addition to D3.When will work on D3 be started? 6 months after your book has been published?Andrei
Feb 08 2010
grauzone wrote:Andrei Alexandrescu wrote:You may start it any time now. AndreiTraits indeed offer more than interfaces. We're looking at sensible things to do within the time constraints we're having; traits would be a major effort, whereas methods in interfaces are just eliminating an artificial limitation. Traits are a possible addition to D3.When will work on D3 be started? 6 months after your book has been published?
Feb 08 2010
retard wrote:I really wonder why you're doing this. NIH. Ever heard or Scala and traits? I'm sorry, but you didn't invent this feature - giving some kind of attribution would be honest. I can imagine how this proposal goes forward. Suddenly D 2 gets almost exactly the same feature (+ contracts) as Scala has had for a long time and somehow you get all the credit in the practical (C++/D) PL community.Member functions with bodies is what C++ has with multiple inheritance. C++ multiple inheritance has been around a lot longer than Scala. D interfaces *are* C++ multiple interface classes, but with some restrictions (like no data members, no virtual base classes, and no function bodies). They are even implemented the same way, with vtables and thunks. This is nothing new.
Feb 08 2010
On Mon, 08 Feb 2010 00:37:53 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome.You forgot to return result :) Also, it should be implemented like this to prevent a problem where a stack with a single element is cleared before an exception is thrown. T belowTop() { auto t = top; pop(); scope(exit) push(t); return top; } As another example (not sure if it's "killer"), here is a more useful default method: T popTop() { scope(success) pop(); return top; } I can see real use for "give me the top, and pop it off at the same time." Now, if we make popTop final, it's 2 virtual function calls (popTop can be inlined), but if we make it overridable, the default implementation has 3 virtual calls, but can be optimized into 1 virtual call if so desired. I guess it's a tradeoff between whether you think most implementors will prefer to use some default implementation or most will want to optimize. But in the case you expect most to optimize, wouldn't you just provide no implementation? In the case of popTop, it's attractive to say "your stack class only needs to define these few primitives," but it's generally trivial to provide a popTop implementation that is more optimized. I've seen places where interface documentation says "implement this function like this: ..." which is quite annoying. final functions solve most of these, I'm not sure if we need another way to do it, but I can't see any reason why it should be disallowed. The judgement call of whether to provide an overridable implementation and no implementation would be difficult. I don't see a default-but-overridable implementation being used often. -Steve
Feb 08 2010
Andrei Alexandrescu wrote:Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI don't understand this. How does belowTop() know how to call top()? It has the 'this' pointer, so that does have a pointer to the vtable; but since it doesn't know the inheritance hierarchy of the object which it applies to, how can it know which vtable index to use? With 'final' functions, of course there's no problem. It can be solved with thunks, of course, but I presume that's not the intention?
Feb 08 2010
Don wrote:Andrei Alexandrescu wrote:It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type. AndreiWalter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI don't understand this. How does belowTop() know how to call top()?
Feb 08 2010
On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer. A real example: interface A { int bar(); int foo() { return bar(); } } class C : A { override int bar() { return 1;} } class D : C { override int foo() { return 2;} } if you have a reference to A, when calling foo, what do you pass as the this pointer? I think the way it works is an interface call does an interface lookup to get the 'true' this pointer (this is a quick lookup since an interface pointer has the offset info at a predetermined location), so the object pointer is passed into foo. When the actual type is a D object, a D reference is expected, but when the actual type is a C object, what is expected? The compiler cannot tell what the underlying type is, so when the actual type is a C object, a C reference will be passed in. So in a "default implementation", there has to be an implicit thunk to convert the type back into an interface. Basically, the function foo as implemented in A looks like this: int foo() { A __this = cast(A)this; // do a thunk, 'this' is of type Object return __this.bar(this); // no lookup of this required, so this is the same as a standard virtual call } This severely lowers my taste for this idea. I think a thunk uses a linear lookup of the interface list at runtime to find the correct interface. A way you might be able to get rid of this problem is to compile the default implementation as if it were a function of the class that implements the interface. I could probably live with that, but this feature seems more complicated than it is worth. -SteveAndrei Alexandrescu wrote:It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI don't understand this. How does belowTop() know how to call top()?
Feb 08 2010
Steven Schveighoffer wrote:On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface. AndreiDon wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.Andrei Alexandrescu wrote:It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.Walter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiI don't understand this. How does belowTop() know how to call top()?
Feb 08 2010
On Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways. -SteveOn Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.
Feb 08 2010
Steven Schveighoffer wrote:On Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:If an object overrode the default implementation, the pointer to method belowTop will point to code that does do the adjustment. AndreiSteven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways.On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.
Feb 08 2010
On Mon, 08 Feb 2010 16:09:19 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:If I understand this correctly, calling such a "default implementation" function is different than calling a standard interface function. And each entry in such an interface for a overridden method will point to a "pre function" that adjusts the 'this' reference before jumping to the real implementation. The vtable entries of the object itself would point to a function that does not do the adjustment, correct? I think all the information is available to make this work, the only issue I see is that a function with a default implementation artificially changes the ABI for that function. Adding a default implementation therefore will make compiled objects incompatible, even with the same vtable layout. As of today, I don't see this being a problem, since you generally only build static D programs. But I can't see a huge flaw in the idea. -SteveOn Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:If an object overrode the default implementation, the pointer to method belowTop will point to code that does do the adjustment.Steven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways.On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.
Feb 08 2010
Steven Schveighoffer wrote:On Mon, 08 Feb 2010 16:09:19 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Actually that's what's happening today.Steven Schveighoffer wrote:If I understand this correctly, calling such a "default implementation" function is different than calling a standard interface function. And each entry in such an interface for a overridden method will point to a "pre function" that adjusts the 'this' reference before jumping to the real implementation.On Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:If an object overrode the default implementation, the pointer to method belowTop will point to code that does do the adjustment.Steven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways.On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.The vtable entries of the object itself would point to a function that does not do the adjustment, correct?Yes, but let's not forget that each object stores more than one vptrs.I think all the information is available to make this work, the only issue I see is that a function with a default implementation artificially changes the ABI for that function. Adding a default implementation therefore will make compiled objects incompatible, even with the same vtable layout.Not getting this, but I'll let Walter weigh in. Andrei
Feb 08 2010
On Mon, 08 Feb 2010 17:19:28 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:Yes, but I think it's happening at the call site and not inside the function itself. I will run a test... You are right, I was wrong. So this is already the way it works (good to know!): interface I { void foo(); } interface J { void foo(); } class C : I, J { int i; void foo() { i = 5;} } produces the following asm for C.foo: _D13testinterface1C3fooMFZv: push EBP mov EBP,ESP sub ESP,4 mov dword ptr 8[EAX],5 leave ret nop _TMP0: add EAX,0FFFFFFF4h jmp near ptr _D13testinterface1C3fooMFZv _TMP1: add EAX,0FFFFFFF0h jmp near ptr _D13testinterface1C3fooMFZv where _TMP0 and _TMP1 are the little pre functions that get stored in the interface vtables. I therefore don't think there are any issues, I misunderstood the way interface functions work. I didn't realize the interface function called a little pre function. I thought it was done at the call site before the call.On Mon, 08 Feb 2010 16:09:19 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Actually that's what's happening today.Steven Schveighoffer wrote:If I understand this correctly, calling such a "default implementation" function is different than calling a standard interface function. And each entry in such an interface for a overridden method will point to a "pre function" that adjusts the 'this' reference before jumping to the real implementation.On Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:If an object overrode the default implementation, the pointer to method belowTop will point to code that does do the adjustment.Steven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways.On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.Right, I just thought the different vtables contained identical references to the same functions. It makes sense that is not the case.The vtable entries of the object itself would point to a function that does not do the adjustment, correct?Yes, but let's not forget that each object stores more than one vptrs.It's my bad, I thought normal interface calls were different than this method of having a little "pre" function, but it makes sense to do it that way. Sorry for the noise. I retract my objection on these grounds :) -SteveI think all the information is available to make this work, the only issue I see is that a function with a default implementation artificially changes the ABI for that function. Adding a default implementation therefore will make compiled objects incompatible, even with the same vtable layout.Not getting this, but I'll let Walter weigh in.
Feb 08 2010
Steven Schveighoffer wrote:On Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I have a strong suspicion that it's exactly the same as multiple inheritance. I thought about this quite a bit a year ago, and initially I thought that having no data members made it OK. But it's deceptive. Virtual member functions are still a problem. I think you can only have final functions.Steven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways. -SteveOn Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.
Feb 08 2010
Don wrote:Steven Schveighoffer wrote:I think it's only data. The problem is that you end up storing multiple copies of the same interface object inside the final object. As long as the per-interface state is compiler-maintained and immutable, you should be in good shape. AndreiOn Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I have a strong suspicion that it's exactly the same as multiple inheritance. I thought about this quite a bit a year ago, and initially I thought that having no data members made it OK. But it's deceptive. Virtual member functions are still a problem. I think you can only have final functions.Steven Schveighoffer wrote:void foo(Stack!T st) { auto x = st.belowTop(); } OK, so if st's virtual function for belowTop points to the default implementation, there is no adjustment. But what if the actual object *did* override the default implementation? Does it also receive the interface pointer as 'this'? Where does the adjustment happen? What happens if you have a reference to the actual concrete object type? Do you have to thunk to the correct interface to pass in the expected interface pointer? It can't be both ways. -SteveOn Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That is done via an adjustment of the reference. In the case of an interface method, no adjustment is necessary. Inside the method, "this" has the static type of the interface and the dynamic type whichever class implements the interface.Don wrote:Actually, I think Don has a point here. A virtual function (even on an interface) is always called with the 'this' pointer, not the interface pointer.I don't understand this. How does belowTop() know how to call top()?It calls top() through the normal interface mechanism. Inside belowTop(), this has Stack!T type.
Feb 08 2010
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleWalter has now implemented final methods in interfaces and also contracts in interfaces, both of which I think are just awesome. We figured that essentially he artificially disallows interfaces from providing bodies for methods. I think that's a gratuitous limitation; the only distinguishing quality of an interface is that it has no state. Other than that, interfaces can always offer overridable functions that by default offer functionality in terms of existing interface functions. For example: interface Stack(T) { void push(T); void pop(); property ref T top(); property bool empty(); T belowTop() { auto t = top; pop(); auto result = top; push(t); } } The default implementation of belowTop does a fair amount of work. A particular implementation might just use that or override it with a more efficient implementation. Many more examples can be imagined, but I'm looking for a killer one, or perhaps a killer counterexample (e.g. when would an interface-defined method be really bad?) Your thoughts welcome. AndreiIf we're going to do this, then why not allow (biggest oxymoron of all time) concrete interfaces, i.e. interfaces that can be instantiated? This would be useful for things like the template method pattern. Example: /**Reduction implemented by template method pattern.*/ interface Reduce(T, U) { T opCall(T initialValue, U[] array) { T result = initialValue; foreach(elem; array) { result = reductionFunction(result, elem); } return result; } abstract T reductionFunction(T, U); } interface Sum(T, U) : Reduce!(T, U) { override T reductionFunction(T lhs, U rhs) { return lhs + rhs; } } An instantiation of an interface wouldn't perform any heap allocations and would just return a pointer to the relevant vtable. It would then work just like an interface inherited from a class: Calling a method dispatches based on the vtable logic. The this pointer is simply a pointer to the relevant vtable. With the this pointer in hand, the function can call other virtual functions just like a regular class.
Feb 08 2010