Re: Strange closure behaviour

2019-06-15 Thread Timon Gehr via Digitalmars-d-learn

On 15.06.19 18:29, Rémy Mouëza wrote:

On Saturday, 15 June 2019 at 01:21:46 UTC, Emmanuelle wrote:

On Saturday, 15 June 2019 at 00:30:43 UTC, Adam D. Ruppe wrote:

On Saturday, 15 June 2019 at 00:24:52 UTC, Emmanuelle wrote:

Is it a compiler bug?


Yup, a very longstanding bug.

You can work around it by wrapping it all in another layer of 
function which you immediately call (which is fairly common in 
javascript):


    funcs ~= ((x) => (int i) { nums[x] ~= i; })(x);

Or maybe less confusingly written long form:

    funcs ~= (delegate(x) {
    return (int i) { nums[x] ~= i; };
    })(x);

You write a function that returns your actual function, and 
immediately calls it with the loop variable, which will explicitly 
make a copy of it.


Oh, I see. Unfortunate that it's a longstanding compiler bug, but at 
least the rather awkward workaround will do. Thank you!


I don't know if we can tell this is a compiler bug.


It's a bug. It's memory corruption. Different objects with overlapping 
lifetimes use the same memory location.



The same behavior happens in Python.


No, it's not the same. Python has no sensible notion of variable scope.

>>> for i in range(3): pass
...
>>> print(i)
2

Yuck.

The logic being variable `x` is captured by the 
closure. That closure's context will contain a pointer/reference to x. 
Whenever x is updated outside of the closure, the context still points 
to the modified x. Hence the seemingly strange behavior.

...


It's not the same instance of the variable. Foreach loop variables are 
local to the loop body. They may both be called `x`, but they are not 
the same. It's most obvious with `immutable` variables.


Adam's workaround ensures that the closure captures a temporary `x` 
variable on the stack: a copy will be made instead of taking a 
reference, since a pointer to `x` would be dangling once the 
`delegate(x){...}` returns.


Most of the time, we want a pointer/reference to the enclosed variables 
in our closures. Note that C++ 17 allows one to select the capture mode: 
the following link lists 8 of them: 
https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture.

...


No, this is not an issue of by value vs by reference. All captures in D 
are by reference, yet the behavior is wrong.


D offers a convenient default that works most of the time. The trade-off 
is having to deal with the creation of several closures referencing a 
variable being modified in a single scope, like the incremented `x` of 
the for loop.

...


By reference capturing may be a convenient default, but even capturing 
by reference the behavior is wrong.






Re: Using scanw Ncurses in D lang

2019-06-15 Thread ag0aep6g via Digitalmars-d-learn

On 15.06.19 23:20, Gabol wrote:

example: scanw("% i", & number); // The compiler accuses error.

Error: function deimos.ncurses.curses.scanw(char* fmt, ...) is not 
callable using argument types (string, int*)
source/app.d(8,14):    cannot pass argument "0" of type string to 
parameter char* fmt

/usr/bin/dmd failed with exit code 1.


Off topic:

The string literal in the error message is wrong. It's "0" when it 
should be "% i". I've made a PR to fix it:

https://github.com/dlang/dmd/pull/10040


Using scanw Ncurses in D lang

2019-06-15 Thread Gabol via Digitalmars-d-learn
how can I use the scanw() function; of the ncurses of the 
deimos.ncurses project since the conventional mode does not work

example: scanw("% i", & number); // The compiler accuses error.

Error: function deimos.ncurses.curses.scanw(char* fmt, ...) is 
not callable using argument types (string, int*)
source/app.d(8,14):cannot pass argument "0" of type 
string to parameter char* fmt

/usr/bin/dmd failed with exit code 1.


Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread user1234 via Digitalmars-d-learn

On Saturday, 15 June 2019 at 17:42:04 UTC, ag0aep6g wrote:

On Saturday, 15 June 2019 at 17:24:45 UTC, user1234 wrote:

---
void foo(){writeln(__PRETTY_FUNCTION__);}

void main(string[] args)
{
void delegate() dg;
dg.funcptr = 
dg.ptr = null; // usually a "this" or a frame address
dg();
}
---

because dg.ptr would be used to retrieve the offset of the 
locals variable used in the parent stack or the address of a 
class instance (the this). But this is not required at all 
here. The opposite way would lead to various access violation.


That only works because foo doesn't have any parameters. When 
you add even just one, things will go wrong.


True if was forgetting that the context is a hidden parameter...
Maybe it depends on the calling convention too ?


Re: Strange closure behaviour

2019-06-15 Thread Emmanuelle via Digitalmars-d-learn

On Saturday, 15 June 2019 at 16:29:29 UTC, Rémy Mouëza wrote:
I don't know if we can tell this is a compiler bug. The same 
behavior happens in Python. The logic being variable `x` is 
captured by the closure. That closure's context will contain a 
pointer/reference to x. Whenever x is updated outside of the 
closure, the context still points to the modified x. Hence the 
seemingly strange behavior.


I come from Ruby, where it works as I expected, so I assumed all 
languages would work like that; but then, D surprised me, and 
now, Python too, and apparently a whole bunch of other languages 
(which is honestly kinda disheartening since I like throwing 
lambdas everywhere.)




Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread ag0aep6g via Digitalmars-d-learn

On Saturday, 15 June 2019 at 17:24:45 UTC, user1234 wrote:

---
void foo(){writeln(__PRETTY_FUNCTION__);}

void main(string[] args)
{
void delegate() dg;
dg.funcptr = 
dg.ptr = null; // usually a "this" or a frame address
dg();
}
---

because dg.ptr would be used to retrieve the offset of the 
locals variable used in the parent stack or the address of a 
class instance (the this). But this is not required at all 
here. The opposite way would lead to various access violation.


That only works because foo doesn't have any parameters. When you 
add even just one, things will go wrong.


Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread user1234 via Digitalmars-d-learn

On Saturday, 15 June 2019 at 16:34:22 UTC, Robert M. Münch wrote:

On 2019-06-15 16:19:23 +, Anonymouse said:

By design, I think: "delegate and function objects cannot be 
mixed. But the standard function std.functional.toDelegate 
converts a function to a delegate."


Your example compiles if the assignment is changed to dg = 
toDelegate(); (given appropriate imports).


https://tour.dlang.org/tour/en/basics/delegates

https://dlang.org/phobos/std_functional.html#.toDelegate


Hmm... but this here compiles:

void main()
{
   import std.stdio: write, writeln, writef, writefln;
   void foo(int a) {return; }

   void test()
   {
void delegate(int) dg;

   dg = 
   }
}

See: https://run.dlang.io/is/U7uhAX

Is it because inside main() there is a stack frame? And with a 
global function there is none? I'm a bit confused...


yes. delegate is a function pointer + its context. At the global 
scope there's no context. Actually the following works fine:


---
void foo(){writeln(__PRETTY_FUNCTION__);}

void main(string[] args)
{
void delegate() dg;
dg.funcptr = 
dg.ptr = null; // usually a "this" or a frame address
dg();
}
---

because dg.ptr would be used to retrieve the offset of the locals 
variable used in the parent stack or the address of a class 
instance (the this). But this is not required at all here. The 
opposite way would lead to various access violation.


Re: Strange closure behaviour

2019-06-15 Thread Adam D. Ruppe via Digitalmars-d-learn

On Saturday, 15 June 2019 at 16:29:29 UTC, Rémy Mouëza wrote:

I don't know if we can tell this is a compiler bug.


I can't remember where the key fact was, but I used to agree with 
you (several languages work this same way, and it makes a lot of 
sense for ease of the implementation), but someone convinced me 
otherwise by pointing to the language of the D spec.


I just can't find that reference right now...

It is worth noting too that the current behavior also opens up a 
whole in the immutable promises; the loop variable can be passed 
as immutable to the outside via a delegate, but then modified 
afterward, which is unambiguously a bug.


Regardless of bug vs spec, it isn't implemented and I wouldn't 
expect that to change any time soon, so it is good to just learn 
the wrapper function technique :) (and it is useful in those 
other languages too)


Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread Alex via Digitalmars-d-learn

On Saturday, 15 June 2019 at 16:34:22 UTC, Robert M. Münch wrote:

On 2019-06-15 16:19:23 +, Anonymouse said:

By design, I think: "delegate and function objects cannot be 
mixed. But the standard function std.functional.toDelegate 
converts a function to a delegate."


Your example compiles if the assignment is changed to dg = 
toDelegate(); (given appropriate imports).


https://tour.dlang.org/tour/en/basics/delegates

https://dlang.org/phobos/std_functional.html#.toDelegate


Hmm... but this here compiles:

void main()
{
   import std.stdio: write, writeln, writef, writefln;
   void foo(int a) {return; }

   void test()
   {
void delegate(int) dg;

   dg = 
   }
}

See: https://run.dlang.io/is/U7uhAX

Is it because inside main() there is a stack frame? And with a 
global function there is none? I'm a bit confused...


Correct. Inside main, foo is a delegate.
https://dlang.org/spec/function.html#nested


Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread Robert M. Münch via Digitalmars-d-learn

On 2019-06-15 16:19:23 +, Anonymouse said:

By design, I think: "delegate and function objects cannot be mixed. But 
the standard function std.functional.toDelegate converts a function to 
a delegate."


Your example compiles if the assignment is changed to dg = 
toDelegate(); (given appropriate imports).


https://tour.dlang.org/tour/en/basics/delegates

https://dlang.org/phobos/std_functional.html#.toDelegate


Hmm... but this here compiles:

void main()
{
   import std.stdio: write, writeln, writef, writefln;
   void foo(int a) {return; }

   void test()
   {
void delegate(int) dg;

   dg = 
   }
}

See: https://run.dlang.io/is/U7uhAX

Is it because inside main() there is a stack frame? And with a global 
function there is none? I'm a bit confused...


--
Robert M. Münch
http://www.saphirion.com
smarter | better | faster



Re: Strange closure behaviour

2019-06-15 Thread Rémy Mouëza via Digitalmars-d-learn

On Saturday, 15 June 2019 at 01:21:46 UTC, Emmanuelle wrote:

On Saturday, 15 June 2019 at 00:30:43 UTC, Adam D. Ruppe wrote:

On Saturday, 15 June 2019 at 00:24:52 UTC, Emmanuelle wrote:

Is it a compiler bug?


Yup, a very longstanding bug.

You can work around it by wrapping it all in another layer of 
function which you immediately call (which is fairly common in 
javascript):


funcs ~= ((x) => (int i) { nums[x] ~= i; })(x);

Or maybe less confusingly written long form:

funcs ~= (delegate(x) {
return (int i) { nums[x] ~= i; };
})(x);

You write a function that returns your actual function, and 
immediately calls it with the loop variable, which will 
explicitly make a copy of it.


Oh, I see. Unfortunate that it's a longstanding compiler bug, 
but at least the rather awkward workaround will do. Thank you!


I don't know if we can tell this is a compiler bug. The same 
behavior happens in Python. The logic being variable `x` is 
captured by the closure. That closure's context will contain a 
pointer/reference to x. Whenever x is updated outside of the 
closure, the context still points to the modified x. Hence the 
seemingly strange behavior.


Adam's workaround ensures that the closure captures a temporary 
`x` variable on the stack: a copy will be made instead of taking 
a reference, since a pointer to `x` would be dangling once the 
`delegate(x){...}` returns.


Most of the time, we want a pointer/reference to the enclosed 
variables in our closures. Note that C++ 17 allows one to select 
the capture mode: the following link lists 8 of them: 
https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture.


D offers a convenient default that works most of the time. The 
trade-off is having to deal with the creation of several closures 
referencing a variable being modified in a single scope, like the 
incremented `x` of the for loop.


That said, I wouldn't mind having the compiler dealing with that 
case: detecting that `x` is within a for loop and making copies 
of it in the closures contexts.


Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread Anonymouse via Digitalmars-d-learn

On Saturday, 15 June 2019 at 15:54:00 UTC, Robert M. Münch wrote:
Why does the follwing code give: Error: cannot implicitly 
convert expression & myFunc of type void function(int a) to 
void delegate(int)



void myFunc(int a){return;}

void main()
{
   void delegate(int) dg;
   dg = 
}

See: https://run.dlang.io/is/iTYo2L


By design, I think.

"delegate and function objects cannot be mixed. But the standard 
function std.functional.toDelegate converts a function to a 
delegate."


Your example compiles if the assignment is changed to dg = 
toDelegate(); (given appropriate imports).


https://tour.dlang.org/tour/en/basics/delegates

https://dlang.org/phobos/std_functional.html#.toDelegate


Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread Robert M. Münch via Digitalmars-d-learn
Why does the follwing code give: Error: cannot implicitly convert 
expression & myFunc of type void function(int a) to void delegate(int)



void myFunc(int a){return;}

void main()
{
   void delegate(int) dg;
   dg = 
}

See: https://run.dlang.io/is/iTYo2L

--
Robert M. Münch
http://www.saphirion.com
smarter | better | faster