Proposition for change in D regarding Inheriting overloaded methods

Steven Schveighoffer schveiguy at yahoo.com
Tue Aug 7 14:09:31 PDT 2007


"Walter Bright" wrote in message news:f9aalt$b2p$1 at digitalmars.com...
> Steven Schveighoffer wrote:
>> However, does the author intend to handle the case where foo(int) is 
>> called? Let's assume he does (which is what the current compiler 
>> assumes).  The author has not forbidden the user of the class from 
>> calling A.foo, because the user can simply cast to an A object, and call 
>> A.foo(int) directly. Therefore, if the author meant to override foo(int) 
>> by defining just a foo(long), he has failed.  From these points, I 
>> believe that the above code is an example of an incorrectly implemented 
>> override, and I believe that the correct response the compiler should 
>> have is to error out, not while compiling test(), but while compiling B, 
>> indicating to the user that he should either declare the alias, or 
>> override foo(int).  This is the point in which my solution differs from 
>> Java.  Java would allow this to proceed, and call the base class' 
>> foo(int) in all cases, which is not what the author intended.
>
> The next update of the compiler will throw a runtime exception for this 
> case.

How is this better than the current implementation?  In the current 
implementation, the code compiles and creates an obscure bug because the 
behavior isn't what the user expects.  In this new implementation, the 
obscure bug is only less obscure because an exception is thrown.  The code 
still compiles properly.  Why allow compilation at all?

>
>> The second issue is how to handle the foo(char[]) case.  In the current 
>> implementation, because A is not searched for overrides, the compiler 
>> produces an error indicating that the user tried to call the foo(long) 
>> method, but there is no implicit conversion from char[] to long.  There 
>> are two possibilities.  One is that the author did not notice that 
>> A.foo(char[]) existed, and intended to override all instances of foo() 
>> with his foo(long) override.  However, the author is NOT notified of this 
>> issue, only the user of the class is notified of this issue.  So the 
>> potential for unambiguous code to have escaped exists.
>
> But a compile time error is still generated, so I don't regard this as a 
> big problem. The big problems are silent hijacking of code.
>

The problem is WHEN the compile time error is generated.  I do not mind if 
the author of the class cannot generate object code for his class because of 
a compile time error (see my alternate solution).  However, because the 
compile error is generated when someone attempts to USE the class, the error 
is delivered to the incorrect person.  That person may not have the ability 
to fix the error.

Silent hijacking of code is not possible with the solution I propose, so 
that becomes a moot point.

>
>> The second possibility is that the author fully intended to allow the 
>> base class to define foo(char[]), but forgot to define the alias.  Again, 
>> since the compiler gives no error, he is unaware that he is releasing 
>> buggy code to the world.  I believe the correct assumption of the 
>> compiler should be that the user wanted the alias for the base class' 
>> foo(char[]), and should alias it implicitly if and only if no suitable 
>> match exists on the derived class.  In the case where the author did not 
>> notice foo(char[]) existed, he problably doesn't mind that foo(char[]) is 
>> defined by the base class.
>
> The problem with code that looks like a mistake, but the compiler makes 
> some assumption about it and compiles it anyway, is that the code auditor 
> cannot tell if it was intended behavior or a coding error.

I understand your point of view, and that is why I said that I would concede 
to a solution where a compiler error is thrown if all overloads are not 
handled.  However, I think it is still incorrect to generate the compiler 
error on the use of the class rather than the compilation of the class.  My 
preference as I said is to avoid having to specify the alias in the simple 
case where the arguments are not implicitly convertable, but if there must 
be a compilation error, I am willing to live with that.

>> If a suitable match exists that is not a direct override of the base 
>> class, then the issue reduces to the previous case, where an implicit 
>> conversion is required, and the compiler should error out.
>>
>> There is one other possibile solution that I would be willing to concede 
>> to, and that is that the compiler errors out if the base class does not 
>> override all overloads of a particular method name.  This forces the user 
>> to either override all overloads of the method, or define the alias. 
>> This would be the safest solution, as the author of B must make his 
>> intentions perfectly clear.
>
> I am not comfortable with this method, as it will force the derived class 
> programmer to implement overloads that may not be at all meant to exist in 
> the API he defines for that class. I think he should be in full control of 
> the API for the class, and not forced to provide implementations of 
> functions that may be irrelevant clutter. I prefer the solution where 
> attempts to call unoverridden base class overloads will result in a 
> runtime exception.
>

The problem is they ARE implemented, and now they will cause runtime 
exceptions!  Also, now this breaks the contract that the base class 
provides.  If you give me an instance of a certain class, and the 
documentation for that class says that it defines a given method, then that 
method should be implemented in all derivatives.  If you want to derive a 
class and force the implementation of a base class' method to throw an 
exception, I think that should be the (for better lack of a word) exception, 
not the rule.  Why derive from a class where you want to shoehorn its 
functionality into something different?  I would recommend to someone trying 
to do that to define a new class, rather than derive.  I challenge anyone to 
give a real-world example of why this should be possible.

As you point out, it is possible to force the implementation that you are 
specifying by overriding the overloaded method and throwing the exception 
yourself, and maybe the requirement of extra cluttering functions will 
discourage people from implementing their code this way.  Maybe there could 
be a specific keyword or something to specify that you want to have the 
overload throw an exception, so there is less code clutter, but I do not 
think the default should be throwing an exception.

-Steve 





More information about the Digitalmars-d mailing list