On Monday, 20 November 2023 at 13:25:48 UTC, Paul Backus wrote:
> On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote:
>
- What is the way to do
writeln
work with Counter
function the same way it works with next
function?
writeln(&Counter)
should do it.
It does not do the same: It shows an address, not the function signature.
Because I need to understand "why", I propose a second example (with some additional info based on @evilrat proposals :-) ):
import std.stdio;
void main()
{
auto createCounter = (int nextValue) => (int dummy) => nextValue++;
auto getNext = createCounter(10);
writeln( "'getNext' is ", getNext );
writeln( "'createCounter' is ", createCounter );
writeln( "'typeof(getNext).stringof' is ", typeof(getNext).stringof );
writeln( "'typeof(createCounter).string' is ", typeof(createCounter).stringof );
}
The output is
'next' is int delegate(int) pure nothrow @nogc @safe
'createCounter' is 557FFCC00968
'typeof(getNext).stringof' is int delegate(int dummy) pure nothrow @nogc @safe
'typeof(createCounter).string' is int delegate(int dummy) pure nothrow @nogc @safe function(int nextValue) pure nothrow @safe
Why writeln
doesn't treat the same way getNext
and createCounter
?
Because getNext
is a delegate and createCounter
is a function.
Why this is a function and not a delegate?
auto createCounter = (int nextValue) => (int dummy) => nextValue++;
Syntactically I dont see any difference:
auto name = "expression returning a delegate"
The reason is D compiler takes the decision.
If you make createCounter
to depend on an external variable, it will be treated as delegate (because it has context information associated to the function: a closure)
import std.stdio;
void main()
{
int diff = 1;
auto createCounter = (int nextValue) => () { scope(exit) nextValue+=diff; return nextValue;};
writeln( "'typeof(createCounter).string' is ", typeof(createCounter).stringof );
}
Will output that createCounter is a delegate:
'typeof(createCounter).string' is int delegate() pure nothrow @nogc @safe delegate(int nextValue) pure nothrow @safe
What "breaks" my mind is that a compiler decision (treat a piece of code as function or delegate) is not completely transparent causing "side" effects on your code (writeln doesn't work the same way: it shows the delegate signature, but not the function signature).
But the decision of the compiler is predictable and you can argue different effects are not side effects: only something you should pay attention to.
This long and winding road toke me to a third and crazzy question
Is there any way to force D compiler to treat this "createCounter" declaration as delegate instead of function?
auto createCounter = (int nextValue) => () => nextValue++;