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

Ok, so I have an object, and one of the attributes is an array reference. I write an accessor method for that attribute that boths sets and gets the attribute. For setting, if I'm passed an arrayref, I just set it directly. If, however, I'm passed an array (of integers, hopefully), I want to set it as a reference to a copy of the original array.

So here's how I tried to do it:

sub foo { ### Shortened, assume we are passed something my $self = shift; ### some stuff $self->{bar} = ref( $_[0] ) ? $_[0] : \@_; ### a couple more things }


Seems simple, right? But it doesn't work. $self->{handle} is set to what it should be, and maintains that value for the rest of the sunroutine. But as soon as the subroutine returns, $self->{handle} now points to an empty array!

Of course, this can be gotten around rather easily (It's understanding, not a solution, I'm looking for), but I'm concered that it reveals a deep misunderstanding about the use of references and subroutines. If anyone could explain why I get this behaviour, I would certainly be in their debt.

Replies are listed 'Best First'.
Re: Wierdness with a reference to @_
by chromatic (Archbishop) on Jul 01, 2000 at 00:09 UTC
    Postulate: because @_ is a magic variable. Witness two different approaches which worked for me:
    sub foo { my $self = shift; my @args = @_; $self->{bar} = ref ( $_[0] ) ? $_[0] : \@args; }
    (my preferred approach)
    sub foo { my $self = shift; $self->{bar} = ref ( $_[0] ) ? $_[0] : [ @_ ]; }
    My suspicion is that @_ gets clobbered (or unset) as soon as you leave the subroutine due to internal Special Magic. You're left holding a reference to an empty variable. Either copy the values out of it, or expand it into an anonymous list.
Re: Wierdness with a reference to @_
by mdillon (Priest) on Jul 01, 2000 at 00:06 UTC
    using the \ (reference) operator does not refer to a copy of the original array, but to the array itself, so whatever is populating @_ must empty it afterwards. i believe this is because it uses a mechanism along the lines of local. to take a reference to a copy of your array, do the following: $self->{bar} = ref($_[0]) ? $_[0] : [ @_ ]; this copies @_ into an anonymous array and returns a reference.
RE: Wierdness with a reference to @_
by merlyn (Sage) on Jul 01, 2000 at 03:30 UTC
    In my experience, subroutines that have the behavior you are creating are "too smart" and cause me no end to grief later. Either make it take a list, or an arrayref, but not both.

    -- Randal L. Schwartz, Perl hacker