Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autovivification doesn't work even as lvalue

I have this simple code:

#!/usr/bin/perl
@inp = map 2**$_, 0..6;
@cc = grep {
    my $num = $inp[$_];
    my $sum;    #---- HERE, I have to have the var declared first, before init.
    $sum += $_ for (split //, $num);
    print "$sum\n";
    $sum % 2;
    } 0..$#inp;

Here, the $sum will be used in for loop, However in this case:

#!/usr/bin/perl
@inp = map 2**$_, 0..6;
@cc = grep {
    my $num = $inp[$_];
    my $sum += $_ for (split //, $num); # HERE, Trying to autovificate - wont work
    print "$sum\n";
    $sum % 2;
    } 0..$#inp;

But when I used var $sum at the same line with for loop - that means I am trying to declare and initiate at once - where should work the autovivifaction - As i would expect to autovivificate the $sum to zero (because used with math operator +=), but will not work, but why so? What are the rules for autovivification?

like image 242
Herdsman Avatar asked Feb 17 '26 07:02

Herdsman


2 Answers

This is not autovivification. You have a syntax mistake. If you had use strict and use warnings turned on, it would be more obvious.

The post-fix for construct treats the left-hand side like a block. So there is a scope for the body of the loop. Therefore you are declaring your my $sum inside that loop body scope, and it's not visible outside.

If you turn on use warnings, you'll get Use of uninitialized value $sum in concatenation (.) or string at ... line 6, which is the print after.

You need to declare the variable first (and use strict and warnings!).

like image 123
simbabque Avatar answered Feb 20 '26 02:02

simbabque


my has two effects:

  • At compile time, my declares the variable.
  • At run time, my allocates a new variable. More or less.

The first effect is what allows you to refer to the variable until the end of the enclosing block.

The second effect means $sum can't possibly hold the sum at the end of the loop since you call my to create a new variable each pass of the loop.


[ Warning: This section discusses Perl's guts. Feel free to jump ahead. ]

But why is it undef instead of containing the number from the last pass?

Well, that's cause my doesn't actually allocate a new variable when executed. It places an instruction on the stack to allocate a new one on scope exit!

The for statement modifier creates a lexical scope so that $_ can be properly restored when the statement is complete, so my $sum is replaced with a fresh variable at the end of each loop pass. (It's technically only being cleared rather than deallocated and reallocated thanks to an optimization.)


Your code could be written as follows:

#!/usr/bin/perl

use strict;
use warnings;

sub sum { my $acc; $acc += $_ for @_; $acc }

my @inp = map 2**$_, 0..6;
my @cc = grep { ( sum split // ) % 2 } @inp;

or even just

my @cc = grep { ( sum split //, 2**$_ ) % 2 } 0..6;

Always use use strict; use warnings;. Note that use warnings; would have made it more obvious that something was going wrong.


By the way, I don't know what you think autovivification means, but it's wrong.

Autovivification is the creation of a variable and a reference to it when deferencing an undefined value.

$ perl -e'
   my $x;
   CORE::say $x // "[undef]";
   $x->[0] = 123;
   CORE::say $x // "[undef]";
'
[undef]
ARRAY(0x35d7f56740)

Less formally, it could also refer to the creation of hash or array elements when using them as lvalues.

$ perl -e'
   my $x;
   CORE::say exists($h{x}) ? 1 : 0;
   my $ref = \( $h{x} );
   CORE::say exists($h{x}) ? 1 : 0;
'
0
1

There's no attempt to autovivify in your code.

like image 42
ikegami Avatar answered Feb 20 '26 01:02

ikegami



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!