Bug 3866 – anonymous delegate with default parameters cross-talks to another anonymous delegate

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-03-01T09:36:00Z
Last change time
2013-07-04T04:52:55Z
Keywords
pull, wrong-code
Assigned to
yebblies
Creator
philippe.sigaud

Comments

Comment #0 by philippe.sigaud — 2010-03-01T09:36:25Z
If you declare an anonymous delegate with default parameter, it affects another anonymous delegate with the same type: import std.stdio; void main() { auto foo = (int a = 1) { return a;}; auto bar = (int a) { return a;}; writeln(foo()); // writes '1' writeln(bar()); // writes '1' also! } It provokes (correctly) an error if bar is defined before foo: bar() called with 0 argument instead of 1. It does not affect delegate with another type auto baz = (double a) { return a;}; writeln(baz()); // Error, correct behaviour
Comment #1 by yebblies — 2011-07-03T06:14:23Z
Comment #2 by yebblies — 2012-02-11T18:55:08Z
The problem occurs because default parameters are stored in the type, but types are considered equivalent if their mangled names match, and mangled names don't include parameter names or default arguments. The solution is probably either to include parameter names and default arguments in the comparison for equality, or to move them out of function types and into function declarations. I'm leaning towards the latter. This case _can_ be fixed by refusing to merge function pointers, but the problem will still exists for pointers to function pointers, structs containing function pointers, etc.
Comment #3 by bugzilla — 2012-04-25T20:35:30Z
Moving the default arguments out of the type and into the function declaration will resolve the problem, at the cost of you would no longer be able to have default arguments for function literals or any pointers to functions. Perhaps that's a good thing.
Comment #4 by issues.dlang — 2012-04-26T10:33:19Z
It was my understanding that default arguments were just arguments that were inserted when a function was called and you didn't provide all of the arguments. They aren't actually part of the signature or type at all. As such, they are only known if you call the function directly. If you use a function pointer (or delegate), then all you have is the signature, so you don't have any default arguments. As such, nested functions with default arguments such as static auto foo(int a = 1) { return a; } and auto foo(int a = 1) { return a + b; } should work just fine, but as with any function, as soon as you take their address or turn them into a delegate variable, their default arguments are lost. And so having default arguments in something like auto foo = (int a = 1) { return a;}; auto bar = (int a) { return a;}; is completely pointless, because all you have is a variable which knows the signature of the function/delegate to call. The function itself can't be called directly, so it doesn't have any default arguments associated with it, and so there's no point in the default arguments even being legal.
Comment #5 by bugzilla — 2012-04-26T23:06:52Z
Leaving this as-is for D1 to avoid breaking existing code. For D2, changing behavior so that default args are part of the declaration, not the type, and so both function calls in the example are illegal, since calling through a function pointer now cannot have default args.
Comment #6 by github-bugzilla — 2012-04-26T23:10:36Z
Commit pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/acc22ce25db42facfe4917aeceabd28a410f4c95 fix Issue 3866 - anonymous delegate with default parameters cross-talks to another anonymous delegate
Comment #7 by bugzilla — 2012-07-22T13:08:12Z
*** Issue 8258 has been marked as a duplicate of this issue. ***
Comment #8 by bugzilla — 2012-07-24T23:01:48Z
*** Issue 8430 has been marked as a duplicate of this issue. ***
Comment #9 by bugzilla — 2012-07-25T11:44:18Z
*** Issue 8438 has been marked as a duplicate of this issue. ***
Comment #10 by andrej.mitrovich — 2012-07-30T17:37:07Z
Personally I never used default values in delegates but I think this pull broke this real-world code from Derelict: void loadPlatformGL(void delegate(void**, string, bool doThrow = true) bindFunc) { bindFunc(null, "foo1"); bindFunc(null, "foo2"); // ... } In this case the default value is useful since it's only used from within the function, and it saves on typing since there are typically dozens of invocations of the delegate (in Derelict).
Comment #11 by k.hara.pg — 2012-08-04T10:12:29Z
*** Issue 8402 has been marked as a duplicate of this issue. ***
Comment #12 by bugzilla — 2012-08-06T15:31:02Z
*** Issue 8515 has been marked as a duplicate of this issue. ***
Comment #13 by k.hara.pg — 2012-09-05T19:02:04Z
In the forum discussion: http://forum.dlang.org/thread/[email protected] We decided to improve the status for default argument issues. Then I've created a new pull which contains some fixups for this issue. D2 pull: https://github.com/D-Programming-Language/dmd/pull/1102 So I reopen this for D2.
Comment #14 by github-bugzilla — 2013-07-04T03:04:04Z
Commit pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/d7362898f16d7d5e04ac4e9f374a39a5e8e0ff53 Improved fix for Issue 3866 - anonymous delegate with default parameters cross-talks to another anonymous delegate This reverts commit acc22ce25db42facfe4917aeceabd28a410f4c95, and moves original test into runnable/functype.d