digitalmars.D.learn - What is :-) ?
- Antonio (37/37) Nov 20 2023 If I run this code
- evilrat (9/24) Nov 20 2023 `writeln( "'Counter' is ", Counter );`
- Antonio (33/35) Nov 20 2023 If you execute
- evilrat (17/22) Nov 20 2023 I found no way to tell compiler that I don't want to call Counter
- Paul Backus (7/11) Nov 20 2023 This is not UFCS, it's [optional parentheses][1], which is a
- Paul Backus (2/4) Nov 20 2023 `writeln(&Counter)` should do it.
- Antonio (74/78) Nov 20 2023 It does not do the same: It shows an address, not the function
- evilrat (17/23) Nov 20 2023 generally there is a way to tell the compiler specifically that
- Antonio (38/46) Nov 21 2023 Thank you!!!.
- Paul Backus (15/26) Nov 20 2023 It's certainly surprising that `writeln` treats function pointers
- Antonio (2/11) Nov 21 2023 Thaks Paul
- Julian Fondren (42/49) Nov 20 2023 `createCounter` is a function, and not a delegate, as it doesn't
If I run this code ```d import std.stdio; void main(){ auto next = Counter(10); next().writeln; next().writeln; next().writeln; // What is "next" function? writeln( "'next' is ", next ); // What is "Counter" function? This fails // writeln( "'Counter' is ", Counter ); } auto Counter(int nextValue) => () => nextValue++; ``` Executing this code results in: ``` 10 11 12 'next' is int delegate() pure nothrow nogc safe ``` Now, I uncomment the ```writeln( "'Counter' is ", Counter );``` line and compiler says ``` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): Error: function `x.Counter(int nextValue)` is not callable using argument types `()` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): too few arguments, expected 1, got 0 ``` I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible ) - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function?
Nov 20 2023
On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote:Now, I uncomment the ```writeln( "'Counter' is ", Counter );``` line and compiler says ``` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): Error: function `x.Counter(int nextValue)` is not callable using argument types `()` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): too few arguments, expected 1, got 0 ``` I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible )`writeln( "'Counter' is ", Counter );` this code is actually internally looks like this `writeln( "'Counter' is ", Counter() );` if you meant to take the function/delegate and not invoke try `&Counter` instead, otherwise it expects the parameters.- What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function?Sorry, that's too confusing and I have no idea what you mean, maybe if you can explain what you are trying to achieve someone might be able to help you.
Nov 20 2023
On Monday, 20 November 2023 at 09:11:07 UTC, evilrat wrote:if you meant to take the function/delegate and not invoke try `&Counter` instead, otherwise it expects the parameters.If you execute ``` writeln( "'Counter' is ", &Counter ); ``` It shows the Counter address: ``` 'Counter' is 557F2567F940 ``` Not the function signature like it does with ```next``` I propose a simple change: ```d void main(){ auto Counter = (int nextValue) => () => nextValue++; auto next = Counter(10); writeln( "'next' is ", next ); writeln( "'Counter' is ", Counter ); } ``` first ```writeln``` shows the signature of next: ``` 'next' is int delegate() pure nothrow nogc safe ``` second writeln shows the address of Counter ``` 'Counter' is 55568953C910 ``` - Why writeln doesn't treat ```next``` and ```Counter``` the same way? (I think I understand why, but it shows a "low" level difference of something that syntactically is equivalent) - What is the way to show Counter signature using ```writeln``` (if possible)? ```
Nov 20 2023
On Monday, 20 November 2023 at 09:44:32 UTC, Antonio wrote:- Why writeln doesn't treat ```next``` and ```Counter``` the same way? (I think I understand why, but it shows a "low" level difference of something that syntactically is equivalent) - What is the way to show Counter signature using ```writeln``` (if possible)?I found no way to tell compiler that I don't want to call Counter and instead want to take the function itself, but closest thing is just to take the string representation at compile time (same as used in pragma msg) and pass it to writeln instead of Counter. I guess this is one of these bif oof moments with UFCS, a function returning a (parameterless) function. Note that in most cases you should never make runtime decisions on .stringof value as it is not standardized. ``` //pragma(msg, typeof(Counter)); // pure nothrow safe int delegate() pure nothrow nogc safe(int nextValue) enum f = typeof(Counter).stringof; // same string as above writeln( "'Counter' is ", f); ``` Of course this works too `writeln( "'Counter' is ", typeof(Counter).stringof);`
Nov 20 2023
On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote:I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible )This is not UFCS, it's [optional parentheses][1], which is a separate language feature. (Reminder: UFCS only applies when the callee has the form `x.y`) According to the spec, it's disabled for function pointers and delegates due to the potential for ambiguity. [1]: https://dlang.org/spec/function.html#optional-parenthesis
Nov 20 2023
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.
Nov 20 2023
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: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 :-) ): ```d 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) ```d 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**? ```d auto createCounter = (int nextValue) => () => nextValue++; ```- What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function?`writeln(&Counter)` should do it.
Nov 20 2023
On Monday, 20 November 2023 at 16:09:33 UTC, Antonio wrote:Is there any way to force D compiler to treat this "createCounter" declaration as **delegate** instead of **function**? ```d auto createCounter = (int nextValue) => () => nextValue++; ```generally there is a way to tell the compiler specifically that you want a delegate or a function, and additionally there is `toDelegate` function from std.functional that could be useful in some cases. https://dlang.org/phobos/std_functional.html#toDelegate the syntax for specifying delegate/function is smth like this, IIRC return type can be omitted but for reference I write it here as auto. ```d // this is a function returning a delegate auto createCounter(int nextValue) => auto delegate() => nextValue++; // this is a function returning a function auto createCounter(int nextValue) => auto function() => nextValue++; ```
Nov 20 2023
On Monday, 20 November 2023 at 16:32:22 UTC, evilrat wrote:```d // this is a function returning a delegate auto createCounter(int nextValue) => auto delegate() => nextValue++;Thank you!!!. Compiler forces me to omit "auto" keyword ```d auto createCounter(int nextValue) => delegate () => nextValue++ ; ``` Explicit return must be specified after "delegate" keyword ```d auto createCounter(int nextValue) => delegate int () => nextValue++ ; ``` When declaring a type (variable or parameter) is when keywords order must be "inverted" ```d import std.stdio; int callWith10( int delegate (int) x) =>x(10); void main(){ int j=100; // Explicit writeln( callWith10( delegate int (int i)=>i+j ) ); // Inferred writeln( callWith10( i=>i+j ) ); // OMG writeln( ( i=>i+j ).callWith10 ); } ```// this is a function returning a function auto createCounter(int nextValue) => auto function() => nextValue++; ```I think this will not work, because nextValue is defined out of the returned function scope: you must return a closure (delegate). Thanks a lot evilrat!!! **From your answer (and other ones too) I have to say that...** * **D Closures rocks!!!** It is hard to find something so powerful in other natively compiled languages: **Heap + GC** has it's advantages. * **D offers nice syntax features**: you can declare arrow methods very similar to dart, or assign an arrow function/delegate to a variable like Javascript/Typescript lambdas.
Nov 21 2023
On Monday, 20 November 2023 at 16:09:33 UTC, Antonio wrote: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).It's certainly surprising that `writeln` treats function pointers and delegates differently. My guess is that it's because [`isPointer`][1] returns `true` for functions and `false` for delegates. [1]: https://phobos.dpldocs.info/std.traits.isPointer.htmlIs there any way to force D compiler to treat this "createCounter" declaration as **delegate** instead of **function**? ```d auto createCounter = (int nextValue) => () => nextValue++; ```You can put the `delegate` keyword in front of the function literal: ```d auto createCounter = delegate (int nextValue) => () => nextValue++; ``` This syntax is documented in the spec's section on [Function Literals][2] (look at the grammar box and the examples). [2]: https://dlang.org/spec/expression.html#function_literals
Nov 20 2023
On Monday, 20 November 2023 at 16:47:13 UTC, Paul Backus wrote:You can put the `delegate` keyword in front of the function literal: ```d auto createCounter = delegate (int nextValue) => () => nextValue++; ``` This syntax is documented in the spec's section on [Function Literals][2] (look at the grammar box and the examples). [2]: https://dlang.org/spec/expression.html#function_literalsThaks Paul
Nov 21 2023
On Monday, 20 November 2023 at 16:09:33 UTC, Antonio wrote:**Why this is a function and not a delegate?** ```auto createCounter = (int nextValue) => (int dummy) => nextValue++;``` Syntactically I dont see any difference:`createCounter` is a function, and not a delegate, as it doesn't close over any variables. It returns a delegate as the variable `nextValue` is closed over. There's no difference in syntax. The difference is however important as an environment must be retained for the closed-over variables and passed along with the pointer, making delegates both more expensive and incompatible with function pointers on the C ABI. Note that `f` and `g` are obviously not pointing to the same `nextValue`: ```d auto createCounter = (int nextValue) => () => nextValue++; void main() { import std.stdio : writeln; auto f = createCounter(5); auto g = createCounter(0); writeln(f()); // 5 writeln(g()); // 0 writeln(f()); // 6 writeln(g()); // 1 } ```What "breaks" my mind is that a compiler decision (treat a piece of code as function or delegate) is not completely transparentD is trying to be convenient (by offering delegates at all, and by making the syntax so light) while offering fine control (by letting you distinguish between function pointers and delegates). It'd be a much simpler language if it dropped one of those aims, but such languages also already exist. Similarly D also distinguishes between "numbers" (`int`) and "numbers" (`double`) and this can also be transparent and also cause 'side effects'. Someone educated in mathematics but not familiar with computing might complain about ```d void main() { import std.stdio : writefln; auto n = 1; writefln!"%d"(n); } ``` breaking when "all I did was bump n by one-tenth, to 1.1". I'm not trying to be mean with this example, and I don't think it's shameful either to know mathematics but not computing. But D expects you to be familiar with such things for you to not be surprised by how it behaves.
Nov 20 2023