Bug 7135 – [tdpl] Multiple delegate-related issues (literal syntax, @system deduction)

Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Mac OS X
Creation time
2011-12-18T21:08:00Z
Last change time
2013-05-21T02:47:44Z
Keywords
TDPL
Assigned to
nobody
Creator
andrei

Comments

Comment #0 by andrei — 2011-12-18T21:08:50Z
This is a copy of a failing TDPL example. First, the compiler doesn't accept the delegate literal syntax unless it includes the keyword "delegate". Fixing that somehow makes the compiler decide the literal is @system and refuses binding it. module test;// Context begin #line 1369 "0900-operators.tex" import std.variant; alias Variant delegate(Dynamic self, Variant[] args...) DynMethod; // Context end // Context begin #line 1383 "0900-operators.tex" class Dynamic { private DynMethod[string] methods; void addMethod(string name, DynMethod m) { methods[name] = m; } void removeMethod(string name) { methods.remove(name); } // Dispatch dynamically on method Variant call(string methodName, Variant[] args...) { return methods[methodName](this, args); } // Provide syntactic sugar with opDispatch Variant opDispatch(string m, Args)(Args args...) { Variant[] packedArgs = new Variant[args.length]; foreach (i, arg; args) { packedArgs[i] = Variant(arg); } return call(m, args); } } // Context end #line 1409 "0900-operators.tex" unittest { import std.stdio; auto obj = new Dynamic; obj.addMethod("sayHello", delegate Variant(Dynamic, Variant[]) { writeln("Hello, world!"); return Variant(); }); obj.sayHello(); // Prints "Hello, world!" } void main(){}
Comment #1 by k.hara.pg — 2011-12-30T23:28:51Z
This is not the delegate literal type deduction problem. It is a trivial mismatching of delegate types. This is the reduced code to explain the problem. ---- struct Variant {} class Dynamic {} alias Variant delegate(Dynamic self, Variant[] args...) DynMethod; void main() { DynMethod dg = delegate Variant(Dynamic, Variant[]) { return Variant(); }; } Output: ---- test.d(6): Error: cannot implicitly convert expression (__dgliteral1) of type Variant delegate(Dynamic _param_0, Variant[] _param_1) pure nthrow @safe to Variant delegate(Dynamic self, Variant[] args...) DynMethod has typesafe variadic parameter, but literal doesn't have. So this is a bug of TDPL sample code, not compiler's.
Comment #2 by andrei — 2011-12-31T00:40:00Z
(In reply to comment #1) > This is not the delegate literal type deduction problem. > It is a trivial mismatching of delegate types. > > This is the reduced code to explain the problem. > ---- > struct Variant {} > class Dynamic {} > alias Variant delegate(Dynamic self, Variant[] args...) DynMethod; > void main() > { > DynMethod dg = delegate Variant(Dynamic, Variant[]) { > return Variant(); > }; > } > > Output: > ---- > test.d(6): Error: cannot implicitly convert expression (__dgliteral1) of type > Variant delegate(Dynamic _param_0, Variant[] _param_1) pure nthrow @safe to > Variant delegate(Dynamic self, Variant[] args...) > > DynMethod has typesafe variadic parameter, but literal doesn't have. > So this is a bug of TDPL sample code, not compiler's. I think (and perhaps I'm wrong) that the signature with ... and the one without must be equivalent. The ... makes a difference only in the call syntax, but in fact still passes an array. (Note that the variadics ending with "T[] param..." are not unsafe C-style variadics.) Please advise - thanks!
Comment #3 by k.hara.pg — 2011-12-31T01:01:24Z
(In reply to comment #2) > I think (and perhaps I'm wrong) that the signature with ... and the one without > must be equivalent. The ... makes a difference only in the call syntax, but in > fact still passes an array. (Note that the variadics ending with "T[] param..." > are not unsafe C-style variadics.) Please advise - thanks! Hmm, current compiler always raise an error against the difference of variadic argument kind (non-variarics vs typesafe-variadics vs C-style variadics). But, from http://d-programming-language.org/abi.html > The variadic part is converted to a dynamic array and the rest is the same as for non-variadic functions. So, in ABI layer, (..., T[]) and (..., T[]...) might be same...
Comment #4 by clugdbug — 2011-12-31T03:12:50Z
(In reply to comment #3) > (In reply to comment #2) > > I think (and perhaps I'm wrong) that the signature with ... and the one without > > must be equivalent. The ... makes a difference only in the call syntax, but in > > fact still passes an array. (Note that the variadics ending with "T[] param..." > > are not unsafe C-style variadics.) Please advise - thanks! > > Hmm, current compiler always raise an error against the difference of variadic > argument kind (non-variarics vs typesafe-variadics vs C-style variadics). > > But, from http://d-programming-language.org/abi.html > > > The variadic part is converted to a dynamic array and the rest is the same as for non-variadic functions. > > So, in ABI layer, (..., T[]) and (..., T[]...) might be same... I don't think so. One difference is visible in declaration.html (there may be other). It says: "An implementation may construct the object or array instance on the stack. Therefore, it is an error to refer to that instance after the variadic function has returned: int[] test(int[] a ...) { return a; // error, array contents invalid after return } " So, it would be legal to call the delegate with the Variant[]... stored on the stack. But it would fail. It might be OK to assign a (Variant[]...) function to a (Variant[]) delegate, but I'm pretty sure the other direction doesn't work.
Comment #5 by timon.gehr — 2011-12-31T07:32:53Z
(In reply to comment #4) > (In reply to comment #3) > > (In reply to comment #2) > > > I think (and perhaps I'm wrong) that the signature with ... and the one without > > > must be equivalent. The ... makes a difference only in the call syntax, but in > > > fact still passes an array. (Note that the variadics ending with "T[] param..." > > > are not unsafe C-style variadics.) Please advise - thanks! > > > > Hmm, current compiler always raise an error against the difference of variadic > > argument kind (non-variarics vs typesafe-variadics vs C-style variadics). > > > > But, from http://d-programming-language.org/abi.html > > > > > The variadic part is converted to a dynamic array and the rest is the same as for non-variadic functions. > > > > So, in ABI layer, (..., T[]) and (..., T[]...) might be same... > > I don't think so. One difference is visible in declaration.html (there may be > other). It says: > > "An implementation may construct the object or array instance on the stack. > Therefore, it is an error to refer to that instance after the variadic function > has returned: > > int[] test(int[] a ...) { > return a; // error, array contents invalid after return > } > " > So, it would be legal to call the delegate with the Variant[]... stored on the > stack. But it would fail. > It might be OK to assign a (Variant[]...) function to a (Variant[]) delegate, > but I'm pretty sure the other direction doesn't work. It should be OK to assign (scope Variant[]) to (Variant[]...).
Comment #6 by andrei — 2011-12-31T08:43:40Z
OK, it looks like this is safe to close now. I compiled a slightly modified version. There was a bug elsewhere, the line Variant opDispatch(string m, Args)(Args args...) { should be Variant opDispatch(string m, Args...)(Args args) { Also, the signature of the delegate should contain "...", i.e. replace delegate Variant(Dynamic, Variant[]) { with delegate Variant(Dynamic, Variant[]...) { The working code is: module test;// Context begin #line 1369 "0900-operators.tex" import std.variant; alias Variant delegate(Dynamic self, Variant[] args...) DynMethod; // Context end // Context begin #line 1383 "0900-operators.tex" class Dynamic { private DynMethod[string] methods; void addMethod(string name, DynMethod m) { methods[name] = m; } void removeMethod(string name) { methods.remove(name); } // Dispatch dynamically on method Variant call(string methodName, Variant[] args...) { return methods[methodName](this, args); } // Provide syntactic sugar with opDispatch Variant opDispatch(string m, Args...)(Args args) { Variant[] packedArgs = new Variant[args.length]; foreach (i, arg; args) { packedArgs[i] = Variant(arg); } return call(m, args); } } // Context end #line 1409 "0900-operators.tex" unittest { import std.stdio; auto obj = new Dynamic; obj.addMethod("sayHello", delegate Variant(Dynamic, Variant[]...) { writeln("Hello, world!"); return Variant(); }); obj.sayHello(); // Prints "Hello, world!" } void main(){}
Comment #7 by andrei — 2011-12-31T10:32:43Z
One more thing - the example in the book reads: obj.addMethod("sayHello", Variant(Dynamic, Variant[]...) { writeln("Hello, world!"); return Variant(); }); That doesn't work. The compilable version reads: obj.addMethod("sayHello", delegate Variant(Dynamic, Variant[]...) { writeln("Hello, world!"); return Variant(); }); Can we arrange things such that the "delegate" or "function" keywords aren't require in the literal definition?
Comment #8 by k.hara.pg — 2012-01-01T05:56:47Z
(In reply to comment #7) > One more thing - the example in the book reads: > > obj.addMethod("sayHello", > Variant(Dynamic, Variant[]...) { > writeln("Hello, world!"); > return Variant(); > }); > > That doesn't work. The compilable version reads: > > obj.addMethod("sayHello", > delegate Variant(Dynamic, Variant[]...) { > writeln("Hello, world!"); > return Variant(); > }); > > Can we arrange things such that the "delegate" or "function" keywords aren't > require in the literal definition? From past, omission of delegate keyword + specification of return type has been wrong syntax. So Variant(Dynamic, Varinat[]...) { ... } couldn't compile. And recent commit https://github.com/D-Programming-Language/dmd/commit/c50eb5f5726a65efa1224ff0f0fd60acbb6e3027 has been disallowed optional parameter names, because of parameter type inference. From these matters, current TDPL code never become valid. ---- Today, following literal notations has been allowed with current dmd. delegate Variant(Dynamic self, Variant[] args...) {...} delegate (Dynamic self, Variant[] args...) {...} (Dynamic self, Variant[] args...) {...} ---- Note: Unfortunately, current dmd does not support parameter type inference + type-safe variadisc like follows. //delegate (self, args...) {...} //(self, args...) {...} Because args could have three kind of infer targets. T[N] args... // T is the element type of args T[] args... // T is the element type of args T args... // T is class type, and args is translated to new T(args)
Comment #9 by k.hara.pg — 2012-03-13T20:50:21Z
(In reply to comment #8) > Note: Unfortunately, current dmd does not support parameter type inference + > type-safe variadisc like follows. > > //delegate (self, args...) {...} > //(self, args...) {...} I've filed bug 7705 to allow such lambda syntax, and posted a pull request to fix it.
Comment #10 by k.hara.pg — 2013-05-21T02:47:44Z
I close this as resolved invalid.