Bug 7265 – Function Literals where a keyword was omitted should be delegate even if inference.

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dlang.org
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-01-10T09:30:00Z
Last change time
2012-01-17T10:11:05Z
Assigned to
nobody
Creator
zan77137

Comments

Comment #0 by zan77137 — 2012-01-10T09:30:54Z
This code should be work (on git head): ------- import std.stdio; void main() { auto dg = { writeln("delegate"); }; static assert(is(typeof(dg) == delegate)); } ------- main.d(6): Error: static assert (is(void function() == delegate)) is false ------- This is being documented as follows: > If the keywords function or delegate are omitted, it defaults to being a delegate.
Comment #1 by timon.gehr — 2012-01-15T11:56:18Z
This is a case of outdated documentation. From TDPL, p150: "If both function and delegate are absent from the literal, the compiler automatically detects which one is necessary".
Comment #2 by zan77137 — 2012-01-16T03:48:12Z
(In reply to comment #1) > This is a case of outdated documentation. > From TDPL, p150: > "If both function and delegate are absent from the literal, the compiler > automatically detects which one is necessary". It is an example unlike the specifications(TDPL, p150). The case is the following situation: ------- import std.stdio, std.traits; void main() { void function() fn = { writeln("function"); }; static assert(isFunctionPointer!(typeof(fn))); void delegate() dg = { writeln("delegate"); }; static assert(isDelegate!(typeof(dg))); } ------- As noted above, the specifications are applied only when there is a necessary type. When there is not a required type, in the case like this time, it should infer the type of the default. This resembles the following examples: ------- import std.traits; void main() { byte a = 1; // typeof(a) is byte auto b = 1; // typeof(b) is int // int cannot implicitly cast to byte. static assert (isImplicitlyConvertible!(typeof(b), typeof(a))); // false. } -------
Comment #3 by timon.gehr — 2012-01-16T08:44:22Z
Everything behaves as specified in TDPL. This is not a compiler bug.
Comment #4 by andrei — 2012-01-16T09:25:15Z
(In reply to comment #3) > Everything behaves as specified in TDPL. This is not a compiler bug. Yah, I just tested this: import std.stdio, std.traits; void main() { auto fn = { writeln("function"); }; static assert(isFunctionPointer!(typeof(fn))); int x; auto dg = { writeln("delegate because it prints ", x); }; static assert(isDelegate!(typeof(dg))); } So the literal is properly classified as a function or delegate depending on it needing a frame pointer or not. There's one remaining question I have. I rewrote the example like this: import std.stdio, std.traits; void main() { auto fn = { writeln("function"); }; static assert(is(typeof(fn) == function)); int x; auto dg = { writeln("delegate because it prints ", x); }; static assert(is(typeof(dg) == delegate)); } The second static assert works, but the first doesn't. Why?
Comment #5 by zan77137 — 2012-01-16T10:07:04Z
(In reply to comment #4) > (In reply to comment #3) > > Everything behaves as specified in TDPL. This is not a compiler bug. > > Yah, I just tested this: > > import std.stdio, std.traits; > void main() > { > auto fn = { writeln("function"); }; > static assert(isFunctionPointer!(typeof(fn))); > int x; > auto dg = { writeln("delegate because it prints ", x); }; > static assert(isDelegate!(typeof(dg))); > } > > So the literal is properly classified as a function or delegate depending on it > needing a frame pointer or not. > Hmm... Because it included a clear breaking change, I thought that a sample code was wrong. > There's one remaining question I have. I rewrote the example like this: > > > import std.stdio, std.traits; > > void main() > { > auto fn = { writeln("function"); }; > static assert(is(typeof(fn) == function)); > > int x; > auto dg = { writeln("delegate because it prints ", x); }; > static assert(is(typeof(dg) == delegate)); > } > > The second static assert works, but the first doesn't. Why? "fn" of the first case is a function pointer and is not a function. The code outputs a compilation error definitely. ----- import std.stdio, std.traits; void main() { static assert(is(typeof(main) == function)); // true, typeof(main) is function static assert(is(typeof(&main) == function)); // false, typeof(&main) is function pointer } -----
Comment #6 by andrei — 2012-01-16T10:15:03Z
(In reply to comment #5) > ----- > import std.stdio, std.traits; > > void main() > { > static assert(is(typeof(main) == function)); // true, typeof(main) is > function > static assert(is(typeof(&main) == function)); // false, typeof(&main) is > function pointer > } > ----- I think fn in auto fn = { ... }; should be the same thing - a name for a function. I guess that's not easy to implement. Kenji, Walter?
Comment #7 by k.hara.pg — 2012-01-16T16:11:52Z
> I think fn in > > auto fn = { ... }; > > should be the same thing - a name for a function. I guess that's not easy to > implement. Kenji, Walter? Rewriting it to true function declaration is easy, but fn is looks like a variable so peaple will try to rebind it with assignment: fn = { writeln("another function literal"); }; and will get an error. It is inconsistent.
Comment #8 by andrei — 2012-01-16T16:36:05Z
OK, thanks.
Comment #9 by zan77137 — 2012-01-17T06:37:31Z
By the way, the reason why I set this Issue with regression is that I cause a difficult problem with the following cases: ------ import std.stdio, std.functional; // Library code struct Control { alias void delegate(Control o) Handler; Handler[] _handlers; void addHandler(H)(H hnd) { _handlers ~= cast(Handler)hnd; } void addHandler2(H)(H hnd) if (is(H == delegate)) { _handlers ~= cast(Handler)hnd; } // Workaround. It is settled if can handle either by toDelegate. void addHandler3(H)(H hnd) { _handlers ~= cast(Handler)toDelegate(hnd); } void call() { foreach (h; _handlers) { h(this); } } } // User code void main() { int i; auto c = new Control; // OK. This literal is inferred delegate. c.addHandler( (Object o){ writeln(i); } ); // Error. This literal is inferred function pointer. // c.addHandler( (Object o){ writeln("test"); } ); // Error. This literal is inferred function pointer, too. // The constraint-if does not influence the type inference. // c.addHandler2( (Object o){ writeln("test2"); } ); // Workaround. c.addHandler3( (Object o){ writeln("test3"); } ); c.call(); } ------ When a library code has a definition such as Control, many breaking changes befall user codes. Actually, this way is used by DFL. One of simple workaround is to use toDelegate with library codes. I think that another solution is to let implicit conversion perform a role as toDelegate. I remember it has entered ML agenda several times. But I've forgotten the conclusion. Is there a person knowing the details?
Comment #10 by timon.gehr — 2012-01-17T10:11:05Z
(In reply to comment #9) > One of simple workaround is to use toDelegate with library codes. > > I think that another solution is to let implicit conversion perform a role as > toDelegate. > > I remember it has entered ML agenda several times. But I've forgotten the > conclusion. > Is there a person knowing the details? I think no conclusion has been reached yet. Andrei (and me too) wants implicit conversions from function pointer to delegate to work, but Walter disagrees with it.