Intro
I will treat your question in a somewhat broader context of parameter-passing semantics in Mathematica in general. Many points of confusion here come from analogies and comparisons with more traditional languages, and it is important to realize that Mathematica uses entirely different (from most other languages) mechanisms for parameter-passing. Realizing this is not helped by the fact that there are significant syntactic similarities with other languages, however.
Parameter - passing semantics in Mathematica : pass-by-value via code injection
Parameter-passing semantics in Mathematica is different from many other languages. Parameters are passed by value, but if you dig deeper, functions are really rules, and parameters are simply injected into the body of a function, right before the body is evaluated. Depending on whether or not the function in question holds a particular argument, what is injected into its body is either the argument verbatim, or its value (meaning that the argument is first evaluated and only then injected, and then the body evaluates).
Whether or not the expressions passed as arguments can be modified inside a function depends on whether or not they represent an L-value (meaning they can be assigned a value, e.g. via Set
operator). I have a rather long section in my book which has a detailed discussion on that, but, to put the story short, for the following function:
f[x_]:=x=1
this will assign to a
:
Clear[a];
f[a]
while this will result in an error:
a=2;
f[a]
because in the first case, the symbol a
is injected into the r.h.s. (it is of course first evaluated, but since it does not have any value, it evaluates trivially, to itself), while in the second, it already has a value, so it's immutable value 2
is injected.
Note however, that this "injection" parameter-passing mechanism is highly unusual, from the point of view of traditional languages. In essence, parameter-passing acts as a code-generation device, assembling full function's code in a macro-like fashion from code pieces passed as parameters and the body which has "placeholders" and acts like a macro. One can say that in Mathematica, run-time code generation happens at each function invocation.
Emulating pass-by-reference via Hold
-attributes
When functions are given Hold
-attributes, they can emulate pass-by-reference semantics since they inject their passed arguments into their bodies verbatim, without first evaluating them. Therefore, giving f
the attribute HoldFirst
(for example), will lead to assignments in both cases.
ClearAll[f];
SetAttributes[f,HoldFirst];
f[x_]:= x = x + 5;
a = 5;
f[a];
a
(* 10 *)
f[a];
a
(* 15 *)
This is however only an emulation, since there are no pointers in Mathematica. One representative aspect of this emulation is that you can not "dereferece" a symbol holding a value. Nevertheless, for many tasks, such an emulation is sufficient.
Getting the behavior similar to other languages (such as C)
Finally, you can easily simulate the effect of local variables by assigning your passed parameters to Module
or Block
-local variables:
TTT[x_] := Block[{xl=x},
xl += 2
];
But in this case, the changes in those local variables will not affect the values of the parameters (just like this would be for function's parameters in C, for example). This behavior is probably the closest analog of how passed parameters belong in say C, where they are copied on the stack and become function's local variables.
The topic of name conflicts for passed parameters and local variables in actually more complex, and some of the associated behavior may be not very easy to understand at first. Mathematica documentation has an extensive coverage of these topics. I also discussed this topic in some more (compared to this answer) details here.
Summary
Parameter-passing in Mathematica is very different from that of many more traditional languages, in terms of core mechanisms involved (rules, run-time code generation). However, the syntax and partly behavior may look pretty close to what we have in other languages. It is important to understand the core mechanisms behind Mathematica's parameter-passing scheme, to better understand the differences and avoid unwanted surprises.
SetAttributes[rasher, HoldFirst]; rasher[x_] := x = x + 1; a = 2; rasher[a]; a
$\endgroup$