http://www.perlmonks.org?node_id=375371

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

Does anybody know how to get
use Lexical::Alias qw(alias); my @array; alias $array[0], $array[1]; $array[1] = 2; print "@array";
to DWIM? It prints " 2", and I would like "2 2".

P.S. Will Perl 6's runtime bindings do this?

Update: I should note that I tried alias_r \$array[0], \$array[1];, and it doesn't work either. Don't bother ;-)

-nuffin
zz zZ Z Z #!perl

Replies are listed 'Best First'.
Re: Aliasing values, not variables
by Corion (Patriarch) on Jul 18, 2004 at 13:01 UTC

    Sorry for not coming up with this ugly solution while you were asking about it in the CB:

    #!/usr/bin/perl -w use strict; sub alias{ \@_ }; my @a = (1,"world"); my $arr = alias( $a[0], $a[0], $a[1] ); $arr->[0] = "hello"; print "@$arr\n";

    I learned this ugly trick from demerphq while he was testing the aliasing features of his DDS module, so maybe looking at what the dumpers and their tests do might give you some more inspiration.

    Updated: Fixed typo in sub alias, spotted by nothingmuch

    Updated: I use strict; but the code won't run like that. That should teach me about posting when I don't cut'n'paste my code ... Spotted by The Mad Hatter

      I don't see how this helps the situation at all. He needs to alias one element of an array to another element of the array.

      Update: hrm, I didn't follow the code properly. Yes, this is a solution to problem. My apologies, Corion.

      _____________________________________________________
      Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
      How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

        It may well be that my solution misses the goal. As far as I understood it, nothingmuch wants two slots in an array to contain the same scalar, and I believe that my subroutine alias does that.

        The routine returns a reference to an array in which the elements are aliased as passed in. So to create an array which aliases the slots 2,3 and 4, you would call it as:

        my $v; my $ar = alias("foo","bar",$v,$v,$v,"baz");

        Assigning to any of the slots 2,3,4 of @$ar will change the other two slots as well, which is how I interpret the question.

        I might well have misunderstood the question and the problem, as I also don't understand what he needs it for, or rather, what he needs it for prompts different solutions to me.

Re: Aliasing values, not variables
by calin (Deacon) on Jul 18, 2004 at 18:31 UTC

    Lexical::Alias is not suited for this task. Try Array::RefElem instead:

    use Array::RefElem 'av_store'; my @array; av_store @array, 1, $array[0]; $array[1] = 2; print "@array";

    If you're bent on using Lexical::Alias, you can try the following trick for your particular situation, though it's of little use for generic array element aliasing. It's an answer to the first question from How's your Perl?, adapted to Lexical::Alias.

    use Lexical::Alias 'alias_a'; my @array; { my $t; alias_a @{sub {\@_}->($t, $t)}, @array; }

    Warning: code untested!. I don't have my laptop which has my custom Perl install with Lexical::Alias and Array::RefElem. Particularly the second example might not work as advertised.

    update: a monk confirms that code works on CB

Re: Aliasing values, not variables (indirecter)
by tye (Sage) on Jul 18, 2004 at 17:42 UTC

    \$array[0] gives you an alias to the value stored in that slot of the array, which is half of what you need. To make $array[1] an alias to that value, you need to get a pointer to the slot $array[1], which isn't a concept that is exposed to Perl scripts. It is almost like you want \\$array[1] except that that gives you a reference to a temporary scalar that points to the same value rather than a reference to the array slot (Perl doesn't support references to array slots).

    Lexical::Alias finds the extra layer of indirection by searching through internal structures (where the lexical variables are kept track of) until it finds a lexical that points to the same data that you passed it a reference to.

    There are other modules that can do this for arrays and hashes. So you can write XS code that you pass a reference to the array, the index to be made an alias, and a reference to (or alias of) the value to be aliased (for example).

    I know that demerphq's Data::Dump::Streamer needed this same functionality so I went to look up which module it used. But it looks like demerphq decided to roll his own replacements before he released the module (at least under that name). But you can just install Data::Dump::Streamer and use its alias functions:

    alias_av(@Array,$index,$var); uses prototypes to get a reference to the array you pass it and uses the fact that function parameters are aliases to the corresponding (scalar) arguments to get a reference to $var. Then it sets $Array[$index] to be an alias to $var.

    - tye        

Re: Aliasing values, not variables
by japhy (Canon) on Jul 18, 2004 at 16:28 UTC
    Update: I forgot about the magic aliasing power of @_. See Corion's branch in this thread.
    I believe part of the problem is that $array[$x] is not a lexical. Consider:
    my @data = (1 .. 5); { local $data[2] = 100; print_data(); } print_data(); sub print_data { print "@data\n"; }
    (Did you know you can use local() on elements in lexical aggregates?)

    But moreso, because the elements in aggregates do not have symbols, I do not think they can be aliased. I would expect Perl 6 would make this possible.

    _____________________________________________________
    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart