22
$\begingroup$

I have seen a number of examples on this site (such as in syntax highlighting and checking evaluation status) in which functions definitions are preceded with

SetAttributes[f, HoldAll]

without comment, and even though it seems unnecessary for the specific task at hand. This leads me to believe that at least in some cases it is simply good practice to do so. Is that the case? If so, why? Are there instances in which it would not be the best practice?

My understanding of the situation is that if, for example, I have x=5 and then pass 1+x to my function f, the argument as seen internally by f will still be represented as 1+x instead of 6. But it seems to me that in most cases if this were true I'd simply want to Evaluate[1+x] before proceeding. This would lead me to conclude that setting HoldAll would be the exception, not the rule.

Update:

My question is not whether the two examples I provided actually require HoldAll to work, but rather

How do I determine, when writing a new function, whether or not to set HoldAll on it?

What I am concerned about is the possibility of creating a function which behaves as desired without the HoldAll setting (or with it, for that matter) for the test cases I throw at it, but which misbehaves later if something else gets passed to it. What possibilities and issues must I consider to ensure I make the correct choice? What are explicit use cases for each of the two options?

$\endgroup$
4
  • $\begingroup$ Can you give some example from this site where you think HoldAll is unnecessary? Then we can think about why it was a good idea to use it there, maybe even find out that it is in fact necessary to handle all cases. $\endgroup$
    – Szabolcs
    Commented Apr 11, 2012 at 7:30
  • 5
    $\begingroup$ While it is true that in both examples you are giving there is no comment on why it is there it is not true that HoldAll is unnecessary. In fact it is necessary in both cases you mentioned and the code shown would not work without it. In general I would aggree that setting HoldAll would be the exception, but probably among the answers on this site here there are an unusual fraction of exceptional examples :-). $\endgroup$ Commented Apr 11, 2012 at 8:36
  • $\begingroup$ @Szabolcs my question includes two examples on this site where I think HoldAll is unnecessary... @Albert, it does make sense that many examples here are exceptional! Perhaps an explanation of why HoldAll is needed would help to enlighten me. I took the first example I mentioned, syntax highlighting, and entered the code from the accepted answer except for the SetAttributes line. The result was exactly what was specified it would be in the answer; I see no different behaviour in the syntax highlighting. I'm not sure why I can't then conclude that the line of code I omitted is unnecessary. $\endgroup$ Commented Apr 11, 2012 at 18:52
  • $\begingroup$ @MichaelUnderwood: I've just seen that Timo has edited his question explaining how HoldAll is needed for the two examples, is that answering your question? And yes, of course it's good to have exceptional examples here, it just probably makes you think HoldAll is necessary more often than it actually is. Usually you will know when to use it, since when needed things will just not work without it. $\endgroup$ Commented Apr 11, 2012 at 20:56

2 Answers 2

22
$\begingroup$

The way Mathematica works is that when it encounters a function with arguments it will try to evaluate the arguments first before proceeding to evaluate the function. This behavior can be modified by specifying the various HoldAll, HoldFirst, HoldRest, etc. attributes for a given function.

So in your example f[x+1] will be immediately replaced by f[6] internally.

To answer your question: You need HoldAll or one of it's siblings if you construct functions that need to know the actual parameters with which the function was called. For example, I sometimes need to make file names using ToString on variables that the function is called with regardless of whether those variables evaluate to something.

In general HoldAllis not necessary if you just do arithemtic functions or other simple data manipulating functions. Once you start getting more into the swing of functional programming style of MMA you'll soon realize when and where you need arguments to stay unevaluated.

In the cases you mentioned it becomes obvious why you would want to specify HoldAll. In, e.g., the "checking evaluation" case you want the code argument to only be evaluated once you are inside the Block, not immediately when Mathematica encounters the function that specifies the Block.

The case in the syntax highlighting question is similar; the list of vars you supply should be passed as is to the Block, or the function will not work if the vars evaluate to something that does not make sense within the Block (numerical values in this case):

Some lines of mma notebook

$\endgroup$
5
  • $\begingroup$ I just made this comment above, but will add to it here. I tried the syntax highlighting example with HoldAll omitted, and it behaved exactly the same. This isn't surprising to me, because if I set foo=bar and then type f[foo], Mathematica doesn't change my input to read f[bar]... So indeed it still displays as f[foo], with foo a different colour. $\endgroup$ Commented Apr 11, 2012 at 18:56
  • 1
    $\begingroup$ Aah, that definitely clears a few things up for me, thanks! Would it be correct to say then that if what you want from the arguments to your function is their values then you shouldn't use HoldAll, but if you explicitly want the symbols as entered then you should? $\endgroup$ Commented Apr 11, 2012 at 19:45
  • $\begingroup$ Hi Michael, you are correct. I was too hasty in looking at the questions you cited and misunderstood how the syntax highlighting related to your question. In that example it is not about the highlighting but about the definition of the SequenceVars function. I have edited my answer to reflect this and supplied a small demo of the effect of HoldAll. I have also tried to answer the actual question you had ;-). $\endgroup$
    – Timo
    Commented Apr 11, 2012 at 19:47
  • $\begingroup$ @MichaelUnderwood Yes you have the gist of it. There are more obscure reasons but you'll most probably immediatly realize that you need lazy evaluation. PS: Sorry about messing up the comment chain but I couldn't let the previous comment stand with so many typos in it. $\endgroup$
    – Timo
    Commented Apr 11, 2012 at 19:52
  • $\begingroup$ Your example with two type of vars is crazy. $\endgroup$
    – Nam Nguyen
    Commented Nov 5, 2020 at 22:50
17
$\begingroup$

The Hold functions enable Mathematica's version of what some other languages call "macros." You can use them for a lot of things, but the essential point is that they preserve the structure of the input. The built-in functions are full of examples:

x = 7;
Plot[x^2, {x, -2, 2}]

Type this in and you'll see that Plot draws the parabola even though "x" was assigned to previously. That's because by Holding the input, the Plot function is able to interpret what actually matters, which is the structure of the function that you are plotting. What the independent variable is called doesn't really matter in this case.

An example of what a simple macro would look like is this, where we convert plus to times:

SetAttributes[f, HoldFirst];
f[expr_] := (expr // Hold) /. Plus -> Times // ReleaseHold;

f[6 + 2]

12

Macros also give you the ultimate power when it comes to abstracting code. As a rule you will rarely need macros, especially in a language like Mathematica which is dynamic and functional, but sometimes macros are the cleanest way.

$\endgroup$
2
  • $\begingroup$ Nice example of a macro. $\endgroup$
    – Timo
    Commented Apr 12, 2012 at 6:00
  • 3
    $\begingroup$ However note that UpValues can circumvent the Hold* attributes, for example after defining _[a]^=0 you'll find that Hold[a] evaluates to 0. $\endgroup$
    – celtschk
    Commented Apr 12, 2012 at 10:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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