6
$\begingroup$

I am looking for something like "byref" assignment in programming languages.

Let's assume I have:

x1=x2=....=xn

if I want to change their values ( say to 3 ) I need to set all of them like:

x1=x2=...=xn=3

Is there any way that I can change just one value ( as xn=3 ), and all others change simultaneously?

For those who are familiar with programming languages it is easy to understand: assign x1..xn as "byref" and changing just one value, will change all others. In large assignments it will reduce a lot of the work load.

Is there any similar ways in the Mathematica?

$\endgroup$
  • $\begingroup$ A search for "pointers in Mathematica" turns up lots of discussion related to this question. Seems that it's more involved than it might appear at first glance due to the way Mathematica handles data typing. A workable solution is presented in this answer and a different approach is shown in this answer. $\endgroup$ – dionys Oct 1 '14 at 22:18
7
$\begingroup$

You can delay-set the variables of interest to a common variable:

Table[x[k] := m, {k, 10}];
m = 4;
Table[x[k], {k, 10}]
m = 3;
Table[x[k], {k, 10}]

which produces output

{4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
{3, 3, 3, 3, 3, 3, 3, 3, 3, 3}

This way, whenever m is altered, the rest of the x[k] adapt accordingly.

I'm not quite sure how to make it so that altering one of the x[i] alters the rest of the x[k], though. Maybe someone else can post an answer which handles that, in case the use of a common variable is somehow not usable for you.

$\endgroup$
6
$\begingroup$

You can "unify" several variables in the following way

x /: HoldPattern[x[k_] = val_] /; 1 <= k <= 10 := (shared = val)
x[k_] /; 1 <= k <= 10 && ValueQ[shared] := shared

x[2]
(* x[2] *)

x[3] = 1
(* 1 *)

x[9]
(* 1 *)

x[8] = 0
(* 0 *)

x[7]
(* 0 *)

x[2] = x[3] + 1   (* like shared++ *)
(* 1 *)

x[11]
(* x[11] *)

The same for uncounted variables is a bit more complicated

SetAttributes[unify, HoldAll];
unify[vars__] := If[Not@ValueQ@shared@Unevaluated[vars], 
     Function[v, v /: HoldPattern[v = val_] := (shared@Unevaluated[vars] = val);
       v /; ValueQ@shared@Unevaluated[vars] := shared@Unevaluated[vars],
         HoldAll] /@ Unevaluated@{vars};]

unify[a, b, c]

a
(* a *)

b = 1
(* 1 *)

c
(* 1 *)

unify[d, e]

d = 2
(* 2 *)

a  (* sets are independent *)
(* 1 *)

ClearAll[a, b, c] (* destruct unify[a, b, c] *)
ClearAll[d, e] 
$\endgroup$
  • $\begingroup$ +1, this definitely seems to better address the original question than my answer, although the pattern-matching syntax is pretty mind-bending! $\endgroup$ – DumpsterDoofus Oct 2 '14 at 0:57
  • $\begingroup$ Actually, do you think you could briefly explain the use of /: in your first example? I'm having trouble understanding the documentation page for TagSet. $\endgroup$ – DumpsterDoofus Oct 2 '14 at 1:23
  • $\begingroup$ Darn clever. Note that unify[a, f] doesn't work as perhaps desired: a = 4; a does not result in 4. (Executed in turn after the above.) OTOH, I don't really understand the OP's use case of having several identifiers refer to the same value (or variable). I thought "byref" had to do with function parameters.... $\endgroup$ – Michael E2 Oct 2 '14 at 1:53
  • $\begingroup$ @MichaelE2 "by ref" and "by value" are the two main parameter-passing strategies. Some languages implement both. What do you push into the stack when you are going to call a function? the parameter's values or the parameter's memory pointer? If the later, the receiving function code may alter the "variables" on the caller end (AKA side effects) $\endgroup$ – Dr. belisarius Oct 2 '14 at 4:43
  • $\begingroup$ @DumpsterDoofus It is almost like UpSet but with manually selected tag. It is a bad idea to redefine Set so I define UpValues for my variables. $\endgroup$ – ybeltukov Oct 2 '14 at 11:59
1
$\begingroup$

You could define a function which creates an array of n constant value

var[constant_, n_] := x = ConstantArray[constant, n]

For e.g we can make an array of size 5 having 3 as the constant value for all elements as follows

var[3, 5]
(*{3, 3, 3, 3, 3}*)

Since x is equated to this function you can call each array element as follows

x[[1]] 
(*3*)

So now if you want to change the constant from 3 to 4 you just call the function

var[4, 5]
(*{4, 4, 4, 4, 4}*)

This will effectively change all the x values

x[[1]] 
(*4*)
$\endgroup$
0
$\begingroup$

If xn has not yet a value,

x1=x2=...=xn

will set all variables to xn, and then if you do

xn=3

all of them will evaluate to 3.

If xn already has a value at the point of assignment, you can temporarily unset it using Block. For example

c=1
Block[{c}, a=b=c]
{a, b, c}
(*
==> {1, 1, 1}
*)
c=2
{a, b, c}
(*
==> {2, 2, 2}
*)

However, in that case the better option would be to do individual assignments using the standard SetDelayed:

a := c; b := c

This always works, even if c is already assigned a value.

Note however that this only works for assignments to c; assignments to a or b will not propagate to the other variables. To achieve that, you can additionally do

a /: (a=x_) := c=x

and the same with b. Basically this tells Mathematica that whenever it sees an expression of the form a=expression it should execute c=expression. Note however that this is not a catch-all; it doesn't cover other ways a might get a value assigned; the most obvious being :=. You'd have to find out a complete set of ways how a might be changed and write a replacement rule for each of them (assuming this is possible; in some cases, a might be buried too deeply in the expression). In the end, it's probably a better idea to just restrict assignments to be done on c.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.