vincentaxhe has asked for the wisdom of the Perl Monks concerning the following question:

my @a; my $proto1 = \@a; my $proto2 = "@{\@a} 3 4"; @a = (1, 2); print "@{$proto1}", "\n"; #OUTPUT: 1 2 print $proto2; #OUTPUT: 3 4, not what I want
How could I properly write $proto2 to defer @a evaluation?

Replies are listed 'Best First'.
Re: set proto string
by cavac (Prior) on Aug 17, 2024 at 14:36 UTC

    That's not how Perl (or many other programming languages) work. The variable is filled at the time the assignment is done.

    What you probably want to achieve is that $proto2 is a reference to @a? Something like you've already done with $proto1.

    But when you assign $proto2, you are generating a string (a temporary scalar, technically) that is assigned to $proto2. $proto2 has no concept that its new value is derived from @a. To make $proto2 behave more like you want it to (though not exactly), you can make it a reference to an anonymous subroutine:

    #!/usr/bin/env perl use v5.38; use strict; use warnings; my @a; my $proto2 = sub { return "@{\@a} 3 4"; }; @a = (1, 2); print $proto2->(), "\n"; # prints "1 2 3 4"

    To make this more in line with your requirements (=evaluating the stuff on access), you can make $proto2 a tied variable. In this case, you also need to make @a accessible from other packages by declaring it "our" instead of "my". Basically, $proto2 is tied to a class (package) and runs its own logic:

    #!/usr/bin/env perl use v5.38; use strict; use warnings; package vincentaxhe; sub TIESCALAR { bless \my $self, shift } sub STORE { ${ $_[0] } = $_[1] } # remember the postfix string sub FETCH { "@{\@main::a} " . ${ my $self = shift } }; package main; our @a; tie my $proto2, 'vincentaxhe'; $proto2 = '3 4'; @a = (1, 2); print $proto2, "\n"; # prints 1 2 3 4 @a = (22, 23, 24); print $proto2, "\n"; # prints 22 23 24 3 4 $proto2 = 'Hello World'; print $proto2, "\n"; # prints 22 23 24 Hello World

    There are probably smarter ways to bind @a to $proto2 in a tied variable than hardcoding it. But it's Saturday and i need to go shopping for some food (shops are closed tomorrow), so i got limited time to spend on this.

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
    Also check out my sisters artwork and my weekly webcomics
      > There are probably smarter ways to bind @a to $proto2 in a tied variable than hardcoding it.

      First of all using a closure variable my @a is also possible in your example if it's in the same scope like sub FETCH

      Now provided that the package is an extra file, hence foreign scope, you can still pass arguments to the tie command, like a ref to \@a.

      See tie VARIABLE,CLASSNAME,LIST

      > Any additional arguments in the LIST are passed to the appropriate constructor method for that class--meaning TIESCALAR() , ...

      Edit

      But for flexibility and reusability I'd rather pass a coderef in LIST which acts as FETCH and returns the string.

      FETCH would access the coderef as an attribute of $self

      Hence for a package MyFetch tie $magic, MyFetch, sub { "@a 1,2" } would do and the numbers of closure variables would be totally free.

      That's the beauty of functional programming. :)

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

        Oh wow, it didn't even cross my mind that i could give the coderef to the tied variable.

        That only goes to show that i haven't played with tie for a long time and really should take some time to refresh my knowledge in that area. I actually had to look up a small tutorial on it just to write my very basic example.

        Thanks!

        PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
        Also check out my sisters artwork and my weekly webcomics
Re: set proto string
by LanX (Saint) on Aug 17, 2024 at 12:32 UTC
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: set proto string
by choroba (Cardinal) on Aug 19, 2024 at 09:46 UTC
    That's why String::Interpolate exists:
    #!/usr/bin/perl use warnings; use strict; use String::Interpolate; my @a; my $proto = 'String::Interpolate'->new({'a' => \@a}); @a = (1, 2); print $proto->('@a 3 4'); # 1 2 3 4

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      yes! god send you who know everything!