D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 11754 - Disallow changing the default parameters of overridden inherited functions
Summary: Disallow changing the default parameters of overridden inherited functions
Status: RESOLVED WONTFIX
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-12-16 14:58 UTC by bearophile_hugs
Modified: 2020-08-04 04:21 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2013-12-16 14:58:11 UTC
Perhaps it's a good idea to statically disallow code like this (returning a compilation error), that changes the default parameters of overridden inherited functions:


import std.stdio;
class Base {
    /*virtual*/ void foo(int i = 10) {
        writeln("Base.foo() ", i);
    }
}
class Derived: Base {
    override /*virtual*/ void foo(int i = 20) { // line 8
        writeln("Derived.foo() ", i);
    }
}
void main() {
    Base c1 = new Base;
    c1.foo();  // Output: Base.foo() 10
    Derived c2 = new Derived;
    c2.foo();  // Output: Derived.foo() 20
    Base c3 = new Derived;
    c3.foo(); // Output: Derived.foo() 10
}



The explanation:
http://www.gotw.ca/gotw/005.htm

> Like overloads, default parameters are taken from the static type (here Base) of the object,
> hence the default value of 10 is taken. However, the function happens to be virtual,
> and so the function actually called is based on the dynamic type (here Derived) of the object.


So I suggest that D code to give an error message like:

test.d(8): Error: changing default arguments of overridden inherited functions is not allowed


Code like this is OK:

void foo(int i) {
...
override void foo(int i) {


Just as:

void foo(int i = 10) {
...
override void foo(int i = 10) {

------------------

Alternative design: just give a warning instead of an error.

------------------

Alternative design: the error message could be shown only if there is one actual function call that doesn't specify the missing argument. This means in this alternative design this main() doesn't generate the error message:

void main() {
    Base c1 = new Base;
    c1.foo(10);
    Derived c2 = new Derived;
    c2.foo(10);
    Base c3 = new Derived;
    c3.foo(10);
}
Comment 1 Andrej Mitrovic 2013-12-19 08:50:51 UTC
What if the initializer in the base class is private?

-----
module a;
private int priv;

class A
{
    void foo(int x = priv) { }
}
-----

-----
module b;
import a;

class B : A
{
    override void foo(int x = priv)  // error: "priv" is private
    {
    }
}
-----
Comment 2 bearophile_hugs 2013-12-19 14:14:46 UTC
(In reply to comment #1)
> What if the initializer in the base class is private?

After the restriction that I have suggested to add, you can't write that code. You have to solve the problem in some other way. (Perhaps using an overloaded method?)
Comment 3 Mathias LANG 2020-08-04 04:21:06 UTC
That seems like a pointless restriction. Closing as WONTFIX.