58
Preamble
This is a very good question, because answering it will make it very clear what immutability means, both in general and in the context of Associations.
General
A few general words on immutability
Associations are immutable data structures. This means that they carry no state, and a copy of an Association is another completely independent Association....
answered Jul 21 '14 at 23:19
Leonid Shifrin
107k1313 gold badges308308 silver badges399399 bronze badges
32
I believe Increment (more accurately PreIncrement as george2079 noted) is essentially this:
SetAttributes[inc, HoldFirst]
inc[a_] := a = (a + 1)
This exhibits the same behavior, e.g.
f[] := (Print[#]; #) &@RandomInteger[{1, 3}]
v = {0, 0, 0};
inc @ v[[f[]]];
2
1
Here f[] is evaluated twice because parameter a is used twice within Set. On the ...
answered Feb 17 '16 at 20:53
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
30
I hesitate to add anything after @Leonid's comprehensive answer, but I'd like to point out that an easy way to achieve the stated goal is to define f like this:
f[x_] := <| x, "isFirstValueTrue" -> x@"firstValue" |>
... which yields the desired result when mapped across the associations in x:
f /@ x
(* { <|"firstValue" -> True, "...
21
Update: Version 10 built-in function Values does value extraction conveniently for rules appearing in lists of arbitrary lengths and depths:
{{x1, y1}, {x2, y2}} = Values[Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}]]
(* {{(-11181-Sqrt[2242057])/74498,1/386 (13-Sqrt[2242057])},
{(-11181+Sqrt[2242057])/74498,1/386 (13+Sqrt[2242057])}} *)
...
21
You asked for a general explanation instead of just focusing on specific application examples, so here it goes ...
The concepts of "pass by reference" and "pass by value" that you may know from languages like C do not apply very well to Mathematica. Do not try to think in this framework.
The right question is not "how to pass by ...
18
General considerations
To my mind, the only robust way to do this is to build some custom object model in Mathematica, and in particular to restrict the way values can be changed to some well-defined route you can control. Because, as it follows from one of the discussions you linked to, there seems to be no reliable way to intercept arbitrary value changes ...
answered May 11 '14 at 18:10
Leonid Shifrin
107k1313 gold badges308308 silver badges399399 bronze badges
15
The reason is that AppendTo and PrependTo actually replace the whole list with a new one, rather than only changing a single element. In that sense, they are not really "in-place". They are in-place in the sense that the result gets assigned back to the same variable.
You can see using Trace, that AppendTo and PrependTo in fact expand:
bar[1]={4,3,2,1};
...
answered Jan 27 '15 at 19:21
Leonid Shifrin
107k1313 gold badges308308 silver badges399399 bronze badges
14
Turn off the warning
It should be noted that we can treat Set::nosym as a warning message rather than an error, and simply turn it Off:
Off[Set::nosym]
{i, _, j} = {1, 2, 3};
{i, j}
{1, 3}
throw-away Symbol
You could asko designate a Symbol for this purpose as a kind of dev/null, using e.g. $Post to clear it every time. I'll pick \[DoubleDagger], ...
answered Aug 9 '13 at 10:58
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
14
The problem here is that in Mathematica, parameters of a function are not local variables. So trying to modify a parameter of a function inside it's body will lead to an error. The reason is that function arguments are evaluated, when the function is called so that it is actually the result of this evaluation that's textually substituted for the function ...
14
Attributes[swap] = HoldAll;
swap[x_, y_] := {x, y} = {y, x};
x = 1;
y = 2;
swap[x, y];
{x, y}
{2, 1}
There are two characteristics of this code worth noting. The first is the HoldAll Attribute:
How do I treat elements in a list as variables inside a module?
When should I, and when should I not, set the HoldAll attribute on a function I define?
Pass ...
answered Feb 7 '17 at 21:12
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
14
I think the best way to understand this behavior is with this example,
In[99]:= x = {a, b, c, d, e};
In[101]:= Length@x
Out[101]= 5
In[102]:= x[[3]] = Nothing;
In[103]:= Length[x]
Out[103]= 4
In[104]:= Block[{Nothing}, Length[x]]
Out[104]= 5
When you say x[[3]] = Nothing, you are not deleting an element from x. x is still a 5-element list. But x is ...
13
This is an old discussion but is about an issue that resurfaces every now and then. One of the best (for a given sense of elegance) answers is the one posted on Stack Overflow
ClearAll[f]
SetAttributes[f, HoldAllComplete]
f[a_, b_, c_] := {
ToString@Unevaluated@a,
ToString@Unevaluated@b,
ToString@Unevaluated@c
}
f[a__] := Function[x, f[a, x], ...
13
Utilizing ValueFunction as mentioned here, we could do something like this:
SetAttributes[Observe, HoldFirst];
Observe[s_Symbol, fn_] :=
With[{VF := Experimental`ValueFunction[s]},
VF =
If[ValueQ @ VF,
ReplacePart[VF, {2, 2, 2} -> Append[VF[[2, 2, 2]], fn]],
Function[Null, Table[f[##], {f, {fn}}], HoldAll]
];
]
We will need to include ...
answered May 11 '14 at 18:24
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
13
{x1, x2} = x /. Solve[x^2 + 3 x + 2 == 0, x]
{-2, -1}
12
You can use the third argument of ToExpression to do this in a structured way:
ToExpression["x", InputForm, Unset]
12
General thoughts
I think that your mechanism is reasonably robust for common use cases, but not fully robust if one wants to take into account all possible ways that the value (or, generally, global properties) of the symbol can be changed in Mathematica.
My current opinion is that making such triggering mechanism fully robust without new system support is ...
answered Apr 24 '13 at 21:10
Leonid Shifrin
107k1313 gold badges308308 silver badges399399 bronze badges
12
The way Set works in setting parts of an expression is this:
symb[[..<part specification>..]] = values;
The component symb must be a symbol (i.e. with head Symbol).
In the OP's code,
p[[All,3]][[1;;2]] = {1,1};
The symb component is p[[All,3]], which is not a symbol.
Fix as @kglr suggests,
p[[1 ;; 2, 3]] = {1, 1};
As for evaluating p[[All,3]][[...
11
I propose these:
SetAttributes[def, HoldAllComplete]
def[s_Symbol, v_] := SetDelayed @@ Hold[s[x_], v]
def[s_Symbol, v_] := With[{L := s[x_]}, L := v]
def[s_Symbol, v_] := Reverse @ Unevaluated[v := s[x_]]
The HoldAllComplete (or SequenceHold) attribute is necessary for an assignment such as:
def[q, Sequence[1, 2, x]]
head[q[5]]
head[1, 2, 5]
Also ...
answered Sep 25 '13 at 15:57
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
11
This question is done and dusted but it is such a good one (together with the existing answers) for demonstrating and encapsulating the different ways Associations can be modified, that I'd like to belatedly summarise while suggesting some other takeaways. In particular, how it can further highlight a mutable and immutable dichotomy or perhaps more ...
11
Updated 14-10-2014 see solution at the end.
Updated 17-07-2015 Bug no longer present in version 10.2
This answer is basically for documentation of the problem.
The credit goes mainly to the people participating in the comments.
Diagnostics
I can reproduce you observation on two different computers both, Windows 7 Pro 64, SP 1 running Mathematica 10.0.1. ...
11
Now that OP has accepted an answer, implicitly making the results from it correct, here's a much faster method than the fastest there (as in 3x to nearly order of magnitude faster, depending on amount of missing points):
v2 = c2 = ConstantArray[0, Length@v1];
v2[[o1]] = o2;
c2[[o1]] = o1;
c2[[Range[1, First@o1]]] = Range[1, First@o1];
v2 = v2[[With[{xx = c2}...
11
No, not a bug.
Let's think about how AppendTo may be implemented (even though the actual implementation isn't inspectable).
SetAttributes[appendTo, HoldFirst]
appendTo[a_, val_] := (a = Append[a, val])
What happens if we evaluate the following?
appendTo[ a[[ RandomInteger[{1,3}] ]], x ]
It simply does this:
a[[ RandomInteger[{1,3}] ]] = Append[a[[ ...
answered Nov 10 '16 at 21:44
Szabolcs
212k2222 gold badges531531 silver badges11121112 bronze badges
11
The problem is not related to Set in general but to how Set works with Part on a left hand side.
Following Set::setps message documentation
This message is generated when a part assignment is used for the value of an expression other than a symbol.
Part assignments are implemented only for parts of the value of a symbol.
Shortly
Part[(*something*), (*spec*)...
11
He is simply saying that the first argument of Set is not evaluated before Set creates the definition.
However, the sub-parts of the first argument are all evaluated, including the head(i.e. part 0).
Thus in
f[x] = y
f[x] is not evaluated in the sense that any previous definition similar to f[z_] := z^2 will be ignored. However, f is evaluated and x is ...
answered Mar 19 '18 at 14:26
Szabolcs
212k2222 gold badges531531 silver badges11121112 bronze badges
10
You can use injector pattern for that:
{Hold[{a = 2, b = 3}], Hold[{a = 4, b = 6}]}[[1]] /. Hold[init_] :> With[init, a + b]
(* 5 *)
{Hold[{a = 2, b = 3}], Hold[{a = 4, b = 6}]}[[2]] /. Hold[init_] :> With[init, a + b]
(* 10 *)
but you can see that Hold is preferred over Unevaluated in such cases.
As an alternative, you can define your own ...
answered Jul 1 '13 at 17:17
Leonid Shifrin
107k1313 gold badges308308 silver badges399399 bronze badges
10
You need to use InputForm to see the actual value of the numbers.
x = -15*0.1 + 6*0.1;
InputForm[x]
Now when you wrote
a[-15*0.1 + 6*0.1] = 5
Now 5 is actually stored in a[-0.8999999999999999] and not in a[-0.9], this is why a[-0.9] does not return the value 5 you expected. But when you wrote a[-0.8999999999999999] it did.
Now, as to why -15*0.1 + ...
10
Reanalysis
My earlier assertions were incorrect or at least incomplete. I now believe the problem in your code originates because of a particular behavior that can be seen in this separate example:
asc = <|foo -> <|bar -> <|baz -> 1|>|>|>
<|foo -> <|bar -> <|baz -> 1|>|>|>
asc[foo][bar][baz] = 2;
asc
...
answered Jul 17 '15 at 6:27
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
10
I will interpret the question "Why?" to be asking
What useful purpose does it serve that SetDelayed evaluates its first argument?
In the standard evaluation sequence, the evaluation of f[x] begins with evaluating the head f. Thus if f = g, then f[x] first evaluates to g[x]; then any definitions of g would be applied. If SetDelayed did not evaluate f[x_],...
answered Sep 26 '15 at 16:52
Michael E2
188k1414 gold badges252252 silver badges588588 bronze badges
10
Here's the issue. In the second (non-working) code,
RandomInteger[{1, Length[a]}]
is evaluated twice, as we can see by Traceing the evaluation:
SeedRandom[2]
a = {{1}, {2}, {3}};
Trace[AppendTo[a[[RandomInteger[{1, Length[a]}]]], RandomInteger[9]], TraceInternal -> True]
{RandomInteger[9], 8}
AppendTo[a[[RandomInteger[{1, Length[a]}]]], 8]
{{a, {{1}, {...
10
Kuba's answer explains why the first form does not work, but it does not address why the second form does work. That has been discussed in other questions
DownValue assignment using Apply
Why is the first argument of the SetDelayed evaluated?
https://stackoverflow.com/q/5846756/618728
https://stackoverflow.com/q/7408310/618728
One can see that the head of ...
answered Jun 23 '17 at 20:00
Mr.Wizard
259k3333 gold badges535535 silver badges12101210 bronze badges
Only top voted, non community-wiki answers of a minimum length are eligible
Related Tags
assignment × 248evaluation × 38
list-manipulation × 26
function-construction × 21
variable-definitions × 20
functions × 16
programming × 14
replacement × 14
variable × 14
scoping × 12
hold × 12
syntax × 10
associations × 9
matrix × 8
rule × 8
symbolic × 7
core-language × 7
symbols × 7
pattern-matching × 6
options × 6
assumptions × 6
conditional × 6
clear × 6
equation-solving × 5
manipulate × 5