February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to retard | 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: > >> 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. 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/ | |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | 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:
>
>> Mon, 08 Feb 2010 07:03:43 -0600, 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.
>>
>> 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.
>
> 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?
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.
| |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to retard | 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/ | |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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.
>
>
> Andrei
I 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?
| |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to retard | retard wrote:
> Mon, 08 Feb 2010 07:03:43 -0600, Andrei Alexandrescu wrote:
>
>> Jacob Carlborg wrote:
>>> 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.
>>>>
>>>>
>>>> Andrei
>>> 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?
>> 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.
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.
Andrei
| |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | Don wrote:
> 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.
>>
>>
>> Andrei
>
> 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.
Andrei
| |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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.
| |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: > Don wrote: >> 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. >>> >>> >>> Andrei >> 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. 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. -Steve | |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Steven Schveighoffer wrote:
> On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Don wrote:
>>> 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.
>>>>
>>>>
>>>> Andrei
>>> 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.
>
> 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.
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.
Andrei
| |||
February 08, 2010 Re: "The last feature": overridable methods in interfaces | ||||
|---|---|---|---|---|
| ||||
Posted in reply to retard | retard wrote: > 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. 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. > 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 | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply