www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Interface Support: Return Types

reply Derek Parnell <derek psych.ward> writes:
My experience with Interfaces is zero, except for dabbling with the D
offering. My understanding of what interfaces are is that they are a
mechanism for defining a set of methods that must be implemented by a
class. About 30 minutes ago I was reading the DSource forum in which
'teqdruid' posted an simple example that shocked me into realizing that
there is at least one deficiency in the current Interface syntax.

Given the interfaces ...

 interface MutableList
 {
   MutableList opSlice(int a, int b);
 }

 interface Reproduce
 {
   Reproduce dup();
 }

and then a class based on this interface ...

 class MyList : MutableList, Reproduce
 {
   MutableList opSlice(int a, int b)
   {
      . . .
   }
   Reproduce dup()
   {
      . . .
   }
   . . . 
 }

This means that the MyList class must implement the interfaces' methods,
namely it must define a function called opSlice() that returns a
'MutableList', and function called dup() that must return a 'Reproduce'.
However, I would rather have it return a MyList class
instead, because as it now stands, to use such a class I must code ...

    MyList a = new MyList(xx);
    MyList b;
    MyList c;

    b = cast(MyList)a[2 .. 3];
    c = cast(MyList)a.dup;

The way I see it, an Interface is a generic way of defining a mandatory set
of member functions. The problem is that when defining the Interface, one
cannot know ahead of time which classes are going to be based on it, and
thus you cannot specify the required return type for functions defined in
the interface that return an instance of the class being defined.

If we could define interfaces thus (or similar syntax) ...

 interface MutableList
 {
   this opSlice(int a, int b);
 }
 interface Reproduce
 {
   this dup();
 }

then you can code the class definition as ...

 class MyList : MutableList, Reproduce
 {
   MyList opSlice(int a, int b)
   {
      . . .
   }
   MyList dup()
   {
      . . .
   }   
   . . . 
 }

and the compiler can make the appropriate substitution of 'MyList' for
'this' in the interface definition and still enforce strict type-safety.
Then I can do away with the redundant' cast' phrases when using the class,
thus making the code more readable and cleaner. And of course, making the
Interfaces a lot more generic in that they can be used to build any class
definition as required by the class designers.

By the way, the use of returning 'Object' in the interfaces still means you
need casts plus you lose strict type-safety.
-- 
Derek
Melbourne, Australia
31/05/2005 10:04:57 AM

-- 
Derek
Melbourne, Australia
31/05/2005 10:34:32 AM
May 30 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <bjopczpwluat$.z1g5tgrbc43m$.dlg 40tude.net>, Derek Parnell says...
My experience with Interfaces is zero, except for dabbling with the D
offering. My understanding of what interfaces are is that they are a
mechanism for defining a set of methods that must be implemented by a
class. About 30 minutes ago I was reading the DSource forum in which
'teqdruid' posted an simple example that shocked me into realizing that
there is at least one deficiency in the current Interface syntax.
Sounds like you want interfaces to support covariant return types. I wasn't aware that they didn't, so I agree. Sean
May 30 2005
parent Derek Parnell <derek psych.ward> writes:
On Tue, 31 May 2005 01:19:16 +0000 (UTC), Sean Kelly wrote:

 In article <bjopczpwluat$.z1g5tgrbc43m$.dlg 40tude.net>, Derek Parnell says...
My experience with Interfaces is zero, except for dabbling with the D
offering. My understanding of what interfaces are is that they are a
mechanism for defining a set of methods that must be implemented by a
class. About 30 minutes ago I was reading the DSource forum in which
'teqdruid' posted an simple example that shocked me into realizing that
there is at least one deficiency in the current Interface syntax.
Sounds like you want interfaces to support covariant return types. I wasn't aware that they didn't, so I agree.
As I say, I have no real experience with Interfaces, so if 'covariant return types' is the official jargonese for the concept then so be it ;-) I tried to describe the effect in common parlance used within the D language. I just googled the term and got a good description of it from http://c2.com/cgi/wiki?CovariantReturnTypes -- Derek Melbourne, Australia 31/05/2005 11:23:47 AM
May 30 2005
prev sibling next sibling parent reply Mike Parker <aldacron71 yahoo.com> writes:
Derek Parnell wrote:

 This means that the MyList class must implement the interfaces' methods,
 namely it must define a function called opSlice() that returns a
 'MutableList', and function called dup() that must return a 'Reproduce'.
 However, I would rather have it return a MyList class
 instead, because as it now stands, to use such a class I must code ...
But then doesn't that defeat the purpose of using the interface in the first place? Interfaces should be used when a standard interface is needed. It's a promise to the client that no matter what the underlying implementation, you are guaranteed that these methods will exist and that they will return these types. So imagine this feature you describe is implemented, and I write my code to rely on the fact that the MutableList being returned is actually a MyList. What happens if the underlying implementation changes and returns a SomeoneElsesList instead? I can't cast a MyList to a SomeoneElsesList, so my code is now broken. In general, when programming with interfaces, you should always program *to* the interface. That guarantees that your code will not break if the underlying implementation changes. D's casting mechanism makes it simple enough to handle specific implementations conditionally so that you can do this if you get a MyList, that for SomoneElsesList, and something else for any other MutableList. Allowing an interface implementation to break its interface's contract by varying return types just isn't a good thing, IMO.
May 30 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 31 May 2005 10:29:17 +0900, Mike Parker wrote:

 Derek Parnell wrote:
 
 This means that the MyList class must implement the interfaces' methods,
 namely it must define a function called opSlice() that returns a
 'MutableList', and function called dup() that must return a 'Reproduce'.
 However, I would rather have it return a MyList class
 instead, because as it now stands, to use such a class I must code ...
But then doesn't that defeat the purpose of using the interface in the first place?
I'm new at this so please bear with me.
Interfaces should be used when a standard interface is 
 needed. 
Yep, that makes sense.
It's a promise to the client that no matter what the underlying 
 implementation, you are guaranteed that these methods will exist and 
 that they will return these types.
Can I reword this to help me clarify your statement? It's a promise to the code that uses the class, which was defined based on the interface ('the client'), that no matter how the class actually implements the routines named in the interface ('the underlying implementation'), that these routines ('methods') will exist and that they will return the types specified by the interface definition. Yep, that's how I see it too.
 So imagine this feature you describe is implemented, and I write my code 
 to rely on the fact that the MutableList being returned is actually a 
 MyList. What happens if the underlying implementation changes and 
 returns a SomeoneElsesList instead? I can't cast a MyList to a 
 SomeoneElsesList, so my code is now broken.
Are you suggesting a scenario in which the MyList class changes the implementation of its 'opSlice' to return a SomeoneElsesList instead of a MyList class? In my proposed syntax, doing that would cause a compiler error because the Interface would have been defined to say that 'opSlice' must return an instance of the class that is based upon the interface. And as that would be MyList then returning a SomeoneElsesList would be against that Interface's requirements. The problem as I see it is that the current syntax mans that you must 'hard code' the return types in the interface definition. When there are sometimes that you wish it could be defined in terms of a 'symbolic' type rather than a real type. The 'symbolic' type would be resolved at compile time when the class using the interfaces is being defined.
 In general, when programming with interfaces, you should always program 
 *to* the interface. That guarantees that your code will not break if the 
 underlying implementation changes. 
Yes, but when a coder is looking at the documentation of a class, let's say a MyList, and sees that opSlice returns something other than the class itself, it is counter-intuitive. It would be like char[] a; char[] b; b = a[1..3]; failing because the slice operation does not return a char[]. Although it may be documented, it is not obvious. "And what is a 'MutableList' anyways?", the coder exclaims ;-)
 D's casting mechanism makes it simple 
 enough to handle specific implementations conditionally so that you can 
 do this if you get a MyList, that for SomoneElsesList, and something 
 else for any other MutableList.
In my view, the cast concept is a way to work around the type-safeness of the language. It is a hack. Unfortunately one which we are forced to use far to often for no good reason.
 Allowing an interface implementation to break its interface's contract 
 by varying return types just isn't a good thing, IMO.
Agreed. But that is not exactly what I'm saying. I'm not saying its okay for a class to return an 'int' when the interface says it should return a 'real'. I am saying, it would be useful to be able to specify an interface in such a way that the return type is resolved at the point in time that the class using the interface is defined, rather than at the time the interface is defined. It is analogous to templates, mixins or the dreaded macro, in that the actual code compiled is deferred. -- Derek Melbourne, Australia 31/05/2005 11:31:55 AM
May 30 2005
next sibling parent kris <fu bar.org> writes:
If I may add something:

An interface is a type of broker between two other parties; nothing 
more. If both parties respect the contract implied by the broker, then 
something akin to magic can happen ~ otherwise, all bets are off.

As a broker, the Interface must absolve itself from all implementation 
details. That typically includes concrete types of any kind. Lets call 
such an animal a "pure" interface. Non-pure interfaces are feasible for 
many things, but you should really ask if an abstract class is a better 
approach for such instances.

Then there's the "multiple inheritance replacement" thing: it would be 
convenient to support covariant return types within Interfaces for 
non-pure usage of this nature, but D does not do this ~ it sticks to the 
pure implementation instead.

You can emulate covariant return types through inherited interface 
returns instead ~ but it can be a pain, for a number of reasons.



Derek Parnell wrote:
 On Tue, 31 May 2005 10:29:17 +0900, Mike Parker wrote:
 
 
Derek Parnell wrote:


This means that the MyList class must implement the interfaces' methods,
namely it must define a function called opSlice() that returns a
'MutableList', and function called dup() that must return a 'Reproduce'.
However, I would rather have it return a MyList class
instead, because as it now stands, to use such a class I must code ...
But then doesn't that defeat the purpose of using the interface in the first place?
I'm new at this so please bear with me.
Interfaces should be used when a standard interface is 
needed. 
Yep, that makes sense.
It's a promise to the client that no matter what the underlying 
implementation, you are guaranteed that these methods will exist and 
that they will return these types.
Can I reword this to help me clarify your statement? It's a promise to the code that uses the class, which was defined based on the interface ('the client'), that no matter how the class actually implements the routines named in the interface ('the underlying implementation'), that these routines ('methods') will exist and that they will return the types specified by the interface definition. Yep, that's how I see it too.
So imagine this feature you describe is implemented, and I write my code 
to rely on the fact that the MutableList being returned is actually a 
MyList. What happens if the underlying implementation changes and 
returns a SomeoneElsesList instead? I can't cast a MyList to a 
SomeoneElsesList, so my code is now broken.
Are you suggesting a scenario in which the MyList class changes the implementation of its 'opSlice' to return a SomeoneElsesList instead of a MyList class? In my proposed syntax, doing that would cause a compiler error because the Interface would have been defined to say that 'opSlice' must return an instance of the class that is based upon the interface. And as that would be MyList then returning a SomeoneElsesList would be against that Interface's requirements. The problem as I see it is that the current syntax mans that you must 'hard code' the return types in the interface definition. When there are sometimes that you wish it could be defined in terms of a 'symbolic' type rather than a real type. The 'symbolic' type would be resolved at compile time when the class using the interfaces is being defined.
In general, when programming with interfaces, you should always program 
*to* the interface. That guarantees that your code will not break if the 
underlying implementation changes. 
Yes, but when a coder is looking at the documentation of a class, let's say a MyList, and sees that opSlice returns something other than the class itself, it is counter-intuitive. It would be like char[] a; char[] b; b = a[1..3]; failing because the slice operation does not return a char[]. Although it may be documented, it is not obvious. "And what is a 'MutableList' anyways?", the coder exclaims ;-)
D's casting mechanism makes it simple 
enough to handle specific implementations conditionally so that you can 
do this if you get a MyList, that for SomoneElsesList, and something 
else for any other MutableList.
In my view, the cast concept is a way to work around the type-safeness of the language. It is a hack. Unfortunately one which we are forced to use far to often for no good reason.
Allowing an interface implementation to break its interface's contract 
by varying return types just isn't a good thing, IMO.
Agreed. But that is not exactly what I'm saying. I'm not saying its okay for a class to return an 'int' when the interface says it should return a 'real'. I am saying, it would be useful to be able to specify an interface in such a way that the return type is resolved at the point in time that the class using the interface is defined, rather than at the time the interface is defined. It is analogous to templates, mixins or the dreaded macro, in that the actual code compiled is deferred.
May 30 2005
prev sibling parent reply Mike Parker <aldacron71 yahoo.com> writes:
Derek Parnell wrote:
 On Tue, 31 May 2005 10:29:17 +0900, Mike Parker wrote:
 Are you suggesting a scenario in which the MyList class changes the
 implementation of its 'opSlice' to return a SomeoneElsesList instead of a
 MyList class? In my proposed syntax, doing that would cause a compiler
 error because the Interface would have been defined to say that 'opSlice'
 must return an instance of the class that is based upon the interface. And
 as that would be MyList then returning a SomeoneElsesList would be against
 that Interface's requirements.
And this is what I don't understand. Constidering that MutableList already dictates that opSlice must return a MutableList object, what is the befefit of allowing a MutableList implementation to narrow that scope from MutableList to MyList? The method in question should be able to return any instance of a MutableList implementation, because that's what the interface says it should return. If I'm calling that method from another class, I (generally) don't care if I'm getting what type of MutableList I'm getting.
 The problem as I see it is that the current syntax mans that you must 
 'hard code' the return types in the interface definition.
That's what an interface is for, isn't it? Call this method, and you will have this type returned.
 When there are sometimes that you wish it could be defined in terms 
of > a 'symbolic' type rather than a real type. The 'symbolic' type would
 be resolved at compile time when the class using the interfaces is
 being defined.
This is the part I'm not getting.
 Yes, but when a coder is looking at the documentation of a class,
 let's say
 a MyList, and sees that opSlice returns something other than the class
 itself, it is counter-intuitive. It would be like
   char[] a;
   char[] b;
   b = a[1..3];

 failing because the slice operation does not return a char[]. 
Although > it may be documented, it is not obvious. "And what is a 'MutableList'
 anyways?", the coder exclaims  ;-)
Okay, this is why opSlice is a bad example. Operator overloads are already part of the language spec, and have no business being part of an interface definition in the first place (unless you want to enforce a specific behavior for special cases). interface Foo { void amethod(); } class Bar : Foo { void amethod() {} } class BarToo : Foo { void amethod() {} } interface Baz { Foo getFoo(); } class BazImpl : Baz { Foo getFoo(); } Baz says that everytime I call Foo, I will get a Foo. Maybe I'll get a Bar or a BarToo, but it will always be a Foo. They syntax you propose would allow this: class BazImplToo : Baz { Bar getFoo() {} } This means that BazImplToo no longer strictly adheres to the Baz interface, because it can't return any type of Foo, but only Foos which are instances of, or extended instances of, Bar. This is how I'm looking at it. What I'm no getting is what benefit this brings.
May 30 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 31 May 2005 12:50:51 +0900, Mike Parker wrote:

 Derek Parnell wrote:
 On Tue, 31 May 2005 10:29:17 +0900, Mike Parker wrote:
 Are you suggesting a scenario in which the MyList class changes the
 implementation of its 'opSlice' to return a SomeoneElsesList instead of a
 MyList class? In my proposed syntax, doing that would cause a compiler
 error because the Interface would have been defined to say that 'opSlice'
 must return an instance of the class that is based upon the interface. And
 as that would be MyList then returning a SomeoneElsesList would be against
 that Interface's requirements.
And this is what I don't understand. Constidering that MutableList already dictates that opSlice must return a MutableList object,
Stop there! What I'm proposing is that MutableList dictates that opSlice must return an instance of *whatever* class that is using MutableList as one of its building blocks. For instance: interface ML { this meth_one(int a, int b); } class BaseList { . . . } class ListOne: BaseList, ML { ListOne meth_one(int a, int b) { ListOne x = new ListOne; . . . return x; } } class ListTwo: ML { ListTwo meth_one(int a, int b) { ListTwo x = new ListTwo; . . . return x; } } By using the syntax "this funcname()" inside the interface definition, I'm trying to tell the compiler that the return type is not known yet and will only be known when this interface is used on a class definition, at which time the compiler will substitute the word 'this' with the name of the class being defined. The contract ('interface promise') is still being met. The only thing is that the specific return type is not known at the time the interface was designed. It allows much more generic interfaces to be designed. It says, "when using this interface to define a class, you must implement a member function that accepts these parameters are returns an instance of the class that you are defining."
 what is 
 the befefit of allowing a MutableList implementation to narrow that 
 scope from MutableList to MyList?
Narrow? How is it narrowing it? I would have thought I was expanding it. Are you thinking that I mean that when the class is being defined, that the interface is then 'locked' into RAM or such.
 The method in question should be able 
 to return any instance of a MutableList implementation, because that's 
 what the interface says it should return. 
Currently, yes. But what-if you could tell the compile to be more flexible.
If I'm calling that method 
 from another class, I (generally) don't care if I'm getting what type of 
 MutableList I'm getting.
Huh? There is only one type of MutableList. Are you saying that any class that uses MutableList as a basis becomes a type of MutableList? How does that work with multiple interfaces being used on a single class definition?
  > The problem as I see it is that the current syntax mans that you must 
  > 'hard code' the return types in the interface definition.
 
 That's what an interface is for, isn't it? Call this method, and you 
 will have this type returned.
Yes.
  > When there are sometimes that you wish it could be defined in terms 
 of > a 'symbolic' type rather than a real type. The 'symbolic' type would
  > be resolved at compile time when the class using the interfaces is
  > being defined.
 
 This is the part I'm not getting.
Hopefully I've described more fully now.
  > Yes, but when a coder is looking at the documentation of a class,
  > let's say
  > a MyList, and sees that opSlice returns something other than the class
  > itself, it is counter-intuitive. It would be like
 
  >   char[] a;
  >   char[] b;
 
  >   b = a[1..3];
  >
  > failing because the slice operation does not return a char[]. 
 Although > it may be documented, it is not obvious. "And what is a 
 'MutableList'
  > anyways?", the coder exclaims  ;-)
 
 Okay, this is why opSlice is a bad example. Operator overloads are 
 already part of the language spec, and have no business being part of an 
 interface definition in the first place (unless you want to enforce a 
 specific behavior for special cases).
 
 interface Foo
 {
     void amethod();
 }
 
 class Bar : Foo
 {
     void amethod() {}
 }
 
 class BarToo : Foo
 {
     void amethod() {}
 }
 
 interface Baz
 {
     Foo getFoo();
 }
 
 class BazImpl : Baz
 {
     Foo getFoo();
 }
 
 Baz says that everytime I call Foo, I will get a Foo. Maybe I'll get a 
 Bar or a BarToo, but it will always be a Foo.
This is the part that I'm not getting. Given that an interface is a list of methods that must be implemented, how can a function return an interface? Are you saying that the getFoo() function is returning a list of method signatures? Why would I want that? It seems that you are suggesting that an interfaces is really some sort of light-weight class. If the classes Bar and BarToo also implemented other methods and data,, but different from each other, what would getFoo() return? Is it just an object that allows you to call only the Foo methods implemented in both Bar and BarToo, but not access the other methods or data in them?
 They syntax you propose 
 would allow this:
 
 class BazImplToo : Baz
 {
     Bar getFoo() {}
 }
No, it will not. Because Baz says it must return a Foo, returning a Bar is wrong. And even if Baz said it can return a 'this thingy', your example would still be wrong because a Bar is not a BazImplToo.
 This means that BazImplToo no longer strictly adheres to the Baz 
 interface, because it can't return any type of Foo, but only Foos which 
 are instances of, or extended instances of, Bar. This is how I'm looking 
 at it. What I'm no getting is what benefit this brings.
I'll try another example: interface Foo { this amethod(); } interface Baz { this bmethod(); int cmethod(); } class Bar : Foo { Bar amethod() { . . .} private real x; } class BarToo : Foo, Baz { BarToo amethod() { . . .} BarToo bmethod() { . . .} int cmethod(){ . . . } } class BazImpl : Baz { BarImpl bmethod() { . . .} int cmethod(){ . . . } } -- Derek Melbourne, Australia 31/05/2005 1:55:36 PM
May 30 2005
parent reply kris <fu bar.org> writes:
Derek Parnell wrote:
<snip>
If I'm calling that method 
from another class, I (generally) don't care if I'm getting what type of 
MutableList I'm getting.
Huh? There is only one type of MutableList. Are you saying that any class that uses MutableList as a basis becomes a type of MutableList? How does that work with multiple interfaces being used on a single class definition?
Part of the power within Interfaces comes from their agnostic properties: if there is no concrete implementation referenced anywhere within, then /anybody/ can implement the interface and magically be compatible will all clients of said interface. That is; If IMutableList is an interface, each of you, John, and I can provide a completely independent implementation, yet all clients of IMutableList just don't care which one is "plugged in" at any given time. There are times when the client will want to know, but that's perhaps a different issue. You'll often find such things returned via the so-called Factory Pattern. This is why interfaces typically reference only other Interfaces (in return values and/or arguments), or define enums and other simple attributes. They were intended to be a pure abstraction of a contract. That doesn't mean some interesting mutations can't be proposed, but I think it's where some confusion can arise.
  
 
 The problem as I see it is that the current syntax mans that you must 
 'hard code' the return types in the interface definition.
That's what an interface is for, isn't it? Call this method, and you will have this type returned.
The traditional Interface would return another interface instead.
May 30 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 30 May 2005 21:55:16 -0700, kris wrote:

 Derek Parnell wrote:
 <snip>
If I'm calling that method 
from another class, I (generally) don't care if I'm getting what type of 
MutableList I'm getting.
Huh? There is only one type of MutableList. Are you saying that any class that uses MutableList as a basis becomes a type of MutableList? How does that work with multiple interfaces being used on a single class definition?
As I say, I *really* am new to all of this Interface stuff. The stuff you wrote below may as well been written in (digital?) Martian for the amount of it I know I really understood ;-)
 Part of the power within Interfaces comes from their agnostic 
 properties: 
'agnostic properties' = defines signatures (name, and return and input parameters) and doesn't care who or how they are implemented?
 if there is no concrete implementation 
'concrete implementation' = implementation code that is compilable?
 referenced anywhere within, 
Is this saying "if the code that defines an interface does not, itself, reference any actual implementation code"? What do you mean by 'reference'? Do you mean 'contains'? Or what???
then /anybody/ can implement the interface and magically be 
 compatible will all clients of said interface. That is; If IMutableList 
 is an interface, each of you, John, and I can provide a completely 
 independent implementation, yet all clients of IMutableList just don't 
 care which one is "plugged in" at any given time.
Is a "client of IMutableList" any class that inherits IMutable? And does this mean that given the code below ... interface iOne { double amethod(); } class Circle: iOne { double amethod() { return (radius * 2 * PI) / 360.00L ; } real bmethod() { ... } } class BattleTank: iOne { double amethod() { return RemainingAmmo / FireRate; } byte[] cmethod() { ... } } class HumanHeart: iOne { double amethod() { return Ventricle.Capacity + Atrium.Capacity; } long* dmethod() { ... } } that somehow the classes Circle, BattleTank and HumanHeart are related in so far as I can use them interchangeably at times? And what do you mean by "plugged in". Is this a runtime or a compile time operation?
 There are times when 
 the client will want to know, but that's perhaps a different issue. 
Has the meaning of "client" changed here? A what is it that the client might want to know?
 You'll often find such things returned via the so-called Factory Pattern.
What things? Interfaces? Class instances?
 This is why interfaces typically reference only other Interfaces (in 
 return values and/or arguments), or define enums and other simple 
 attributes. 
Are you saying that the methods defined in an interface definition typically only name other interfaces as data types in the return value and function arguments? Then can they specify functions that can be comnpiled? Surely, somewhere along the way a method in an interface must use real data types?
 They were intended to be a pure abstraction of a contract.
Yes, this is my understanding of them too. Nothing concrete. *JUST* a list of function signatures that is used by the compiler to ensure that classes that use the interface have all the interface's methods implemented. My assumption is that there is never any object code that is generated by an interface definition - it is just a device used by the compiler and not the linker.
 That doesn't mean some interesting mutations can't be proposed, but I 
 think it's where some confusion can arise.
Not really. I'm overly confused as it is ;-)
  
 
 The problem as I see it is that the current syntax mans that you must 
 'hard code' the return types in the interface definition.
That's what an interface is for, isn't it? Call this method, and you will have this type returned.
The traditional Interface would return another interface instead.
What is meant (i.e. Show me the code) by an interface *returning* another interface? How can something that is never instantiated execute any code to return anything? Or does this terminology ('return another interface') refer to some action by the compiler and not a run time action? -- Derek Melbourne, Australia 31/05/2005 2:57:28 PM
May 30 2005
parent reply kris <fu bar.org> writes:
Derek Parnell wrote:
 As I say, I *really* am new to all of this Interface stuff. The stuff you
 wrote below may as well been written in (digital?) Martian for the amount
 of it I know I really understood ;-)
Funny!
Part of the power within Interfaces comes from their agnostic 
properties: 
'agnostic properties' = defines signatures (name, and return and input parameters) and doesn't care who or how they are implemented?
Right. If I understand you correctly :)
if there is no concrete implementation 
'concrete implementation' = implementation code that is compilable?
Yeah; the actual implementation of an Interface is closely related to the implementation of abstract methods defined in a superclass ~ both are 'concrete' rather than 'abstract'. It is only said implementation that produces linkable code.
referenced anywhere within, 
Is this saying "if the code that defines an interface does not, itself, reference any actual implementation code"? What do you mean by 'reference'? Do you mean 'contains'? Or what???
Aye: "if the /declaration/ of an Interface does not ..." ~ there's no code in an Interface itself. By reference, I mean the Interface module does not import any module declaring a 'concrete', linkable, anything. It may very well import other Interfaces. Repeat ad nauseum <g>
then /anybody/ can implement the interface and magically be 
compatible will all clients of said interface. That is; If IMutableList 
is an interface, each of you, John, and I can provide a completely 
independent implementation, yet all clients of IMutableList just don't 
care which one is "plugged in" at any given time.
Is a "client of IMutableList" any class that inherits IMutable?
No. Or not really. The client of an Interface is usually a consumer/user of it, like someone buying something in a store. A class providing a concrete, linkable version of some Interface is said to "implement" the interface. If Walter were to define/declare an Interface describing a String class (*cough*), and you were to write an implementing class then I, as a consumer/user, could instantiate the interface via your concrete implementation. Further, John could write an alternate concrete implementation, and I could use that instead, without changing my 'client' code. That is, If I stick to using the Interface only, then I can switch between one or the other. For such simple usage, one could use an abstract base class instead. Since you mentioned the use of inheritance, it's worth noting that each Interface can inherit from others; multiple others if appropriate.
 And does this mean that given the code below ...
 
  interface iOne
  {
      double amethod();
  }
 
  class Circle: iOne
  {
      double amethod() { return (radius * 2 * PI) / 360.00L ; }
      real bmethod() { ... }
  }
 
  class BattleTank: iOne
  {
      double amethod() { return RemainingAmmo / FireRate; }
      byte[] cmethod() { ... }
  }
 
  class HumanHeart: iOne
  {
      double amethod() { return Ventricle.Capacity + Atrium.Capacity; }
      long* dmethod() { ... }
  }
  
 that somehow the classes Circle, BattleTank and HumanHeart are related in
 so far as I can use them interchangeably at times?
Yes. The Interface is just a contract ~ if various implementations attach completely different semantics to that Interface, that's a problem <g>. Oftentimes, an Interface is used as a means to discuss details of how two parties will collaborate ~ the mechanics are enforced by the Interface methods, but the semantics are agreed upon in other ways; usually heavily documented in the Interface module. An important point (I think) is this: an Interface is a means of /decoupling/ two independent entities, such that they no longer contain explicit ties to one another. Again, one can use an abstract base class for simple cases ~ Interfaces provide the extra 'decoupling' horsepower when needed, within a singly-rooted hierarchy.
 
 And what do you mean by "plugged in". Is this a runtime or a compile time
 operation?
 
It can be both ~ largely depends upon language capabilities. One key aspect of 'pluggable' systems is that a client should not know anything more than what the contract exposes. In other words, anything that /changes/ across different implementations should be abstracted via the Interface. The same is true for an abstract base-class. This is part and parcel of the decoupling aspect.
 
There are times when 
the client will want to know, but that's perhaps a different issue. 
Has the meaning of "client" changed here? A what is it that the client might want to know?
Some clients break the contract when they want to use specific capabilities of certain concrete implementations. They do this by casting the Interface to a known, concrete implementation, and using that instead. This is bogus, but it does happen. All decooupling efforts are thus borked. The resolution is to refactor the interface, or lay down some smack upon the client.
You'll often find such things returned via the so-called Factory Pattern.
What things? Interfaces? Class instances?
Factories return concrete class instances; but typically do so by returning an Interface. Specifically, a class instance that implements the appropriate interface: The factory is usually consider a producer in such cases; it hides how the Interface is implemented by encapsulating the concrete instance within itself. The client/consumer doesn't know, or care, from whence the implementation cometh from.
This is why interfaces typically reference only other Interfaces (in 
return values and/or arguments), or define enums and other simple 
attributes. 
Are you saying that the methods defined in an interface definition typically only name other interfaces as data types in the return value and function arguments?
Usually, yes. This makes them agnostic of any particular implementation. It's not a hard requirement, but it's necessary where "fully decoupled" is desirable.
 Then can they specify functions that can be comnpiled?
 Surely, somewhere along the way a method in an interface must use 
real > data
 types?
Traditional Interfaces are contract declarations only. No code is specified within them. That occurs within Concrete implementations of the Interface.
They were intended to be a pure abstraction of a contract.
Yes, this is my understanding of them too. Nothing concrete. *JUST* a list of function signatures that is used by the compiler to ensure that classes that use the interface have all the interface's methods implemented. My assumption is that there is never any object code that is generated by an interface definition - it is just a device used by the compiler and not the linker.
Aye. In D, I believe they are just like a list of delegate pointers.
That doesn't mean some interesting mutations can't be proposed, but I 
think it's where some confusion can arise.
Not really. I'm overly confused as it is ;-)
 


The problem as I see it is that the current syntax mans that you must 
'hard code' the return types in the interface definition.
That's what an interface is for, isn't it? Call this method, and you will have this type returned.
The traditional Interface would return another interface instead.
What is meant (i.e. Show me the code) by an interface *returning* another interface? How can something that is never instantiated execute any code to return anything? Or does this terminology ('return another interface') refer to some action by the compiler and not a run time action?
Note the declaration of IVehicle. It is independent of any concrete Transmission. As would be any client of IVehicle. Though I'm not sure what I'd do with a concrete transmission; or a concrete bus, for that matter :) BTW; these examples are somewhat trivialized, and don't even touch upon multiple Interface implementations or Interface inheritance. I'm sure you realize that.
May 31 2005
next sibling parent Derek Parnell <derek psych.ward> writes:
On Tue, 31 May 2005 00:51:21 -0700, kris wrote:

[a whole lot of good things about Interfaces that I'm still digesting.]

Things are clearer now but I still need to get my head around this better. 

More research is required...

-- 
Derek Parnell
Melbourne, Australia
1/06/2005 2:03:31 AM
May 31 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"kris" <fu bar.org> wrote in message news:d7h4lh$12nu$1 digitaldaemon.com...
 Yes, this is my understanding of them too. Nothing concrete. *JUST* a
list
 of function signatures that is used by the compiler to ensure that
classes
 that use the interface have all the interface's methods implemented. My
 assumption is that there is never any object code that is generated by
an
 interface definition - it is just a device used by the compiler and not
the
 linker.
Aye. In D, I believe they are just like a list of delegate pointers.
No, in D, an interface is a pointer to a vtbl[]. Each interface implemented by a class gets a vptr allocated in the class instance, and that vptr points to a vtbl[] for the functions that implement it. Casting a class to an interface means adding an offset to the 'this' pointer to point to the vptr member for that interface. Casting from an interface back to the class means subtracting that offset. The subtract is a little tricky since the pointer doesn't know where it came from, so the first entry in the interface's vtbl[] is an instance of the class Interface with the necessary offset. The cast is handled by the library function _d_interface_cast(). So, an interface "instantiation" is a physical pointer that can get copied, passed as a function argument, etc. The problem with interface covariance with classes is that that pointer is not the same as the 'this' pointer to a class. There are ways to deal with this, such as putting out special vtbl[]s with 'this' adjustor thunks in them, but D doesn't do that now and since it's a complex implementation problem, it won't for now. Covariance for class inheritance works because the 'this' for the base class is exactly the same as the 'this' for a derived class.
May 31 2005
next sibling parent Sean Kelly <sean f4.ca> writes:
In article <d7j9s9$fq8$1 digitaldaemon.com>, Walter says...
The problem with interface covariance with classes is that that pointer is
not the same as the 'this' pointer to a class. There are ways to deal with
this, such as putting out special vtbl[]s with 'this' adjustor thunks in
them, but D doesn't do that now and since it's a complex implementation
problem, it won't for now.
Sounds reasonable. I kind of see interface implementation as a contract anyway, so I'd accept the argument that return type is part of that contract. Sean
May 31 2005
prev sibling parent reply Matthias Becker <Matthias_member pathlink.com> writes:
in D, an interface is a pointer to a vtbl[]. Each interface implemented
by a class gets a vptr allocated in the class instance, and that vptr points
to a vtbl[] for the functions that implement it.
Such a vtbl[] coud be created at runtime as well, right? So perhaps there could be a new language-construct (I call it protocoll for now) which basically behaes like an interface, but doesn't need to be explicitly implemented: protocol Foo { void method (); } class Bar { void method () {...} } void function (Foo foo) {...} void main () { function (new Bar()); // OK } Protocolls might be a bit more expensive than interfaces as the vtbl[] has to be generated at runtime, but they are more flexible as well. E.g. you can write a protocol that has a subset of some classes you haven't written and this way allow to use these classes polymorphically in your own framework.
Jun 01 2005
next sibling parent Sean Kelly <sean f4.ca> writes:
In article <d7k1b0$15md$1 digitaldaemon.com>, Matthias Becker says...
in D, an interface is a pointer to a vtbl[]. Each interface implemented
by a class gets a vptr allocated in the class instance, and that vptr points
to a vtbl[] for the functions that implement it.
Such a vtbl[] coud be created at runtime as well, right? So perhaps there could be a new language-construct (I call it protocoll for now) which basically behaes like an interface, but doesn't need to be explicitly implemented: protocol Foo { void method (); } class Bar { void method () {...} } void function (Foo foo) {...} void main () { function (new Bar()); // OK } Protocolls might be a bit more expensive than interfaces as the vtbl[] has to be generated at runtime, but they are more flexible as well. E.g. you can write a protocol that has a subset of some classes you haven't written and this way allow to use these classes polymorphically in your own framework.
Cool idea, but this scares me a bit--it allows an object to impersonate something it was never intended to impersonate. What if Bar.method has a function that has nothing to do with what Foo.method is supposed to do? Sean
Jun 01 2005
prev sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
I guess you'll find
this idea is close to yours:
http://www.heron-language.com/interfaces.html
Chapter 'Unintrusive Retroactive Polymorphism'
The idea is just perfect, imho.

Andrew.


"Matthias Becker" <Matthias_member pathlink.com> wrote in message 
news:d7k1b0$15md$1 digitaldaemon.com...
in D, an interface is a pointer to a vtbl[]. Each interface implemented
by a class gets a vptr allocated in the class instance, and that vptr 
points
to a vtbl[] for the functions that implement it.
Such a vtbl[] coud be created at runtime as well, right? So perhaps there could be a new language-construct (I call it protocoll for now) which basically behaes like an interface, but doesn't need to be explicitly implemented: protocol Foo { void method (); } class Bar { void method () {...} } void function (Foo foo) {...} void main () { function (new Bar()); // OK } Protocolls might be a bit more expensive than interfaces as the vtbl[] has to be generated at runtime, but they are more flexible as well. E.g. you can write a protocol that has a subset of some classes you haven't written and this way allow to use these classes polymorphically in your own framework.
Jun 04 2005
next sibling parent Ben Hinkle <Ben_member pathlink.com> writes:
In article <d7t04k$5se$1 digitaldaemon.com>, Andrew Fedoniouk says...
I guess you'll find
this idea is close to yours:
http://www.heron-language.com/interfaces.html
Chapter 'Unintrusive Retroactive Polymorphism'
The idea is just perfect, imho.

Andrew.
I don't know much about Objective-C but I think it also has a concept roughly like that called "informal protocols" (a protocol in Objective-C is like an interface in D). It would be an interesting thought experiment to take the object model of Objective-C and graft it onto the non-object-model of D and presto Objective-D. Scary but fun to think about. :-)
"Matthias Becker" <Matthias_member pathlink.com> wrote in message 
news:d7k1b0$15md$1 digitaldaemon.com...
in D, an interface is a pointer to a vtbl[]. Each interface implemented
by a class gets a vptr allocated in the class instance, and that vptr 
points
to a vtbl[] for the functions that implement it.
Such a vtbl[] coud be created at runtime as well, right? So perhaps there could be a new language-construct (I call it protocoll for now) which basically behaes like an interface, but doesn't need to be explicitly implemented: protocol Foo { void method (); } class Bar { void method () {...} } void function (Foo foo) {...} void main () { function (new Bar()); // OK } Protocolls might be a bit more expensive than interfaces as the vtbl[] has to be generated at runtime, but they are more flexible as well. E.g. you can write a protocol that has a subset of some classes you haven't written and this way allow to use these classes polymorphically in your own framework.
Jun 04 2005
prev sibling parent "Kris" <fu bar.com> writes:
Christopher Diggins was around here for a little while:
http://www.digitalmars.com/d/archives/digitalmars/D/1097.html

I thought it was a good idea also.



"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:d7t04k$5se$1 digitaldaemon.com...
 I guess you'll find
 this idea is close to yours:
 http://www.heron-language.com/interfaces.html
 Chapter 'Unintrusive Retroactive Polymorphism'
 The idea is just perfect, imho.

 Andrew.


 "Matthias Becker" <Matthias_member pathlink.com> wrote in message
 news:d7k1b0$15md$1 digitaldaemon.com...
in D, an interface is a pointer to a vtbl[]. Each interface implemented
by a class gets a vptr allocated in the class instance, and that vptr
points
to a vtbl[] for the functions that implement it.
Such a vtbl[] coud be created at runtime as well, right? So perhaps
there
 could
 be a new language-construct (I call it protocoll for now) which
basically
 behaes
 like an interface, but doesn't need to be explicitly implemented:

 protocol Foo {
 void method ();
 }

 class Bar {
 void method () {...}
 }

 void function (Foo foo) {...}

 void main ()
 {
 function (new Bar());  // OK
 }

 Protocolls might be a bit more expensive than interfaces as the vtbl[]
has
 to be
 generated at runtime, but they are more flexible as well. E.g. you can
 write a
 protocol that has a subset of some classes you haven't written and this
 way
 allow to use these classes polymorphically in your own framework.
Jun 04 2005
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Derek Parnell" <derek psych.ward> wrote in message 
news:bjopczpwluat$.z1g5tgrbc43m$.dlg 40tude.net...
 My experience with Interfaces is zero, except for dabbling with the D
 offering. My understanding of what interfaces are is that they are a
 mechanism for defining a set of methods that must be implemented by a
 class. About 30 minutes ago I was reading the DSource forum in which
 'teqdruid' posted an simple example that shocked me into realizing that
 there is at least one deficiency in the current Interface syntax.
That's very weird. I always assumed D's interfaces supported covariant return types, as inherited classes do, though I've not yet needed to use them, so I never knew it didn't work. Maybe it's just an oversight in the spec?
May 30 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Derek Parnell" <derek psych.ward> wrote in message
news:bjopczpwluat$.z1g5tgrbc43m$.dlg 40tude.net...
 If we could define interfaces thus (or similar syntax) ...

  interface MutableList
  {
    this opSlice(int a, int b);
  }
  interface Reproduce
  {
    this dup();
  }

 then you can code the class definition as ...

  class MyList : MutableList, Reproduce
  {
    MyList opSlice(int a, int b)
    {
       . . .
    }
    MyList dup()
    {
       . . .
    }
    . . .
  }
I can't help but think that an interface template will fit the bill here: interface MutableList(T) { T opSlice(int a, int b); } interface Reproduce(T) { T dup(); } class MyList : MutableList!(MyList), Reproduce!(MyList) { MyList opSlice(int a, int b) { . . . } MyList dup() { . . . } . . . }
May 31 2005
parent Derek Parnell <derek psych.ward> writes:
On Tue, 31 May 2005 20:07:32 -0700, Walter wrote:

 "Derek Parnell" <derek psych.ward> wrote in message
 news:bjopczpwluat$.z1g5tgrbc43m$.dlg 40tude.net...
 If we could define interfaces thus (or similar syntax) ...

  interface MutableList
  {
    this opSlice(int a, int b);
  }
  interface Reproduce
  {
    this dup();
  }

 then you can code the class definition as ...

  class MyList : MutableList, Reproduce
  {
    MyList opSlice(int a, int b)
    {
       . . .
    }
    MyList dup()
    {
       . . .
    }
    . . .
  }
I can't help but think that an interface template will fit the bill here:
I didn't know one could do that! I think I'll update the wiki DocComments about this. This is exactly what is required for my purposes (though the syntax is a tad bulky). -- Derek Melbourne, Australia 1/06/2005 1:16:59 PM
May 31 2005