# What is the difference between Set and SetDelayed when evaluating the RHS leaves it unchanged?

I thought there was no difference between f[a_] = 2 + a; and f[a_] := 2 + a; because the resulting DownValues[f] are identical.

However, the Information[f] are different:

Globalf

f[a_] = 2 + a


and

Globalf

f[a_] := 2 + a


Is that difference entirely due to some flag telling how the DownValues arose, or do non-historical differences (like the mechanism upon calling) exist too?

• try ClearAll[f1, f2, a];a = 5; f1[a_] = 2 + a; f2[a_] := 2 + a;DownValues /@ {f1, f2}?
– kglr
Sep 10 '18 at 7:09
• I just answered something very similar here. Sep 10 '18 at 8:44
• @kglr I'm afraid this isn't what OP concerns, the RHS changes after evaluating in this case, which is against OP's title. Sep 15 '18 at 6:23
• Thanks @xzczd; good point. Should have read the title first:)
– kglr
Sep 15 '18 at 6:35
• Strongly related: mathematica.stackexchange.com/q/6346/1871 Jun 2 '20 at 8:35

This is just my guess about what is going on. First, there is really an internal difference between the two approaches, as is shown in the OP. Another place where this difference manifests itself is with the function LanguageExtendedDefinition:

Clear[f];
f[a_] = 2 + a;

LanguageExtendedDefinition[f]


LanguageDefinitionList[f->{OwnValues->{},SubValues->{},UpValues->{},DownValues->{HoldPattern[f[a_]]->2+a},NValues->{},FormatValues->{},DefaultValues->{},Messages->{},Attributes->{}}]

Notice the Rule instead of the RuleDelayed in the DownValues rule. For the SetDelayed version:

Clear[g]
g[a_] := 2 + a

LanguageExtendedDefinition[g]


LanguageDefinitionList[g->{OwnValues->{},SubValues->{},UpValues->{},DownValues->{HoldPattern[g[a_]]:>2+a},NValues->{},FormatValues->{},DefaultValues->{},Messages->{},Attributes->{}}]

This time the DownValues rule uses RuleDelayed.

So, I think the real question is why the output of DownValues doesn't use Rule:

Clear[f]
f[a_] = 2 + a;

DownValues[f]


{HoldPattern[f[a_]] :> 2 + a}

I think the answer is that if DownValues did use Rule, then the output would be confusing if a had acquired a value after f was defined. Suppose the output of DownValues was:

dv = {HoldPattern[f[a_]] -> 2 + a}


{HoldPattern[f[a_]] -> 2 + a}

At some point, a is given a value:

a = 3;


And then, later, the user wants to know the DownValues of f:

dv


{HoldPattern[f[a_]] -> 5}

The user would be confused into thinking that the RHS of the rule was 5, when it is really 2+a. So, the function DownValues purposefully replaces Rule with RuleDelayed to avoid this confusion. Note that an alternative was to introduce another hold-type wrapper around the output of DownValues, and this is actually what LanguageExtendedDefinition does.

• Interesting. Then, does this internal difference have any deeper influence? I guess the answer is no, but being just a normal user, I dare not affirm. Sep 17 '18 at 7:58
• Is there a detectable difference between the two kinds of definitions though? I mean a difference in behaviour, ignoring directly checking Definitions or ExtendedDefinition. Sep 20 '18 at 8:29
• @Szabolcs My guess is that there is no example where this difference in definitions would exhibit a difference in evaluation behavior. However, I wouldn't be surprised if somebody could come up with one. Sep 22 '18 at 21:45

Also, it should be pointed out, that DownValues are the same, but Definition is still different. I guess this might be the "flag" op asked about.

Information displays Definition by calling it. While one might think Information only "illustrates" whatever is kept internally, then probably Definition really is what the kernel knows. Same output, but maybe a semantic difference one could say.

In[32]:= ClearAll[f, a]
f[a_] = a + 2
Definition[f]
f[a_] := a + 2
Definition[f]

Out[33]= 2 + a

Out[34]= Definition[f]

Out[36]= Definition[f]

• Actually, Information internally calls Definition: Clear[f, x]; f[x_] = x; Trace[Information[f], Definition[_]] // Flatten // FullForm. Sep 16 '18 at 13:18
• Thanks, I knew that, but improved my answer to emphesize my message. Do you agree with what I now state?
– Johu
Sep 16 '18 at 13:40
• Hmm… I think "what the kernel knows" is a somewhat vague description, and I tend to think Definition is also kind of illustration. Try the following example: Clear[f, g, x]; f[x_] = x; DownValues[g] = DownValues[f]; {Definition@g, UpValues@g, DownValues@g} // InputForm Sep 16 '18 at 14:13

Reading the title of the question, I can't help but notice the part about what gets evaluated and when:

"What is the difference between Set and SetDelayed when evaluating the RHS leaves it unchanged?"

where I emphasize the later part.

I think there is a slight misunderstanding about what is the difference between Set and SetDelayed with regard to the time of evaluation of the RHS.

In the example provided, both definitions seem to be equivalent, especially after looking at the relevant DownValues-which appear identical- because care is not taken to account for the OwnValues of the symbol used in the definition of f, here a. Thus, it appears that the two definitions are equivalent, when in actual fact they are not.

If prior to the evaluation of the definition of f using Set, the symbol a had obtained a value eg by evaluating a=-2 at a prior point, the two definitions would have had different Information and different DownValues.

For the sake of comparison, juxtapose the following definitions to the ones in the Q:

a = -2;
f[a_] = 2 + a;
Information[f]
DownValues[f]


Globalf

f[a_] = 0

{ HoldPattern[f[a_]] :> 0 }

Clear[a, f] (* it's not necessary to clear a but we do it anyway. *)

f[a_] := 2 + a;
Information[f]
DownValues[f]


Globalf

f[a_] := 2 + a

{ HoldPattern[f[a_]] :> 2 + a }

After evaluating the lines above, I hope it becomes clear that the two definitions are not equivalent.

In the case of Set, the RHS appears to be left unevaluated, when there are no OwnValues for a, but that is not the case!. By construction, Set always evaluates its RHS.

• I'm sorry, but as pointed out in previous comment, OP only concerns about cases that RHS is unchanged after evaluating, so example like a = -2; f[a_] = 2 + a is out of scope of this question. Sep 16 '18 at 8:45
• I think there is also a copypaste mistake in the first example... SetDelayed acts as Set
– Johu
Sep 16 '18 at 9:32
• @Johu indeed, thanks for pointing it out! Sep 16 '18 at 10:31
• Well, it seems that you've misunderstood OP's question in some way. "I don't understand how the RHS of Set could remain unchanged in the context of the Q. " Simplest case: Clear[f, x]; f[x_] = x;. Sep 16 '18 at 13:14
• If you give it a thought, the Q is actually quite interesting. Take a close look at Carls answer. It is not about interchangeable use, but it is about hidden information, which makes the two different even if DownValues are the same!
– Johu
Sep 17 '18 at 21:53