April 16, 2006
In article <e1s2sr$n4s$1@digitaldaemon.com>, Hasan Aljudy says...
>
>What you want is exactly what polymorphism is designed for. I really don't understand what's your problem.
>
I don't believe that D can solve the following problem. I can see several way to get a _similar_ effect but all have substantial penalties involving code complexity, speed or maintainability/extensibility

If you can use you suggested approach to solve this problem I would be pleased to see it.
---------------
You are given this (you may not modify it)

interface I {int get();}
interface J {int get();}

1) You need to make a class C that implements both I and J that has different action for I.get and J.get.

2) Classes derived from C must be able to override the action of both I.get and Jget

3) Given an instance, c, of the class C, the following statements must work.
I i = c;
i.get	// must call the appropriate I.get even if c is of a derived type.
J j = c
j.get	// must call the appropriate J.get even if c is of a derived type.

4) Converting a C object to an I or J interface must not rely on the overloading
of the cast operation (e.i. "I i = c;" must not call any methods)

5) Must be simply extendable to interfaces with lots of function (one more function in I must not require more than one function be defined to keep C up to date)

I believe these requirements for a programming solution to be vary reasonable. If I were working in a programming shop and assigned a subordinate to the problem as defined through point 2, I would expect that 3-5 would be assumed.



April 16, 2006
In article <e1s7gd$r15$1@digitaldaemon.com>, BCS says...
>
>In article <e1s2sr$n4s$1@digitaldaemon.com>, Hasan Aljudy says...
>>
>>What you want is exactly what polymorphism is designed for. I really don't understand what's your problem.
>>
>I don't believe that D can solve the following problem.
[...]

Oops:

I forgot to state my position

The problem I stated before is conceptually vary easy to solve: somehow, explicitly set the contents of the vtbls used by C when cast to I or J. The solution that you proposed, while workable, is a vary poor design. It is wasteful in runtime, program size, memory usage, code size and maintenance cost.



April 16, 2006
BCS wrote:
> In article <e1s2sr$n4s$1@digitaldaemon.com>, Hasan Aljudy says...
> 
>>What you want is exactly what polymorphism is designed for. I really don't understand what's your problem.
>>
> 
> I don't believe that D can solve the following problem. I can see several way to
> get a _similar_ effect but all have substantial penalties involving code
> complexity, speed or maintainability/extensibility
> 
> If you can use you suggested approach to solve this problem I would be pleased
> to see it.
> ---------------
> You are given this (you may not modify it)
> 
> interface I {int get();}
> interface J {int get();}
> 
> 1) You need to make a class C that implements both I and J that has different
> action for I.get and J.get.
> 
> 2) Classes derived from C must be able to override the action of both I.get and
> Jget
> 
> 3) Given an instance, c, of the class C, the following statements must work.
> I i = c;
> i.get	// must call the appropriate I.get even if c is of a derived type.
> J j = c
> j.get	// must call the appropriate J.get even if c is of a derived type.
> 
> 4) Converting a C object to an I or J interface must not rely on the overloading
> of the cast operation (e.i. "I i = c;" must not call any methods)
> 
> 5) Must be simply extendable to interfaces with lots of function (one more
> function in I must not require more than one function be defined to keep C up to
> date)
> 
> I believe these requirements for a programming solution to be vary reasonable.
> If I were working in a programming shop and assigned a subordinate to the
> problem as defined through point 2, I would expect that 3-5 would be assumed.

I would dump these requirements, talk to the guy who set them, and try to figure out what problem he was trying to solve, then I'd make a better design.

> The problem I stated before is conceptually vary easy to solve: somehow,
> explicitly set the contents of the vtbls used by C when cast to I or J. The
> solution that you proposed, while workable, is a vary poor design. It is
> wasteful in runtime, program size, memory usage, code size and maintenance cost.

It's not very easy, and I don't see how it improves performance.

1. It requires a substantial change to the grammar; namely, function names are not simply identifiers any more.

2. I don't see where's the performance gain; you're still using vtables.

I don't even see how it's supposed to be a "better design".

April 16, 2006
On Sun, 16 Apr 2006 11:43:41 +1000, BCS <BCS_member@pathlink.com> wrote:

> In article <e1s2sr$n4s$1@digitaldaemon.com>, Hasan Aljudy says...
>>
>> What you want is exactly what polymorphism is designed for. I really
>> don't understand what's your problem.
>>
> I don't believe that D can solve the following problem. I can see several way to
> get a _similar_ effect but all have substantial penalties involving code
> complexity, speed or maintainability/extensibility
>
> If you can use you suggested approach to solve this problem I would be pleased
> to see it.
> ---------------
> You are given this (you may not modify it)
>
> interface I {int get();}
> interface J {int get();}


I understood that an 'interface' was just a way of stating that the methods named in it must be implemented by any class that is derived from the interface. In other words, that the class must implement a method with the same name and parameter signature. So if two interfaces have the same method defined, then the class that is derived from both must define a method (one method) of the same name etc...


> 1) You need to make a class C that implements both I and J that has different
> action for I.get and J.get.

You can't do this in one class. I guess you can do ...

  class IC: I
  {
     int get(){ return 1; }
  }

  class JC: J
  {
     int get(){ return 2; }
  }

  class C
  {
      IC i;
      JC j;

      . . .
  }

  C c = new C;
  c.i.get;	// must call the appropriate I.get even if c is of a derived type.
  c.j.get;	// must call the appropriate J.get even if c is of a derived type.


> 2) Classes derived from C must be able to override the action of both I.get and
> J.get

But there are no actions defined for these interface methods, just signatures. There is nothing to override.

> 3) Given an instance, c, of the class C, the following statements must work.
> I i = c;
> i.get	// must call the appropriate I.get even if c is of a derived type.
> J j = c
> j.get	// must call the appropriate J.get even if c is of a derived type.
>
> 4) Converting a C object to an I or J interface must not rely on the overloading
> of the cast operation (e.i. "I i = c;" must not call any methods)
>
> 5) Must be simply extendable to interfaces with lots of function (one more
> function in I must not require more than one function be defined to keep C up to
> date)

It seems that 'interface' in D means something different from what you mean by the term.

-- 
Derek Parnell
Melbourne, Australia
April 16, 2006
In article <e1s99b$sop$1@digitaldaemon.com>, Hasan Aljudy says...
>
>BCS wrote:
>> In article <e1s2sr$n4s$1@digitaldaemon.com>, Hasan Aljudy says...
>> 
>>>What you want is exactly what polymorphism is designed for. I really don't understand what's your problem.
>>>
>> 
>> I don't believe that D can solve the following problem. I can see several way
>> to
>> get a _similar_ effect but all have substantial penalties involving code
>> complexity, speed or maintainability/extensibility
>> 
>> If you can use you suggested approach to solve this problem I would be
>> pleased
>> to see it.
>> ---------------
>> You are given this (you may not modify it)
>> 
>> interface I {int get();}
>> interface J {int get();}
>> 
>> 1) You need to make a class C that implements both I and J that has different action for I.get and J.get.
>> 
>> 2) Classes derived from C must be able to override the action of both I.get
>> and
>> Jget
>> 
>> 3) Given an instance, c, of the class C, the following statements must work.
>> I i = c;
>> i.get	// must call the appropriate I.get even if c is of a derived
>> type.
>> J j = c
>> j.get	// must call the appropriate J.get even if c is of a derived
>> type.
>> 
>> 4) Converting a C object to an I or J interface must not rely on the
>> overloading
>> of the cast operation (e.i. "I i = c;" must not call any methods)
>> 
>> 5) Must be simply extendable to interfaces with lots of function (one more function in I must not require more than one function be defined to keep C up to date)
>> 
>> I believe these requirements for a programming solution to be vary
>> reasonable.
>> If I were working in a programming shop and assigned a subordinate to the
>> problem as defined through point 2, I would expect that 3-5 would be assumed.
>
>I would dump these requirements, talk to the guy who set them, and try to figure out what problem he was trying to solve, then I'd make a better design.

say that the interfaces are part of closed source libs, as such the only part that is available for redesign is that part that is being designed by the hypothetical subordinate.

>
> > The problem I stated before is conceptually vary easy to solve: somehow,
> > explicitly set the contents of the vtbls used by C when cast to I or
> > J. The
> > solution that you proposed, while workable, is a vary poor design. It is
> > wasteful in runtime, program size, memory usage, code size and maintenance
> >cost.
>
>It's not very easy, and I don't see how it improves performance. 1. It requires a substantial change to the grammar;

This is exactly what I am saying should be done

> namely, function names are not simply identifiers any more.

Not necessarily a syntax like the following wouldn't require any change to the function definition syntax. Also it would allow a function to implement an interface without having the same name as the function in the interface (useful if that name is already used by a inherited class).

class C : I, J
{
int getI(){...}
int getI(){...}

alias getI I.get;
alias getJ J.get;
}
>
>2. I don't see where's the performance gain; you're still using vtables.

Yes but only one vtable and only one level of function call. Alternate solutions require the use of otherwise unneeded object with methods that simply wrap other methods. I would consider that pure waste.

>
>I don't even see how it's supposed to be a "better design".
>
I am considering this problem from the standpoint of the efficiency of the final product. I consider this objective to be of great importance, more so than the how easy it is to write the program (and to some degree the simplicity of the language). From this perspective, all available solutions to the problem are wistful. Some people take the opposite view, which supports different solutions.


April 16, 2006
In article <op.s72xewiy6b8z09@ginger.vic.bigpond.net.au>, Derek Parnell says...
>
>On Sun, 16 Apr 2006 11:43:41 +1000, BCS <BCS_member@pathlink.com> wrote:
>
>> In article <e1s2sr$n4s$1@digitaldaemon.com>, Hasan Aljudy says...
>>>
>>> What you want is exactly what polymorphism is designed for. I really don't understand what's your problem.
>>>
>> I don't believe that D can solve the following problem. I can see
>> several way to
>> get a _similar_ effect but all have substantial penalties involving code
>> complexity, speed or maintainability/extensibility
>>
>> If you can use you suggested approach to solve this problem I would be
>> pleased
>> to see it.
>> ---------------
>> You are given this (you may not modify it)
>>
>> interface I {int get();}
>> interface J {int get();}
>
>
>I understood that an 'interface' was just a way of stating that the methods named in it must be implemented by any class that is derived from the interface. In other words, that the class must implement a method with the same name and parameter signature. So if two interfaces have the same method defined, then the class that is derived from both must define a method (one method) of the same name etc...
>

Yes, mostly. However if I understand them correctly, an interface also defines a actual data structure that consist of a context pointer (the pointer to the object) and a separate vtbl pointer that points to a vtbl that is different from the vtbl of the implementing class. The point of this is that each interface has a layout for this vtbl that is independent of the layout of the classes vtbl. This has the effect that code that uses a interface only needs to known that layout and not anything about the class it is actually using.

>
>> 1) You need to make a class C that implements both I and J that has
>> different
>> action for I.get and J.get.
>
>You can't do this in one class. I guess you can do ...
>
>   class IC: I
>   {
>      int get(){ return 1; }
>   }
>
>   class JC: J
>   {
>      int get(){ return 2; }
>   }
>
>   class C
>   {
>       IC i;
>       JC j;
>
>       . . .
>   }
>
>   C c = new C;
>   c.i.get;	// must call the appropriate I.get even if c is of a derived
>type.
>   c.j.get;	// must call the appropriate J.get even if c is of a derived
>type.
>
>
>> 2) Classes derived from C must be able to override the action of both
>> I.get and
>> J.get
>
>But there are no actions defined for these interface methods, just signatures. There is nothing to override.

The point is that if E is derived from C, than the effect of casting a E object to type I and calling get can be defined in E

class E : C
{
int get() { /* new functionality*/ ...}
}
E e = new E;
I i = e;
i.get; // calls the function in E

>
>> 3) Given an instance, c, of the class C, the following statements must
>> work.
>> I i = c;
>> i.get	// must call the appropriate I.get even if c is of a derived type.
>> J j = c
>> j.get	// must call the appropriate J.get even if c is of a derived type.
>>
>> 4) Converting a C object to an I or J interface must not rely on the
>> overloading
>> of the cast operation (e.i. "I i = c;" must not call any methods)
>>
>> 5) Must be simply extendable to interfaces with lots of function (one
>> more
>> function in I must not require more than one function be defined to keep
>> C up to
>> date)
>
>It seems that 'interface' in D means something different from what you mean by the term.
>

I may be totally wrong, but I think that interfaces are a bit more than what you are thinking of. The documentation I have found on them is kind of thin and doesn't do a good job of describing what they actually are doing behind the scenes. Most of this I have had to puzzle out my self.

>-- 
>Derek Parnell
>Melbourne, Australia


April 17, 2006
Ryan Steen wrote:
> In article <e1qem7$1lvs$1@digitaldaemon.com>, Lionello Lunesu says...
> 
>> #class Command : IResult, IResultRow {	// handle wrapper
>> #	sqlite3_stmt* stmt;
>> #	~this() { sqlite3_finalize(stmt); }
>> #	IResult Execute() { return cast(IResult)this; }
>> #	// this one iterates rows; does cast(IResultRow)this
>> #	int IResult.opApply( int delegate(inout IResultRow) dg );
>> #	// this one iterates fields; does new ResultField(this,fieldno)
>> #	int IResultRow.opApply( int delegate(inout IResultField) dg );
>> #}
> 
> I do not see the problem here because the opApply from the different interfaces
> do not have identical formal parameter lists. Therefore your code above is very
> vlose to the solution:
> 
> #class Command : IResult, IResultRow {	// handle wrapper
> #	sqlite3_stmt* stmt;
> #	~this() { sqlite3_finalize(stmt); }
> #	IResult Execute() { return this; }
> #	// this one iterates rows; does cast(IResultRow)this
> #	int opApply( int delegate(inout IResultRow) dg );
> #	// this one iterates fields; does new ResultField(this,fieldno)
> #	int opApply( int delegate(inout IResultField) dg );
> #}

Brilliant!!! Why didn't I think of that.. Indeed, it works. BUT, I could not provide the opIndex and opCall operators:

#class Parameter {..}

#class Command {
#  // return command parameter i
#  Parameter opIndex(uint i);
#  // return command parameter named n
#  Parameter opCall(char[] n);
#}

#class ResultRow {
#  // return field at index i
#  ResultField opIndex(uint i);
#  // return field named n
#  ResultField opCall(char[] n);
#}

So the problem in the original post still applies to opIndex and opCall.

Thanks a lot for the suggestion ;)

L.
April 17, 2006
Hasan Aljudy wrote:

<snip>

> A bit more complicated (for this simple example), but you're doing the same thing: creating new entries in a vtable, to choose different functions at runtime.


Your solution is pretty close to what I had in the first place. The reason I didn't like it was because of all the "new"s. CA and CB don't contain any data, but must be new'ed nonetheless. Furthermore, in your code you have to keep passing the C class to each call on CA and CB: not a viable solution.

L.
April 17, 2006
Consider this:

Two interfaces are part of different third party modules. One module wants you to provide an implementation for interface IA and a completely different module needs some interface IB. They are completely unrelated.

No problem at all. Your application class can easily interface with both:

class C : IA, IB
{
  // implement all of IA's methods
  ...
  // implement all of IB's methods
  ...
}

And you provide cast(IA)this to module A and cast(IB)this to module B. No worries.

After some time, a new version has come out for both the third party modules, each with some added functionality. However, all programmers being human (last time I checked) they're pretty bad at randomness and they both declared a method "int get()" in their interfaces.

Now you're in trouble. There's no way you can provide one implementation for both "int get()"s, since they are completely unrelated. IA.get is used in a completely different context from IB.get.

Now what? Redesign the whole app and make multiple classes? I wish there was another way.

L.
April 17, 2006
In article <e1vci0$1luu$1@digitaldaemon.com>, Lionello Lunesu says...
>They are completely unrelated.
>Now what? Redesign the whole app and make multiple classes?

Yes. Such design is flawed: to implement two completely unrelated interfaces in one single class.