14

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:

Global`f

f[a_] = 2 + a

and

Global`f

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?

MeMyselfI
  • 1,116
  • 5
  • 12

3 Answers3

16

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 Language`ExtendedDefinition:

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

Language`ExtendedDefinition[f]

Language`DefinitionList[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

Language`ExtendedDefinition[g]

Language`DefinitionList[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 Language`ExtendedDefinition does.

xzczd
  • 65,995
  • 9
  • 163
  • 468
Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • 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. – xzczd Sep 17 '18 at 07: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. – Szabolcs Sep 20 '18 at 08:29
  • 1
    @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. – Carl Woll Sep 22 '18 at 21:45
2

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]
Johu
  • 4,918
  • 16
  • 43
  • Actually, Information internally calls Definition: Clear[f, x]; f[x_] = x; Trace[Information[f], Definition[_]] // Flatten // FullForm. – xzczd 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 – xzczd Sep 16 '18 at 14:13
0

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]

Global`f

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]

Global`f

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.

  • 4
    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. – xzczd Sep 16 '18 at 08:45
  • 1
    I think there is also a copypaste mistake in the first example... SetDelayed acts as Set – Johu Sep 16 '18 at 09:32
  • @Johu indeed, thanks for pointing it out! – yosimitsu kodanuri Sep 16 '18 at 10:31
  • @xzczd I don't understand how the RHS of Set could remain unchanged in the context of the Q (without considering advanced use cases). My answer tries to convey the message that Set always evaluates its RHS and there's probably some misunderstanding on behalf of the OP. If you consider my answer as off topic I'll be more than happy to delete it. – yosimitsu kodanuri Sep 16 '18 at 11:28
  • 1
    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;. – xzczd Sep 16 '18 at 13:14
  • @xzczd like I say in my answer, this kind of example is not a case where the RHS of Set remains unchanged. Set always evaluates its RHS and it does so too in this case; it only appears as though nothing changes because x doesn't have eg OwnValues rules associated to it so that the evaluation loop doesn't have anything to replace in its place. Unless the question is actually about the scope of symbols and contexts etc. Anyway, thanks for the follow-up comment. I'm really interested to see how this Q gets resolved – yosimitsu kodanuri Sep 16 '18 at 16:15
  • Yes, Set evaluates its RHS, but the RHS after evaluation is the same as the one before evaluation, so it's unchanged, isn't it? From Cambridge dictionary: "unchanged
    adjective staying the same. "
    – xzczd Sep 17 '18 at 07:45
  • would you consider something like f[a_]=FixedPoint[# &, a] and f[a_]:=a two expressions that could be used interchangeably with the ones presented, for the purposes of this question? – yosimitsu kodanuri Sep 17 '18 at 13:57
  • 3
    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
  • @Johu I do believe it is an interesting question and that's why I'm not flagging it; indeed, I have read @CarlWoll's answer; multiple times. Like I said in a previous comment, I'm really interested to see where this leads to. – yosimitsu kodanuri Sep 18 '18 at 14:25