## How to modify function argument?

38

24

Usually in programming languages, function arguments are normal local variables, which can be modified.

Is this not true in Mathematica?

In[94]:= TTT[x_] := Block[{},
x += 2
];

In[95]:= TTT[3]


During evaluation of In[95]:= AddTo::rvalue: 3 is not a variable with a value, so its value cannot be changed. >>

Out[95]= 3 += 2


Is it possible to simulate normal argument behavior somehow?

2Like this? SetAttributes[rasher, HoldFirst]; rasher[x_] := x = x + 1; a = 2; rasher[a]; a – ciao – 2014-02-14T03:48:30.580

@PeeterJoot That one looks good to me, I wouldn't have written the answer if I had found that one ... – Szabolcs – 2014-02-14T04:23:47.660

My question also looks like it is answered by: http://mathematica.stackexchange.com/questions/23800/pass-by-reference-for-an-option-argument

– Peeter Joot – 2014-02-14T04:23:55.643

1

Relevant(?): http://mathematica.stackexchange.com/a/2677

– Oleksandr R. – 2013-01-14T19:14:50.767

@OleksandrR. I think so! And yet another one of a similar kind. I'll probably later add these links to my answer.

– Leonid Shifrin – 2013-01-14T19:20:44.810

@LeonidShifrin ah, I'd forgotten about that answer of yours. Very good solution... nice to see it again! – Oleksandr R. – 2013-01-14T19:44:38.733

Also related: (3269), (4126), (9078), (13662)

– Mr.Wizard – 2013-01-15T04:41:57.790

@Mr.Wizard I don't think that one is quite a dupe (and I am saying it not because I also got an accepted answer there). If that one would have been asked after this one, then indeed, my answer here covers that case as well, albeit more schematically. Given things as they are, I would just include a link to that question / answer in my answer here, and perhaps also vice versa (more or less what rm -rf suggested). Thanks also for the other links - I wasn't aware of all of them. I'll have a second look and perhaps include at least some into my answer. – Leonid Shifrin – 2013-01-15T09:55:51.273

## Answers

59

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

3Congrats on hitting 30k ! – Artes – 2013-01-14T18:04:17.267

@Artes Thanks man! – Leonid Shifrin – 2013-01-14T18:05:09.840

1Welcome to the 30k club! The club just became 100% more awesome :) – rm -rf – 2013-01-14T18:35:40.847

@rm-rf Thanks, buddy! I thought you and Mr.Wizard would be too lonely there without me :) – Leonid Shifrin – 2013-01-14T18:42:08.540

Mr.Wizard is now the lonely one in his exclusive 40k club =) Alas, time is too tight to be able to keep pace with him like I used to (and the same goes for you, Sz and Heike) – rm -rf – 2013-01-14T18:45:06.290

@rm-rf Right... gone are the good old days. But also I left my rep ambitions on SO. If there is any such interest I still (may be) keep it is more in the high average vote count and high ratio of silver to bronze badges, rather than their absolute numbers :). – Leonid Shifrin – 2013-01-14T18:50:05.880

Ah, yes... the badge tally :) You do have a very high average rep count for someone who has posted as many answers as you have (it's easier to be at the top when one has only 20 posts)

– rm -rf – 2013-01-14T19:00:13.277

@rm-rf B.t.w., I was just notified that I also joined the Epic club, inhabited until now by Mr.Wizard and Szabolcs. Will be waiting for you there :-) – Leonid Shifrin – 2013-01-14T19:00:48.037

@rm-rf Looking at the list of people in that table, don't you think that this is a good criteria? I am pleased to be there in such a company. – Leonid Shifrin – 2013-01-14T19:02:56.817

I only need 5 more 200 rep days to get there and it has been that way for several months now... unfortunately I spend more time on janitorial/mod work than answering these days. Have a conference deadline coming up soon, so might be able to blast a few 200+ days after that – rm -rf – 2013-01-14T19:03:02.513

@rm-rf I am sure it won't take you long to get there once you get some time on your hands. Also, sometimes one is just lucky to answer some question that gets a lot of votes, so this may actually require less time/effort than you think now. – Leonid Shifrin – 2013-01-14T19:04:54.257

Re: the table, most certainly! I've always considered this to be a more important criterion (and used this query even when on SO). Our site got into data.SE only very recently, so there wasn't much talk of it before. – rm -rf – 2013-01-14T19:05:05.057

@rm-rf I wonder how we fare on SO regarding this query, at least those of us who were on SO for a fair amount of time. – Leonid Shifrin – 2013-01-14T19:06:56.110

@rm-rf B.t.w., thinking about it, the reason that it may be easier to get a higher average vote count with fewer posts seems to be that this is also not an ideal metric. A yet better metric would likely be the power of the power law of the distribution of vote counts for a single person, but my guess is that the power law becomes really applicable only for a large enough number of answered questions, so that there are long enough tails (assuming that the power law holds indeed, but I have a hunch that this is generally true). A good question for M.SE? – Leonid Shifrin – 2013-01-14T19:26:37.217

All this talk of 30k and 40k club reminded me of the real xk club champion: https://www.google.com/search?q=wilt+chamberlain+women

– telefunkenvf14 – 2013-01-14T19:53:36.530

@LeonidShifrin I'm trying to get someone in the SE mod/community team to modify a data.se query for SO mma tag. I distinctly recall having used a query explicitly for that purpose, but I can't find it (search on data.se is terrible). Re: power law, there might not be sufficient data from our site, but you might be interested in this blog post

– rm -rf – 2013-01-14T20:01:13.947

It is interesting to note that this is normal behavior for most functional languages: variables once set are immutable, and that counts for parameters, too. – rcollyer – 2013-01-15T02:32:41.020

@rm-rf amusing "rep" discussion above. I haven't looked but I'm probably near the bottom of the average vote table. I'm sure I could keep a much higher average if that were my goal but I prefer to post anything and everything that I think may be of interest and answer questions that I know nobody cares about, a behavior which has amusingly landed me in the "first rank" position despite my lack of expertise. I'm the first to say that Leonid is The Mathematica Professor and is, was, and will be in a league well beyond me. – Mr.Wizard – 2013-01-15T03:01:09.597

@Mr.Wizard Lower, yes, but that's still relatively high for someone who has posted ~800 posts! Besides, that script uses just the reputation and doesn't take into account all your lost rep. So your actual number should be much higher. Btw, "lack of expertise"? LOL! – rm -rf – 2013-01-15T03:07:37.690

@rm-rf If it doesn't count votes over the cap that's not fair. I mean I didn't get any "rep" for this answer because it was after the cap. Leonid probably loses more as he has had quite a few 20+ answers, and this one's destined to be another. Speaking of which, although it's plainly appreciated I'm sure this question is a duplicate, though I haven't found the original I'm looking for yet. I wonder how to handle this; a merge will likely rob someone of an Accept, but closing is a loss too...

– Mr.Wizard – 2013-01-15T03:14:10.527

@Mr.Wizard Probably leave both open with cross links to the other in the comments? I didn't write that script and it's only to get a rough estimate anyway. Btw, I did look at rep w/o rep caps and from memory, you were ~53, I was at ~37, Leonid ~33 and Szabolcs ~31. Clearly, you've lost the most followed by Szabolcs. I always stop answering after I hit the cap and do other routine site stuff, so anything I've accrued over the cap is accidental. However, there's going to be absolutely no change to this rule, as even Jon Skeet's (~1.8 mil) plea to abolish/raise the cap was declined... twice :) – rm -rf – 2013-01-15T03:25:37.180

@rm-rf and Leonid: since my proposed duplicate (see question comments) is also answered by Leonid I propose merging these questions rather than keeping both open and linking them. I think the remaining question could easily be edited into The Canonical Question. Please give me your thoughts. – Mr.Wizard – 2013-01-15T04:46:02.190

@Mr.Wizard I'm not for merging, because this question is minimal and to the point and Leonid's answer here is more comprehensive (and popular). I would instead suggest closing the older one as a duplicate of this. – rm -rf – 2013-01-15T05:37:35.690

@rm-rf I thought the two questions could be combined into a canonical post as has been suggested previously by others. Leonid is the perfect choice to write such answers, and in this case he already has. Closing is fine too as it directs people to the new/other question more forcefully than simply putting a "Related: ..." link in the comments. Whatever the case I'd like to get one master post we can tag with faq or whatever and close-as-duplicate any new questions which relate to it. To that end the question (and it's answer(s)) should include both the basic case (continued) – Mr.Wizard – 2013-01-15T06:16:10.593

such as this one, and the more complicated ones such as a couple of the "Related:" ones I linked. – Mr.Wizard – 2013-01-15T06:16:42.777

@rm-rf Thanks for the blog ref. Interesting, although the author was concerned with a different thing. The post was giving some good data analysis, but a bit shallow on the conceptual side. It was more like what I'd expect from a data scientist rather than a mathematician. In any case, Physics rules. – Leonid Shifrin – 2013-01-15T10:28:51.410

9

Short answer: You need to set the attribute HoldAll on your function to prevent the variable to be modified from being changed into its value before it's substituted into the assignment. See long answer below.

AppendTo has this attribute (see Attributes[AppendTo]).

In other languages, pass by reference is used for two purposes:

1. avoiding copying large data structures

2. enabling the function to modify its arguments

Number (1) is not necessary in Mathematica. Mathematica handles data structures in a copy-on-write like manner so data structures are not duplicated when references from several locations or when passed to functions. For more information see Share.

Number (2) is what you are asking about in your question. To enable a function to modify its argument in Mathematica, it must not evaluate its arguments by default.

Suppose we'd like to create a function that increments a variable by 1:

increment[x_] := x = x+1


If we evaluate a=2; increment[a] now, this is what happens:

1. a gets evaluated to 2
2. increment[2] gets evaluated to 2 = 2+1
3. 2+1 gets evaluated to 3
4. We end up with 2=3 which yields an error as an integer can't be assigned to.

You can see this by looking at the output of TracePrint[increment[a]].

Clearly, we need to prevent a from evaluating to 2 before it gets substituted into x=x+1. This can be achieved by setting the attribute HoldAll on increment.

If a function has the attribute HoldAll, its arguments will not be evaluated before the function itself. Se we need:

SetAttributes[increment, HoldAll]
increment[x_] := x = x + 1


Now the evaluation sequence for increment[a] is:

1. increment[a] --> a = a+1
2. a+1 --> 2+1
3. 2+1 --> 3
4. a = 3

... and a is set to 3, i.e. incremented by 1!

Thanks. I ran into this problem when trying to update a list passed as a parameter. Somehow I had managed to avoid the idea of the HoldAll attribute until today :-) The error message (and on-line help) kind of made it clear what the problem was. I had to come here to find a fix. – Jyrki Lahtonen – 2020-05-08T14:51:51.443

7

First off, there is no use for your Block as you don't specify which variables you're localizing

Secondly, MMA will evaluate the inner expression x before it evaluates the outer one TTT[x] unless you specify otherwise. That's why it replaces the x with the 3 inside the function.

Try

SetAttributes[TTT, HoldFirst];
TTT[x_]:= (x+=2);


Finally, in your particular example, you tell MMA to use the number 3 inside the function, with TTT[3]. No programming language I know allows you to redefine integers. Instead, attach a symbol to 3, then try the following:

x = 3;
TTT[x];
x == 5
(* True *)


Edit: It occurred to me that what you may have wanted when calling TTT[3] is something similar to pass-by-value, but creating a local symbol with a unique name is probably the best way to do this in MMA (usually with a With).

2

I can't remember where I first saw this, but here is another way:

variable = "Old Value";
f[Dynamic[arg_]] := arg = "New Value";
variable
f[Dynamic[variable]];
variable


which works because Dynamic holds its first argument, as explained in the other answers. From the documentation for Dynamic,

Dynamic has attribute HoldFirst, so that expr is not evaluated until its value is needed for display.