0

Sometimes I'd like to make a function, which would take an argument "by reference" instead of usual "by value". This is semantically similar to what e.g. AppendTo does: changes the variable passed to it. But when I try to do this straightforwardly, I get:

myFunc[x_] := (Clear[x]; x = 1)
test = 0; (* dirty the variable *)
myFunc[test];

Clear::ssym: 0 is not a symbol or a string. >>

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

So, seems x is treated as "the value of x" inside the function. How do I change myFunc to treat x as "the symbol passed as x", so that it works like intended?

Ruslan
  • 7,152
  • 1
  • 23
  • 52
  • Also specifically addressed here: (18737) – Mr.Wizard Jan 28 '15 at 06:40
  • I think a better way to do this is to make a local variable in the module, assign that the value of the input, then make modification on the local variable, and return that at the end. This is in the spirit of how Mathematica programming is done. – Nasser Jan 28 '15 at 07:44
  • @Nasser of course, it was how I used to work around this. But Pickett's answer lets me do it more conveniently in some cases. – Ruslan Jan 28 '15 at 08:22
  • @Ruslan Could I ask why you want to assign a value to x (or its 'value' test) inside your function? I'm not saying you don't have good reason but to an external observer it just seems an odd thing to want to do. – Ymareth Jan 28 '15 at 09:13
  • @Ymareth the function may take multiple arguments to change, and not having to say {a,b,c}=f[a,b,c] is really convenient. After all, even the built-in AppendTo[v,val] is also nothing more than syntactic sugar over v=Append[v,val], but it's so useful. This can be compared to using x+=y instead of x=x+y. – Ruslan Jan 28 '15 at 09:37
  • @Ruslan I was wondering if you had a specific usecase. I agree its a useful thing to be able to do in very specific circumstances however, and I think its a serious however as it does, rather completely, break the functional programming paradigm that Mathematica is built for. I can't help but think such a style will bring you more problems rather than fewer. – Ymareth Jan 28 '15 at 09:40
  • @Ymareth my usecase was the following: I had several matrices, and wanted to zero nth column and nth row in each, so a function zeroCross[mat_,n_] would just do that. I'd then just do zeroCross[#,n]&/@{m1,m2,...,mk}. If it returned the changed matrix instead of changing the argument, this would change to {m1,m2,...,mk}=zeroCross[#,n]&/@{m1,m2,...,mk}, where mk is of course not a two-letter name. – Ruslan Jan 28 '15 at 09:45

1 Answers1

3

You give the function the HoldFirst or HoldAll attribute:

myFunc[x_] := (Clear[x]; x = 1)
SetAttributes[myFunc, HoldFirst]
test = 0;
myFunc[test];
test

1

C. E.
  • 70,533
  • 6
  • 140
  • 264