View mode: basic / threaded / horizontal-split · Log in · Help
August 03, 2007
Re: Overloading/Inheritance issue
Regan, good thing posting about that other older thread, I didn't know 
about it, and it was nice to see some actual arguments for the current 
behavior (even if I don't agree with them, but at least they can be 
argued), instead of the typical "it's the way it's done in C++"/"it's 
how C++ people want it done"...

The first argument is this one:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=6975
(the one where with a series of cast, one can call a different method 
other than the "nearest" one in the method lineage hierarchy)
Indeed that's a problematic behavior, but it's not a language design 
error, it's a compiler bug! There has to be a way to make that work. 
Wasn't this option even considered or discussed? Did Walter just go 
right through to changing the language?


Regan Heath wrote:
> Steve Schveighoffer wrote:
> 
> Performance isn't the reason against the Java behaviour, here is Walters 
> explaination:
> 
> <quote Walter quoting Stroustrup>
> 
> Stroustrup gives two examples (slightly modified here):
> 
> ---------------------------------
> class X1 { void f(int); }
> 
> // chain of derivations X(n) : X(n-1)
> 
> class X9: X8 { void f(double); }
> 
> void g(X9 p)
> {
>     p.f(1);    // X1.f or X9.f ?
> }
> -----------------------------------
> His argument is that one can easilly miss an overload of f() somewhere in a
> complex class heirarchy, and argues that one should not need to understand
> everything about a class heirarchy in order to derive from it. 

The second argument. This one is simply crap...
Stroustrup argues "that one should not need to understand everything 
about a class heirarchy in order to derive from it". Well, maybe you 
don't have to understand *everything* but you surely will have to 
understand *a lot*, even if you aren't changing a lot of behavior in the 
subclass. This is simply something you can't (or shouldn't) escape from: 
if you are changing the implementation, even if just a bit, you have to 
understand the rest of implementation, or you risk breaking things, no 
mater how boring or worksome it might be. This is not the same as simply 
*using* a class, where you only have to understand it's 
interface/contract, and encapsulation shields you from the implementation.
This is my rebuttal for the general case of this argument, but as for 
that particular example, it should also be noted, that with a decent IDE 
(in the likeness of JDT), the example is totally moot. You just place 
your mouse of the function call, and a text hover will show you the 
signature (and javadoc) of the function, thus immediately indicating 
which overload is being called, without having to manually search N 
levels of hierarchy to find which overload it is. Code completion will 
also allow listing all available overloads in an equally easy and 
convenient way. This is yet another case of people failing to understand 
how semantic code analysis tools (ie, IDE) can influence language 
productivity and design shortcomings.
(Minor plug, these two features, especially the last one, are not too 
far from being implemented in the Descent project)

>The other
> example involves operator=(), but since D doesn't allow overloading
> operator=() instead I'll rewrite it as if it were a function that needs to
> alter a class state, and a derived class written later that 'caches' a
> computation on the derived state:
> 
> class B
> {    long x;
>      void set(long i) { x = i; }
>     void set(int i) { x = i; }
>     long squareIt() { return x * x; }
> }
> class D : B
> {
>     long square;
>     void set(long i) { B.set(i); square = x * x; }
>     long squareIt() { return square; }
> }
> 
> Now, imagine B were a complex class with a lot of stuff in it, and our
> optimizing programmer missed the existence of set(int). Then, one has:
> 
>     long foo(B b)
>     {
>         b.set(3);
>         return b.squareIt();
>     }
> 
> and we have an obscure bug.
> 
> </quote>
> 

The third and final argument. This one at least, I agree that it is a 
valid concern. However, this should be solved in another way, not with 
the current D behavior (which clearly breaks the is-a relationship, a 
fixture of OO semantics).
One suggestion I agree with, is that if a subclass does not override 
*all* overloads of the same function name, then it is a compiler error. 
Then the above code would simply be an error, forcing the user to use an 
alias to bring down the upper class overloads, or write their own overloads.
For example, I've personally written visitor classes that in D would 
*silently* break with this behavior, and it wouldn't be easy to spot it, 
as well as very error prone in the face of changes. I could post the 
examples but it likely wouldn't matter to Walter anyway.

PS: Someone call to this thread those guys who think D design 
development is "community-driven"... ;)

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
August 04, 2007
Re: Overloading/Inheritance issue
Derek Parnell wrote:
> This is intentional and is due to D's simplistic lookup rules. Basically, D
> will look for a matching signature only in the class it self and not in any
> parent classes (its a little more complex than this but ...)

Essentially, D's behavior here matches C++'s. Steve is asking for Java 
style behavior. There are good arguments for both styles, and risks with 
both.

I prefer the C++ style because:

1) One can get the Java style behavior by using the alias declaration as 
outlined by Derek.

2) It avoids the problem of forgetting to override one of the base class 
overloads, which can be a hidden source of bugs.

3) A new overload can be added to the base class without screwing up the 
derived class.

4) Having overloads spread across the inheritance hierarchy makes the 
source code resistant to visual audits. For any method call, you'll have 
to look at EVERY base class to see if it has an overload that is a 
better match.

5) I tend to view overloads as a tool that should be used sparingly, not 
as a substitute for having to think up a new name. In that vein, having 
a complex set of overloads is an indication that something might be 
wrong with the design.
August 04, 2007
Re: Overloading/Inheritance issue
Kirk McDonald wrote:
>>   alias super.foo foo;
> That's not a workaround, nor is this considered a problem. This is the 
> intended behavior.

Yes, and it took some extra effort to make sure it worked that way! In 
other words, it is not accidental or incidental behavior.
August 04, 2007
Re: Overloading/Inheritance issue
Steve Schveighoffer wrote:
> Everyone who used the Y derivative suddenly finds their code doesn't 
compile.


This is actually good. Failing to compile means that a change in the 
class that might break things will not *silently* break things.
August 04, 2007
Re: Overloading/Inheritance issue
Aarti_pl wrote:
> ... and it's even not consistent with one of D design rules:
> 
> "If something looks similar as in C++, it should behave similar to C++."
> 
> I think that breaking this rule is main source of confusion here. In my 
> opinion it would be much better for D to implement inheritance in a way 
> similar to other C-like languages.

It does behave, in this instance, just like C++. Steve is asking for the 
Java behavior.
August 04, 2007
Re: Overloading/Inheritance issue
Regan Heath wrote:
> I could keep linking all day... these are all from the same thread so 
> starting at the top and reading the whole thread should give you a fair 
> idea of the issues.

All on one page:

http://www.digitalmars.com/d/archives/digitalmars/D/6928.html
August 04, 2007
Re: Overloading/Inheritance issue
Walter Bright wrote:

> Aarti_pl wrote:
>> ... and it's even not consistent with one of D design rules:
>> 
>> "If something looks similar as in C++, it should behave similar to C++."
>> 
>> I think that breaking this rule is main source of confusion here. In my
>> opinion it would be much better for D to implement inheritance in a way
>> similar to other C-like languages.
> 
> It does behave, in this instance, just like C++. Steve is asking for the
> Java behavior.

Yes you are right. I found that I was wrong just after Regan post with old
threads concerning this issue.

There must be some other rule broken in this case, because I didn't know
that in C++ behaviour is same. :-) Probably rule which is broken is just...
programmer intuition...

Although current behaviour is not very intuitive I can live with it (knowing
that there are arguments against intuitive behaviour). I think that it
would be good idea to document it better (including few arguments why it
was chosen over Java style behaviour).

-- 
Regards
Marcin Kuszczak (Aarti_pl)
-------------------------------------
Ask me why I believe in Jesus - http://zapytaj.dlajezusa.pl (en/pl)
Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/
-------------------------------------
August 04, 2007
Re: Overloading/Inheritance issue
Walter Bright wrote:
> 
> 4) Having overloads spread across the inheritance hierarchy makes the 
> source code resistant to visual audits. For any method call, you'll have 
> to look at EVERY base class to see if it has an overload that is a 
> better match.
> 

I'm not sure if you've seen my other reply to this argument, but let be 
more explicit, with pictures. Let's say you have such a big inheritance 
hierarchy, with overloads spread across it.

This is a picture of one using a tool to list all possible overloads, 
without have to look at EVERY base class:
http://web.ist.utl.pt/bruno.d.o.medeiros/dee/ide_overload_completion.png
It shows you the signatures of all overloads (as well as the class that 
they belong to).

This is a picture of one calling that function with a literal, and 
having the tool automatically list which overload is being called:
http://web.ist.utl.pt/bruno.d.o.medeiros/dee/ide_overload_lookup.png
The yellow popup shows the signature of the invoked overload, which we 
can see is the one with the long parameter. How easy! You don't even 
have to recall the specifics of the lookup rules of the language.
(note that that popup appears just by placing the mouse cursor over 
"set", there is not even a need to invoke an explicit command)

D's syntax makes it as easy to build these tools as Java, C#, Ruby, 
etc.. (which is *way* easier than doing it for C++)

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
August 04, 2007
Re: Overloading/Inheritance issue
Derek Parnell wrote:
> On Wed, 01 Aug 2007 16:47:12 -0400, Steve Schveighoffer wrote:
> 
>> I am wondering if the following behavior is intentional and if so, why. 
> 
> This is intentional and is due to D's simplistic lookup rules. Basically, D
> will look for a matching signature only in the class it self and not in any
> parent classes (its a little more complex than this but ...)
> 
> To 'fix' this situation you need to explicitly identify methods from parent
> classes that you wish to access from objects of the child class. This is
> done using an alias statement.
> 
> Add "alias X.foo foo;" to your class definition of Y.
> 
> class Y : X
> {
>   alias X.foo foo; // pulls in class X's foo name into this scope.
>   public int foo(int y)
>   {
>     return 3;
>   }
> }
> 
> Now it will compile and run.
> 
Well if you're going to make that kind of a requirement, why 
not allow multiple inheritance?  It would seem to resolve all 
the problems with "ambiguity in multiple paths of implementation".

(Also, it would be well if this were prominently documented. 
You did a very clear job, so copying that would be all that's 
necessary.  File it under inheritance.)
August 05, 2007
Re: Overloading/Inheritance issue
Bruno Medeiros wrote:
> Walter Bright wrote:
>>
>> 4) Having overloads spread across the inheritance hierarchy makes the 
>> source code resistant to visual audits. For any method call, you'll 
>> have to look at EVERY base class to see if it has an overload that is 
>> a better match.
>>
> 
> I'm not sure if you've seen my other reply to this argument, but let be 
> more explicit, with pictures. Let's say you have such a big inheritance 
> hierarchy, with overloads spread across it.

I appreciate that you can write tools to analyze it. I think they help a 
lot in writing the code, but I don't think they are as helpful for 
auditing (code review).

Another problem with them is they are not part of the D compiler itself, 
and in my experience add on tools rarely get used, no matter how useful 
they are.
1 2 3 4 5 6 7
Top | Discussion index | About this forum | D home