www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - tuple of delegates requires explicit type

reply DigitalDesigns <DigitalDesigns gmail.com> writes:
alias f = void delegate();
Tuple!(f)[] fs;

fs ~= tuple(() { });

fails but

fs ~= Tuple!(f)(() { });

passes.
in tuple, it is seeing the lambda as void and thinks I'm trying 
to append a tuple of void. I don't see why the compiler can't see 
that it works.
Jun 20 2018
next sibling parent Meta <jared771 gmail.com> writes:
On Wednesday, 20 June 2018 at 11:43:52 UTC, DigitalDesigns wrote:
 alias f = void delegate();
 Tuple!(f)[] fs;

 fs ~= tuple(() { });

 fails but

 fs ~= Tuple!(f)(() { });

 passes.
 in tuple, it is seeing the lambda as void and thinks I'm trying 
 to append a tuple of void. I don't see why the compiler can't 
 see that it works.
It's because if you don't specify any types, the compiler creates a template function so type inference for the arguments/return type can take place. It could probably be inferred without making the literal a template, but that's just how it's done currently.
Jun 20 2018
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, June 20, 2018 11:43:52 DigitalDesigns via Digitalmars-d wrote:
 alias f = void delegate();
 Tuple!(f)[] fs;

 fs ~= tuple(() { });

 fails but

 fs ~= Tuple!(f)(() { });

 passes.
 in tuple, it is seeing the lambda as void and thinks I'm trying
 to append a tuple of void. I don't see why the compiler can't see
 that it works.
The types don't match. --- import std.typecons; alias f = void delegate(); void main() { pragma(msg, typeof(tuple((){}))); pragma(msg, typeof(Tuple!f((){}))); } --- prints Tuple!(void function() pure nothrow nogc safe) Tuple!(void delegate()) tuple is instantiated and evaluated independently of what's done with the result, so the fact that you're then appending it to a Tuple!f[] is irrelevant. By the point it tries to append, it's already determined the type of what it's trying to append, and because you didn't specify the type, it's what it gets inferred as, which is not the same type as you have in the array. - Jonathan M Davis
Jun 20 2018
parent reply DigitalDesigns <DigitalDesigns gmail.com> writes:
On Wednesday, 20 June 2018 at 12:08:28 UTC, Jonathan M Davis 
wrote:
 On Wednesday, June 20, 2018 11:43:52 DigitalDesigns via 
 Digitalmars-d wrote:
 alias f = void delegate();
 Tuple!(f)[] fs;

 fs ~= tuple(() { });

 fails but

 fs ~= Tuple!(f)(() { });

 passes.
 in tuple, it is seeing the lambda as void and thinks I'm trying
 to append a tuple of void. I don't see why the compiler can't 
 see
 that it works.
The types don't match. --- import std.typecons; alias f = void delegate(); void main() { pragma(msg, typeof(tuple((){}))); pragma(msg, typeof(Tuple!f((){}))); } --- prints Tuple!(void function() pure nothrow nogc safe) Tuple!(void delegate()) tuple is instantiated and evaluated independently of what's done with the result, so the fact that you're then appending it to a Tuple!f[] is irrelevant. By the point it tries to append, it's already determined the type of what it's trying to append, and because you didn't specify the type, it's what it gets inferred as, which is not the same type as you have in the array. - Jonathan M Davis
But here's the kicker!!! Trust me, it will be good!! They are the same types! That alone says that the compiler is not doing enough work! I mean, it is well established that the array is of type f and the lambda is of type f!! See, what the compiler is not doing is realizing that a lambda can be implicitly cast to any other lambda with the same signature. If it understood that then it should have no problem with casting the tuple implicitly.
 Tuple!(void function() pure nothrow  nogc  safe)
 Tuple!(void delegate())
a function can always be cast to a delegate(delegate is a super type as it inherits function in type logic) and the lambda may be a function or delegate depending on context. Hence the compiler can always assume an implicit cast of functions to delegates when type checking on tuple. This seems to be the missing logic either in the compiler or possibly with tuple. If tuple could support an implicit cast or simply upcast all functions to delegates then the code would work... but it seems tuple does no upcasting. Tuple!(double)[] f; f ~= tuple(3); // change 3 to 3.3 and it works fine! has the same problem. We know int inherits from double(it is a sub-type in the class of types). This is the same problem as general implicit casting which D can do. Just seems that it fails for tuples because it does not apply the implicit casts per argument. It's easy to see that if one has n types in a tuple then it can be implicitly converted if all the types are implicitly converted. Conv(T(a1,...,an)) = T(Conv(a1),...,Conv(an))
Jun 20 2018
parent ag0aep6g <anonymous example.com> writes:
On Wednesday, 20 June 2018 at 15:19:29 UTC, DigitalDesigns wrote:
 See, what the compiler is not doing is realizing that a lambda 
 can be implicitly cast to any other lambda with the same 
 signature. If it understood that then it should have no problem 
 with casting the tuple implicitly.


 Tuple!(void function() pure nothrow  nogc  safe)
 Tuple!(void delegate())
a function can always be cast to a delegate(delegate is a super type as it inherits function in type logic)
Functions (or rather, function pointers) do not convert implicitly to delegates in D. `void delegate()` is not a supertype of `void function()` in D. The issue is that a delegate call passes the context pointer in a spot where a function call passes a parameter. So a function pointer can't just be reinterpreted as a delegate. The conversion could be made to work by automatically wrapping the function in a delegate. Walter is understandibly against that because of the performance implication. Alternatively, it might be possible to change the delegate ABI so that the parameters are passed the same as for function calls. Older thread about that: https://forum.dlang.org/post/ofc0lj$2u4h$1 digitalmars.com
Jun 20 2018