in reply to Closures and scope of lexicals

The variable is captured (i.e. kept around), not the value.

I would not have expected this.

Weird. You read $i, but expect to get the value of something other than $i?

is this [...] something which can be found documented somewhere?

Closures are documented in perlsub. "If something more permanent is still aware of the lexical, it will stick around."

This means you can access the lexical beyond when it would normally be destroyed for going out of scope (which doesn't actually happen in your second snippet).

Reading the variable still gives its current value as usual.

is this a bug [...]?

Absolutely not.

Imagine if the following module didn't work because $i didn't get captured by get and set:

package Foo; my $i; sub get { $i } sub set { $i = shift; } 1
(These are true closures like your first snippet but unlike your second since $i goes out of scope at the end of the file before get and set are called.)

is this [...] a quirk [...]?

Absolutely not.

Same in JavaScript.

const subrefs = []; let i = 0; for ( let j = 3; j--; ) { i++; subrefs.push( function(){ console.log( i ); } ); } for ( const subref of subrefs ) { subref(); }
3 3 3

Same in C#

List<Action> subrefs = new(); int i = 0; for (int j = 0; j < 3; ++j ) { i++; subrefs.Add( () => Console.WriteLine( i ) ); } foreach ( var subref in subrefs ) { subref(); }
3 3 3

Same in Python

subrefs = [] i = 0 for j in range(3): i = i + 1 def subref(): print( i ) subrefs.append( subref ) for subref in subrefs: subref()
3 3 3

Replies are listed 'Best First'.
Re^2: Closures and scope of lexicals
by haj (Vicar) on Oct 31, 2024 at 15:32 UTC
    Closures are documented in perlsub. "If something more permanent is still aware of the lexical, it will stick around."

    That's the relevant pointer. Thanks! I should have found that by myself.

Re^2: Closures and scope of lexicals
by LanX (Saint) on Oct 31, 2024 at 14:07 UTC
    Tho python is still different IIRC.

    There is no block scope, variables live in a function or a file.

    In order to create a list of closure functions in a loop closing over different variables - like in the OP's first example - one would need to call an explicit generator function, having the var in its scope and returning the closure.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      But it's supposed to be file-scoped. $i is scoped to the file in the OP's code. Your suggested change would make the code different than the OP's code.

        I was referring to his first example which prints 123

        That's more complicated to achieve in Python IMHO.

        Edit

        I think JS had a similar effect with var , that's why let was introduced

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery