6

I do not get to understand how the Perl read($buf) function is able to modify the content of the $buf variable. $buf is not a reference, so the parameter is given by copy (from my c/c++ knowledge). So how come the $buf variable is modified in the caller ?

Is it a tie variable or something ? The C documentation about setbuf is also quite elusive and unclear to me

# Example 1
$buf=''; # It is a scalar, not a ref
$bytes = $fh->read($buf);
print $buf; # $buf was modified, what is the magic ?

# Example 2
sub read_it {
    my $buf = shift;
    return $fh->read($buf);
}
my $buf;
$bytes = read_it($buf);
print $buf; # As expected, this scope $buf was not modified
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Alex F
  • 826
  • 8
  • 18

2 Answers2

11

No magic is needed -- all perl subroutines are call-by-alias, if you will. Quoth perlsub:

The array @_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable).

For example:

sub increment {
  $_[0] += 1;
}

my $i = 0;
increment($i);  # now $i == 1

In your "Example 2", your read_it sub copies the first element of @_ to the lexical $buf, which copy is then modified "in place" by the call to read(). Pass in $_[0] instead of copying, and see what happens:

sub read_this {
  $fh->read($_[0]);  # will modify caller's variable
}
sub read_that {
  $fh->read(shift);  # so will this...
}
pilcrow
  • 56,591
  • 13
  • 94
  • 135
0

read() is a built-in function, and so can do magic. You can accomplish something similar with your own functions, though, by declaring a function prototype:

sub myread(\$) { ... }

The argument declaration \$ means that the argument is implicitly passed as a reference.

The only magic in the built-in read is that it works even when called indirectly or as a filehandle method, which doesn't work for regular functions.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
  • 3
    You don't need a prototype or explicit passing-by-reference in order to modify a variable passed to a subroutine: `sub foo { $_[0] ++ }`. – FMc Jun 10 '10 at 05:24
  • +1 This isn't quite on point for the OP's question, but prototypes and *bona fide* perl references (not symbolic refs) are important to know in this domain. – pilcrow Jun 10 '10 at 13:56
  • @FM, good catch. I always forget that `@_` can be used that way. – JSBձոգչ Jun 10 '10 at 14:05