[comp.lang.perl] Strange behavior with "local"

pem@frankland-river.aaii.oz.au (Paul E. Maisano) (03/18/90)

Maybe I'm missing something but this seems like strange behaviour to me.

----------cut-here---------
#!/usr/bin/perl

$buf = "original value";

&buggy($buf);
print "buf=$buf\n";

sub buggy {
    local($buf) = "new value";
    print "buf=$buf\n";
    $_[0] = $buf;
}
----------cut-here---------

Running this produces:
    buf=new value
    buf=original value

It looks like the global $buf does not get changed. It should, since scalars
are passed by reference and the last line in &buggy refers to the global
variable.

If I change the name of the local variable in &buggy, everything works as
expected; the global $buf gets changed.

It seems that the value of the $buf variable is being restored before the
subroutine is exited. 

I hope this is a bug, otherwise I have to be very careful about naming my
local variables.

I'm using perl 3.0 pl15 on a SUN3/60 and sparcstation-1.

------------------
Paul E. Maisano
Australian Artificial Intelligence Institute
1 Grattan St. Carlton, Vic. 3053, Australia
Ph: +613 663-7922  Fax: +613 663-7937
Email: pem@aaii.oz.au   UUCP: {uunet,mcsun,ukc,nttlab}!munnari!aaii.oz.au!pem

pem@frankland-river.aaii.oz.au (Paul E. Maisano) (03/19/90)

In article <1363@frankland-river.aaii.oz.au>, pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
> Maybe I'm missing something but this seems like strange behaviour to me.
> 
> ----------cut-here---------
> #!/usr/bin/perl
> 
> $buf = "original value";
> 
> &buggy($buf);
> print "buf=$buf\n";
> 
> sub buggy {
>     local($buf) = "new value";
>     print "buf=$buf\n";
>     $_[0] = $buf;
> }
> ----------cut-here---------
> 
> Running this produces:
>     buf=new value
>     buf=original value
> 
> It seems that the value of the $buf variable is being restored before the
> subroutine is exited. 

Sorry, I must be getting old... This is not strange behaviour at all.
$buf is being restored *when* the subroutine returns. This is the documented
behaviour of local.

> I hope this is a bug, otherwise I have to be very careful about naming my
> local variables.

This is clearly not a bug in perl but a bug in my brain.

However, this does demonstrate that due to the way local works you
must be careful about naming your 'local' variables if you are modifying
your arguments. The scenario is:
	You have a global variable called $buf.
	It calls a subroutine which alters $buf (by reference).
	[The subroutine knows nothing about the name of the variable.]
	The subroutine has a 'local' variable called $buf.
	When the subroutine exits, the old value of $buf is restored since
	we are no longer in the scope of the 'local'.
	Thus the new value of $buf is overwritten by the old value.
This seems IMVHO to be a misfeature, if the names of local variables
can affect the way the program runs.

Isn't there any safer way to implement local variables. Static scoping ?
I'd make some suggestions but I'm already too embarrassed by my last posting.

------------------
Paul E. Maisano
Australian Artificial Intelligence Institute
1 Grattan St. Carlton, Vic. 3053, Australia
Ph: +613 663-7922  Fax: +613 663-7937
Email: pem@aaii.oz.au   UUCP: {uunet,mcsun,ukc,nttlab}!munnari!aaii.oz.au!pem

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/20/90)

In article <1364@frankland-river.aaii.oz.au> pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
: However, this does demonstrate that due to the way local works you
: must be careful about naming your 'local' variables if you are modifying
: your arguments. The scenario is:
: 	You have a global variable called $buf.
: 	It calls a subroutine which alters $buf (by reference).
: 	[The subroutine knows nothing about the name of the variable.]
: 	The subroutine has a 'local' variable called $buf.
: 	When the subroutine exits, the old value of $buf is restored since
: 	we are no longer in the scope of the 'local'.
: 	Thus the new value of $buf is overwritten by the old value.
: This seems IMVHO to be a misfeature, if the names of local variables
: can affect the way the program runs.

It's never a problem unless you modify parameters passed by reference, which
is a slightly dangerous thing in almost anyone's book.  But here's a way
to do it.  It almost looks idiomatic, though the necessity for double brackets
I would consider to be a bug:

	#!/usr/bin/perl

	$buf = "original value";

	&buggy($buf);
	print "buf=$buf\n";

	sub buggy {
	    $_[0] = do {{
		local($buf) = "new value";
		print "buf=$buf\n";
		$buf;
	    }};
	}

: Isn't there any safer way to implement local variables. Static scoping ?
: I'd make some suggestions but I'm already too embarrassed by my last posting.

Some measure of static scoping is provided by the package declaration.
Perhaps that is what you want.  Now you only have to worry about package
name collisions...

However, picking one unique name for a package is a lot easier than picking
unique names for all your local variables, if you're going to be doing a lot
of reference parameter modification.  And it lets you have a package
of routines that can keep its own state between subroutine calls.

Since all characters of a package name are significant, you would be pretty
safe in saying:

	#!/usr/bin/perl

	$buf = "original value";

	&buggy($buf);
	print "buf=$buf\n";

	sub buggy {
	    package jaksopfqjiwofkslfdjkasljfklqowjedfikaxjajksdjfkalqpmvcmvxo;
	    local($buf) = "new value";
	    print "buf=$buf\n";
	    $_[0] = $buf;
	}

Randal would probably just say $buggy'buf all over.  But it's easier to
use the package declaration.  Especially if you use the package name above. :-)

Larry

merlyn@iwarp.intel.com (Randal Schwartz) (03/20/90)

In article <7470@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax (Larry Wall) writes:
| Randal would probably just say $buggy'buf all over.  But it's easier to
| use the package declaration.  Especially if you use the package name above. :-)

Well, no, it was an *afterthought* on that multidim code, because I
was running into the strange local() problems, and thought that
snarfing it into its own package would help.  It did. :-)

print "Just another Perl hacker," x "1no time to write a cute signature";
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/