From: James Stein on
I think the scanty procedures below show unexpected, perhaps buggy,
behavior.

These two procedures work as expected:
f assigns a value to a variable passed in by g:

*Input:*

ClearAll [f, g];
f [lhs_, rhs_] := lhs = rhs;
g[rhs_] := Module[{localVar},
f [localVar, rhs];
Print["g: localVar=", localVar];
];
g[44];


*(printed) Output:*

g: localVar= 44


But this method, where f receives the variable differently, fails:


*Input:*

ClearAll [f, g];
f [lhs_List, rhs_] := lhs[[1]] = rhs;
g[rhs_] := Module[{localVar},
f [{localVar}, rhs];
Print["g: localVar=", localVar];
];
g[44];


*(printed) Output:*

g: localVar=localVar$313085


In addition, there is an error message:

Set::setps :

(localVar$313085} in the part assignment is not a symbol.

which is curious because:

Head[localVar$313085] returns Symbol.


My motivation here is to allow a procedure to return one or more subsidiary
results in variables provided by the caller.


From: schochet123 on
Set ( = ) does not evaluate its first argument (the lhs) by default,
so you need to use Evaluate to tell it to do so. Just replace
lhs[[1]] = rhs by Evaluate[lhs[[1]]]=rhs

Steve

On May 8, 2:06 pm, James Stein <mathgr...(a)stein.org> wrote:
>
> But this method, where f receives the variable differently, fails:
>
> *Input:*
>
> ClearAll [f, g];
> f [lhs_List, rhs_] := lhs[[1]] = rhs;
> g[rhs_] := Module[{localVar},
> f [{localVar}, rhs];
> Print["g: localVar=", localVar];
> ];
> g[44];
>
> *(printed) Output:*
>
> g: localVar=localVar$313085
>
> In addition, there is an error message:
>
> Set::setps :
>
> (localVar$313085} in the part assignment is not a symbol.
>
> which is curious because:
>
> Head[localVar$313085] returns Symbol.


From: Leonid Shifrin on
Hi James,

The behavior you observed in not buggy and also not unexpected when you know
the mechanics of Mathematica evaluation.

You are obviously trying to implement pass-by-reference in your function
calls. To do that in Mathematica, you need to give your functions Hold* -
attributes, covering those arguments that you want to pass by reference. If
you don't, the arguments get evaluated before they are used in the body of
your function, and then instead of variables your function will work with
(often immutable) copies of their content (their values). Attempt to modify
these copies will often cause error messages.

Your first call is fine because the local variable does not have a value
initially, and because you only call <f> once. But try this for instance:

In[1] =
ClearAll[f, g];
f[lhs_, rhs_] := lhs = rhs;
g[rhs_] :=
Module[{localVar},
f[localVar, rhs];
f[localVar, rhs];
Print["g: localVar=", localVar];];
g[44];

Set::setraw: Cannot assign to raw object 44. >>

g: localVar=44

And, sure enough, you get an error since by the time we call <f> second
time, your <localVar> already has a value. Since <f> did not hold its
arguments, localVar evaluated to that value, and the second call was then
completely equivalent to calling f[44,44].
Fixing the behavior in the first case is easy: just set a HoldFirst
attribute for <f>: SetAttributes[f, HoldFirst];, and it will work.

Fixing the second example is harder, because when you use assignment of the
form expr[[1]] =rhs, (so called Part assignment), Mathematica expects <expr>
to be a Symbol whose value (technically called OwnValue) is a list (or,
more generally, normal expression which has a first part). In your case, you
have not a symbol but an expression {localVar}, so this won't work even when
we fix the problem with Hold*-attributes.

There are several ways to fix this, but which one is best depends on what
exactly you wish to accomplish. Generally pass-by-reference is discouraged
in Mathematica programming (there are exceptions), and in any case to
implement it in less trivial cases (like your second one) you will need to
understand the Mathematica evaluation process and know how to work with held
expressions. I will show just one example: a function that takes a list of
values and a sequence of variables of the same length, and assigns values
to variables:

ClearAll[setMany];
SetAttributes[setMany, HoldRest];
setMany[values_List, vars___] /;
Length[values] == Length[Hold[vars]] :=
Set @@ Hold[{vars}, values]

This uses the special form of simultaneous assignment available in
Mathematica, like {a,b,c} = {1,2,3}.

For example:

Clear[a, b, c];
setMany[{1, 2, 3}, a, b, c];
{a, b, c}

{1, 2, 3}

Here is how you could use it:

Clear[g];
g[rhs_] :=
Module[{localVar1, localVar2},
setMany[{rhs, rhs^2}, localVar1, localVar2];
Print["g: localVar1=", localVar1];
Print["g: localVar2=", localVar2]];


g[3]

g: localVar1=3

g: localVar2=9

You may want to look at

http://www.mathprogramming-intro.org/book/node173.html

and

http://www.mathprogramming-intro.org/book/node207.html

where I dwell on the topic of parameter-passing in Mathematica, and at

http://www.mathprogramming-intro.org/book/node205.html

where I try to explain what Hold attributes are. I however do not explain
how to work with held expressions. Working with held expressions is
explained well in the books of Roman Maeder (Programming in Mathematica),
and David Wagner (Power programming in Mathematica: the kernel). The latter
is unfortunately out of print.

Hope this helps.

Regards,
Leonid


On Sat, May 8, 2010 at 4:06 AM, James Stein <mathgroup(a)stein.org> wrote:

> I think the scanty procedures below show unexpected, perhaps buggy,
> behavior.
>
> These two procedures work as expected:
> f assigns a value to a variable passed in by g:
>
> *Input:*
>
> ClearAll [f, g];
> f [lhs_, rhs_] := lhs = rhs;
> g[rhs_] := Module[{localVar},
> f [localVar, rhs];
> Print["g: localVar=", localVar];
> ];
> g[44];
>
>
> *(printed) Output:*
>
> g: localVar= 44
>
>
> But this method, where f receives the variable differently, fails:
>
>
> *Input:*
>
> ClearAll [f, g];
> f [lhs_List, rhs_] := lhs[[1]] = rhs;
> g[rhs_] := Module[{localVar},
> f [{localVar}, rhs];
> Print["g: localVar=", localVar];
> ];
> g[44];
>
>
> *(printed) Output:*
>
> g: localVar=localVar$313085
>
>
> In addition, there is an error message:
>
> Set::setps :
>
> (localVar$313085} in the part assignment is not a symbol.
>
> which is curious because:
>
> Head[localVar$313085] returns Symbol.
>
>
> My motivation here is to allow a procedure to return one or more subsidiary
> results in variables provided by the caller.
>
>
>


From: Richard Fateman on
James Stein wrote:
....

>
>
> My motivation here is to allow a procedure to return one or more subsidiary
> results in variables provided by the caller.

I suggest you re-think this motivation, since it leads to subtle bugs,
and is probably difficult to do in Mathematica. I suggest you have a
routine return a list of values. You can pick them out this way..

> {a,b,c} = {1,2,3} assigns values to a and b and c.

This design abides more by functional abstraction.

I haven't looked at the details of your example, but Mathematica's
evaluation of names that are locally bound is a mess.

Good luck.


>

From: James Stein on
Leonid:

Thank you for your careful explanation; very helpful. I was mystified by the
error message, which seemed to complain that a symbol was not a symbol! But
now, it makes perfect sense!


Richard:

In my actual situation (not the simple case I described), the function in
question was already returning a list of values; which is why my misguided
idea occurred to me. Thanks for your sugestion.