Summary: delegates with differing default arguments lead to
                    same template instantiation
           Product: D
           Version: 1.057
          Platform: Other
        OS/Version: All
            Status: NEW
          Keywords: wrong-code
          Severity: major
          Priority: P2
         Component: DMD

--- Comment #0 from 2010-03-29 16:02:30 PDT ---
Look at these two delegates:

void delegate(int x = 123) D_A;
void delegate(int x) D_B;

They have the same type, but they behave differently. E.g. you can call D_A(),
but not D_B().

They lead to the same template instantiation:

void foo(T)(T del) {

foo(D_A) and foo(D_B) will be the same template instantiations.

This is a bug, because foo(D_B) will think that del has a default parameter,
which is obviously not the case. dmd should instantiate two different templates
for it. Maybe make delegates with different default args have different types.

Here's a test case, which demonstrates how this can lead to trouble in real
world programs. The code is ripped out from a scripting wrapper, which tries to
support default arguments. (The reason why doMethod is templated on a delegate
and not on the class/method is to drastically reduce the number of template

import std.stdio;

template ParameterTupleOf( Fn )
    static if( is( Fn Params == function ) )
        alias Params ParameterTupleOf;
    else static if( is( Fn Params == delegate ) )
        alias ParameterTupleOf!(Params) ParameterTupleOf;
    else static if( is( Fn Params == Params* ) )
        alias ParameterTupleOf!(Params) ParameterTupleOf;
        static assert( false, "Argument has no parameters." );

int requiredArgCount(alias Fn)() {
    alias ParameterTupleOf!(typeof(Fn)) Params;
    Params p;
    static if (is(typeof(Fn())))
        return 0;
    foreach (int idx, x; p) {
        static if (is(typeof(Fn(p[0..idx+1]))))
            return idx+1;

class Foo {
    void moo1() {}
    void moo2(short x) {}
    void moo3(int x = 123) {}
    void moo4(int x) {}

void doMethod(T)(T del, char[] name, char[] expect) {
    writefln("method %s, required arg count: got %s, expected %s", name,
requiredArgCount!(del)(), expect);

void method(Class, char[] name)(char[] expect) {
    auto fn = mixin("&Class." ~ name);
    doMethod(fn, name, expect);

void main() {
    //just to prove that the other code works
    method!(Foo, "moo1")("0");
    method!(Foo, "moo2")("1");
    //here starts the problem
    //moo3 instantiates doMethod!(void delegate(int x = 123))
    method!(Foo, "moo3")("0");
    //moo4 _should_ instantiate doMethod!(void delegate(int x))
    //but it really insantiates the same as moo3:
    //  doMethod!(void delegate(int x = 123))
    //this is obviously wrong!
    //doMethod() will think that moo4 has a default argument, when it
    //really hasn't (you can see that in the runtime output of this program)
    method!(Foo, "moo4")("1");

Configure issuemail:
------- You are receiving this mail because: -------

Reply via email to