Page 1 of 1

❌ [a108] Lambda expression unable to capture a for-loop's variables

Posted: 07 Dec 2019, 18:47
by lvalkov
Not a bug as per:
lexikos wrote:
07 Dec 2019, 19:02
Variables are captured by reference...

Given an Array A, for each element, store a capturing lambda in Array B. Later, invoke them, yielding the following erroneous results:

Code: Select all

A := [1, 2, 3]
B := []

for item in A
	B.Push(() => MsgBox(item))

%B[1]%() ; MsgBox(''), expected MsgBox('1')
%B[2]%() ; MsgBox(''), expected MsgBox('2')
%B[3]%() ; MsgBox(''), expected MsgBox('3')

Introducing a temp variable yields the following:

Code: Select all

A := [1, 2, 3]
B := []

for item in A
{
	temp := item
	B.Push(() => MsgBox(temp))
}

%B[1]%() ; MsgBox('3'), expected MsgBox('1')
%B[2]%() ; MsgBox('3'), expected MsgBox('2')
%B[3]%() ; MsgBox('3'), expected MsgBox('3')

Reverting back to Func/Bind resolves the issue:

Code: Select all

A := [1, 2, 3]
B := []

for item in A
	B.Push(Func('MsgBox').Bind(item))

%B[1]%() ; MsgBox('1'), expected MsgBox('1')
%B[2]%() ; MsgBox('2'), expected MsgBox('2')
%B[3]%() ; MsgBox('3'), expected MsgBox('3')

Re: [a108] Lambda expression unable to capture a for-loop's variables

Posted: 07 Dec 2019, 19:02
by lexikos
Variables are captured by reference, not by value. There is only one variable named item, not one for each iteration.

This is a common mistake in Javascript. One small difference here is that when our for-loop completes, it restores the variable to the value it had prior to the loop (nothing), so you get nothing instead of the very last item.

Re: [a108] Lambda expression unable to capture a for-loop's variables

Posted: 08 Dec 2019, 09:44
by lvalkov
Okay, I will work around this using Func/Bind or nested function wrappers.

Re: ❌ [a108] Lambda expression unable to capture a for-loop's variables

Posted: 09 Dec 2019, 11:18
by joefiesta
@Ivalkov : It would be nice if you posted code that actually executes.

Re: ❌ [a108] Lambda expression unable to capture a for-loop's variables

Posted: 10 Dec 2019, 00:34
by lvalkov
@joefiesta
Each of the code samples, submitted thus far, can be run in isolation and is guaranteed to, at the very least, 'execute' on the version targeted by this bug report.
I have settled on resolving my issue using Func/Bind. If you are looking for an example of that, look no further than code sample #3 in my original post.

If you are looking for an example using nested function wrappers:

Code: Select all

f() {
	A := [1, 2, 3]
	B := []

	g(x) => B.Push(() => MsgBox(x))

	for item in A
		g(item)

	return B
}

B := f()
%B[1]%() ; MsgBox('1'), expected MsgBox('1')
%B[2]%() ; MsgBox('2'), expected MsgBox('2')
%B[3]%() ; MsgBox('3'), expected MsgBox('3')