[comp.lang.perl] Passing scalars by reference

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

Could someone please tell me how I can pass scalars by reference in the
same way arrays are. I know I can refer to $_[nnn] like its says in the
manual, but I would like to do something like:

sub foo {
    local($x_by_ref_with_meaningful_name) = $_[0];
    ...
    $x_by_ref_with_meaningful_name .= $foo;	# update the original scalar
}

I tried this and it seemed to work on the first call only. Thereafter
it updated a global variable called $x_by_ref_with_meaningful_name.

Hopefully it's not a bug and I'm just doing something wrong.
It's happening on both SUN-3's and sparcstations, pl 12.

------------------
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/07/90)

In article <1220@frankland-river.aaii.oz.au> pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
: Could someone please tell me how I can pass scalars by reference in the
: same way arrays are. I know I can refer to $_[nnn] like its says in the
: manual, but I would like to do something like:
: 
: sub foo {
:     local($x_by_ref_with_meaningful_name) = $_[0];
:     ...
:     $x_by_ref_with_meaningful_name .= $foo;	# update the original scalar
: }
: 
: I tried this and it seemed to work on the first call only. Thereafter
: it updated a global variable called $x_by_ref_with_meaningful_name.

That won't do what you want, because local($scalar) = @_ will always copy the
value--it's how you turn call-by-reference into call-by-value in Perl.

There are several ways for you to reference the original scalar:

	1) Give up on giving a meaningful name and refer to $_[0].

	2) Invoke the C preprocessor and say

		#define meaningful_name _[0]

	3) Use the type glob *name to pass in the symbol name:

		sub foo {
		    local(*meaningful_name) = $_[0];
		    $meaningful_name .= pop(@meaningful_name);
		}

		&foo(*original_name);

This last method is the most powerful, because you can pass anything that has
a name in the symbol table, including filehandles, subroutines and formats.
What you're really doing is passing in the symbol table entry for everything
with that name and giving it a new name locally.

Note that mechanism 1 can only give you references into an array's elements,
while mechanism 3 can give you the array as a whole, so you can push, pop,
shift, etc. on it.

Larry

tneff@bfmny0.UU.NET (Tom Neff) (03/07/90)

In article <7293@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>	3) Use the type glob *name to pass in the symbol name: ...
>
>This last method is the most powerful, because you can pass anything that has
>a name in the symbol table, including filehandles, subroutines and formats.
>What you're really doing is passing in the symbol table entry for everything
>with that name and giving it a new name locally.

Also note something not covered explicitly in the manual:  This is the
only way you can pass multiple arrays to a subroutine without effectively
concatenating them into one amorphous array.

For example if I want to be able to say

	@Questions = ("who", "what", "why");
	@Answers = ("us", "this", "because");
	@Weights = ("40", "35", "25");

	$score = &process_one_quiz($pupil, @Questions, @Answers, @Weights);

I cannot just say

	sub process_one_quiz {
		local ($p, @Q, @A, @W) = @_;
		...
	}

because @Q eats the rest of the @_ array including answers and weights.
(The parameter list is ONE list.)  But if I say

	sub process_one_quiz {
		local ($p, *Q, *A, *W) = @_;
		for $i ($[..$#Q) {
			print "$Q[$i],$A[$i],$W[$i]\n";
			# (real work deleted)
		}
	}

	$score = &process_one_quiz($pupil, *Questions, *Answers, *Weights);

then everything works right.

Thus pass-by-reference can be an important tool for passing arrays even
when the subroutine has no need to modify any elements.  (Larry might
want to mention this in the manual.)
-- 
To have a horror of the bourgeois   (\(    Tom Neff
is bourgeois. -- Jules Renard        )\)   tneff@bfmny0.UU.NET

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

Thanks for the explanation Larry. It's clear what I was doing wrong now.

> : sub foo {
> :     local($x_by_ref_with_meaningful_name) = $_[0];
> :     ...
> :     $x_by_ref_with_meaningful_name .= $foo;	# update the original scalar
> : }

That was just a slip, what I meant to write was:

sub foo {
    local(*x_by_ref_with_meaningful_name) = $_[0];
    ...
    $x_by_ref_with_meaningful_name .= $foo;	# update the original scalar
}

I had tried this. I was however calling foo incorrectly, as in
	&foo($real_name) instead of &foo(*real_name).

The thing that threw me off track was that this actually works, once.

I would be interested in knowing why this happens.

------------------
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