Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Assign a reference to a non reference

by mystik (Sexton)
on Oct 03, 2002 at 11:32 UTC ( #202479=perlquestion: print w/replies, xml ) Need Help??

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

Hello all,

I want to do something like this:

sub foo { return ({},[]); } my (%baz, @bar); (\%baz,\@bar) = &foo();
but perl doesn't let me:
Can't modify reference constructor in list assignment at foo.pl line 5 +, near ");" Execution of foo.pl aborted due to compilation errors.
Is there a one liner to assign references into named non-reference vars?

Replies are listed 'Best First'.
Re: Assign a reference to a non reference
by fglock (Vicar) on Oct 03, 2002 at 11:36 UTC

    References are "normal" variables:

    sub foo { return ({},[]); } my ($baz, $bar); ($baz,$bar) = &foo(); print ref $baz," ",ref $bar,"\n";

    \%hash is a reference, but you can't do \%hash = $ref because \%hash is a constant.

    assign references into named non-reference vars

    %hash = %$baz; @array = @$bar;

      hrm, I figured \%hash couldn't be an lvalue .. :(

      I was trying to find an "elegant" way to fit this into someone else's code.

      I'm currently doing it like this:

      my @tmp = &foo(); %baz = %$tmp[0]; @bar = @$tmp[1];

      But if I can eliminate the need for @tmp, i'd be happy

        You just can't do it. Look at it from the other end, you're trying to return two lists. To assign them to two variables without using a temporary you must do a listwise assignment of the returned values. This means your code is going to look something like

        my (%baz, @bar) = foo();

        But that doesn't work with Perl, the two lists are flattened, and the first variable is in a winner-take-all situation. @bar gets nothing. At first I thought it was simply a matter of coercing on the fly

        my (%baz, @bar) = sub { %{$_[0]}, @{$_[1]} }->(foo());

        But that still doesn't work. To understand, have a look at what adding the following does:

        use Data::Dumper; sub foo { return ({J=>'A', P=>'H', }, [4.019,5.8]); } # ... original listy assignment here ... print Dumper(\%baz);

        There is a way around the problem of course, and that is to use references henceforth:

        my ($baz, $bar) = foo(); print "$baz->{J} $bar->[1]\n";

        This will do what you want, at the expense of having to dereference via ->. This may or may not be a problem to retrofit into your project.


        print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'
Re: Assign a reference to a non reference
by merlyn (Sage) on Oct 03, 2002 at 14:36 UTC
    Ugliness abounds, but this should do it:
    (%baz = %{$_->[0]}), (@bar = @{$_->[1]}) for [&foo()];
    I'm using $_ as a holder for an array ref to the return value.

    Hey, it's one line. No, I can't think of a quick idiom, unless you permit global variables:

    our (%baz, @bar); (*baz, *bar) = &foo();
    But mucking with the symbol table is generally bad form as well.

    -- Randal L. Schwartz, Perl hacker

Re: Assign a reference to a non reference
by antifun (Sexton) on Oct 03, 2002 at 14:08 UTC
    You're kind of stuck here.
    • Perl won't let you assign to the non-lvaluable thing you tried in your original example.
    • You'll have a lot of trouble doing something like
      (@a, %h) = anything()
      because @a will always get everything that is returned. (An artifact of the way perl handles nested list contexts.)
    • So that leaves you with something like
      ($href, $aref) = (@{&foo})
      which is basically what you came up with on your own.

    Once you've got the references, you can dereference them one at a time, as you are doing, but good luck trying to assign (copy) them all to "real" arrays/hashes at once because of that second point above. Anyone who knows any better than I do care to comment?
    ---
    "I hate it when I think myself into a corner."
    Matt Mitchell

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://202479]
Approved by ybiC
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2022-07-04 06:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?