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

Evening! I'm trying to append to a scalar using a reference. I'm doing the same thing for an array which works, but this doesn't - isntead, it seems to have passed the reference name to my variable:
sub file_expansion { my ($output, $input) = @_; my $test = $output; # For testing whether I need to append + to an array or a scalar# while (<@$input>) { if (-e $_) { open (FILE, "< $_"); my @lines = <FILE>; foreach my $line (@lines) { $_ = $test; if (/SCALAR/) { $output .= $line; } else { push @$output, $line; } } } else { print "<<ERROR: File \'$_\' doesn't exist or c +an't be read.>>"; } } } @temp_fyle = "/home/monkey/list_of_commands"; (looks like below: interface blah ip address 1.2.3.4 255.255.255.255 ) &file_expansion(\$template,\@temp_fyle);
Ok, what I'd expect is that printing $output within the sub will result in the contents of the file being in there. What I'm finding, however, is that I get something like "SCALAR(0x828c810)interface blah ip address 1.2.3.4 255.255.255.255" And after exiting the loop, $template is empty. Obviously what's happening is that I've not referenced it properly and the $output variable actually has the scalar reference as its value rather than being a reference to the original scalar. What have I done wrong?
toeslikefingers.com - because you've got too much time on your hands

Replies are listed 'Best First'.
Re: referencing question
by gjb (Vicar) on Nov 06, 2003 at 12:59 UTC
    $$output .= $line;
    should do the trick, you forgot to dereference the reference to the scalar. For the list reference, you correctly used @$output though.

    Hope this helps, -gjb-

      Yup, a guy across the room just explained it. Finally getting to grips with all this referencing business. Also figured out that I should be using ref() rather than my dodgy 'assign reference to a string and test that' business with the '$test' variable.
      toeslikefingers.com - because you've got too much time on your hands
Re: referencing question
by hmerrill (Friar) on Nov 06, 2003 at 17:05 UTC
    When passing parameters, you want to pass scalars - which means you want to pass:
    * scalars as themselves * each array as an array reference (a reference is a scalar) * each hash as a hash reference (a reference is a scalar)
    so
    1. there is no reason to pass a reference to $template(a scalar) to the subroutine - why not just pass $template? Forget about the reference - then in the subroutine you can do my ($output, $input) = @_; and just use $output in the subroutine, instead of having to use $$output. 2. when you pass \@temp_fyle in the call to subroutine file_expansion, that's fine. This is just my preference, but IMHO it helps keep your code simpler and more understandable if you name variables consistent with what they contain. For example, in subroutine file_expansion, name the imcoming parameter that is a reference to the array what it is - a reference, like this: my ($output, $input_arrayref) = @_; or maybe even better my ($output, $temp_fyle_arrayref) = @_; Then, since you can actually use the reference to point at array elements (instead of having to dereference the array reference into an array), you can do something like this print "first element is $temp_fyle_arrayref->[0]\n"; to refer to the 1st element of the array, instead of having to do my @new_array = @$temp_fyle_arrayref; my $first = @new_array[0]; print "first element is $first\n"; which takes more memory since you are creating another array(@new_array).
    HTH.
      hmerrill: I was under the impression that if you had very large scalar (e.g. $template contains a 100kb template) it was more efficient to pass a reference than to pass the whole scalar, since no memory is being copied. Or am I confused on this point?
        No, your impression is probably correct - I've never really used scalars with really *large* values, so that's probably why I didn't think of that. In that case, you *should* probably pass a reference to the scalar like you were doing in the first place. Sorry if I confused you.