Working with Unevaluated Expressions

Robby Villegas
Wolfram Research

Abstract:

Most experienced Mathematica programmers will eventually encounter tasks or applications in which they need to manipulate expressions without letting them evaluate. For instance, typesetting and interpretation rules, debugging programs, code analysis tools, and constructing code on the fly at run time are all areas of programming that require careful control of evaluation.  Since Mathematica automatically evaluates arguments and return values of functions, building up a result without exposing intermediate stages of work to the evaluator requires subtle techniques that even seasoned Mathematica programmers sometimes find elusive. In this tutorial, I will demonstrate situations in which evaluation control is important, pointing out common pitfalls and providing useful tools and techniques along the way.

Off[General::spell,  General::spell1]

Get["init.m"]

An Introduction to demystify scary things

The overarching evaluator

Mathematica is an interpreted language.  When Mathematica sees an input like this:

  f[1 + 2, 3^3, x + x + 0]

its standard procedure is to pre-evaluate the head f and the arguments ei before actually invoking the function f.  Thus, by the time the code for the function f is called, it sees this:

  f[3, 9, 2 x]

It is the overarching evaluator that pre-processes the general form of expressions in this way.

The reason Mathematica pre-evaluates is that it's usually what you want, in order to make interactive use or programming easier.  For instance, if you previously assigned a, b, and n values, you definitely want them substituted in before this the Expand function is called here:

ClearAll["a",  "b",  "n"]

{a,  b}  =  {3,  7}; 
n  =  7;

Expand[(a x  +  b y)^n]

And in this example, you want the D to compute the derivative expression before Simplify goes to work, since before D produces an expression, there's really nothing to simplify:

Simplify[ D[ArcSin[x],  {x,  8}] ]

If Simplify acted on its literal argument, D[ArcSin[x], {x, 8}], what could it try to simplify?  ArcSin[x]?  x?  8??  That would not make sense, so the argument evaluates first, then the outer function is called.

So, in general, before f is actually called, there are two stages of your input.  Here they are using the generic form from earlier:

(Before)  f[1 + 2, 3^3, x + x + 0]
  
(After)  f[3, 9, 2 x]

The first stage is your original input before the evaluator gets its hands on it.
The second stage has the head and arguments evaluated.

It is the second that actually calls f, so f never sees the original arguments like 1 + 2, only the reduced arguments like 3!

I usually think of the evaluator's pre-processing as applying the "evaluator function", call it eval(), to all the parts.  I colored the head red and the arguments blue to emphasize them.

  f[e1, ..., en]
  
     ⟹
     
  eval(f) [ eval(e1), ..., eval(en) ]

For those of you familiar with the evaluation sequence in Appendix "A.4.1 The Standard Evaluation Sequence" of the Mathematica book, I'm talking about steps 2 through 4, usually called "standard argument evaluation".

Here's a contrived example to show that simple arithmetic reduces the head and argument to sensible values.  Again, I've colored the head and argument, and made the function brackets large, to make it clear that this example is really of the simple form f[x], with f and x being sort of weird, complex things:

(1*FactorInteger  +  0)  [ 2^2 * 3^3 ]

Trace seems like a scary function, but you can use it in this case to catch the evaluation of head and argument, and see that it results in a nice, simple FactorInteger[108], which is then evaluated.  I've taken the liberty of arranging the Trace result in a column and coloring the head and argument evaluations just as above to make it clear what each evaluation chain is.

Trace[ (1*FactorInteger  +  0)  [ 2^2 * 3^3 ] ]

The point of this is to get you thinking of each input, and each statement in your programs, as having two stages:  the original stage that you typed (or constructed), and the reduced stage where arguments have been evaluated.  And to remember that the function isn't called until the second stage, so it doesn't know what the original form was.

There are cases where you really want f to receive the arguments as given by the user or the programmer, not the pre-processed, i.e. evaluated, form.  Since the default behavior of the Mathematica language interpreter is to evaluate everything in sight until nothing more changes, you need to use non-default techniques to prevent evaluation.

Sometimes you want to send an argument into the function unevaluated.  For instance, when typesetting, or analyzing some code, you might want to compute Length of the expression Print[1, 2, 3], or use Cases to extract the numbers from the mixed sum 1 + 3.5 + Pi + x + (3 - I)^2.

Sometimes you want the return value of the function to remain unevaluated until you can do something else with it.

That is the subject of this talk.

Advanced note:  As you may know, in addition to evaluating head and arguments, the evaluator does other pre-processing to the original input, such as flatten Sequence, and invoke upvalues on arguments.  These things can all alter the original input before the main function ever gets called.  You might want to prevent some or all of these alterations.

An unevaluated expression is just an expression, a tree structure like anything else.

Before we start, I want to mention that an "unevaluated" expression is just an expression.  It's a tree structure that you can draw and see with your eyes:

Plus[3,  4,  Times[5,  6],  Power[5,  2]]

For a moment, let yourself forget that Mathematica would yank this expression out of your hands and give you back the integer 62.  Imagine that you can manipulate it as an abstract structure whose heads and elements are meaningless.  That's what you're going to learn to do in this talk.

Since this expression is structurally the same as more stable ones like {3, 4, {5, 6}, {5, 2}}, programming commands that you are familiar with can operate on it, as long as you can see to it that the expression arrives unaltered at the code of the function.

There's nothing scary about operating on these; it's just a little harder to keep the evaluator's hands off them for a moment until you're ready for them to evaluate.

Simple uses of Unevaluated

Let's look at some simple uses of Unevaluated.

Unevaluated is a wrapper on arguments that is simply a signal to the evaluator to avoid evaluating the argument.

Head[ Unevaluated[Plus[1,  2,  3]] ]

Length[ 
      Unevaluated[Print["spam",  "and", "eggs"]] ]

ToString[ Unevaluated[2^2 * 3^3 * 5^5] ]

Cases[
      Unevaluated[
        1 + 3.5 + Pi + 
          x + (3 - 
                I)^2],  _Integer  |  _Rational  |  _Real]

It is transparent to the function receiving the argument.  You can think of it as a shuttle giving the argument safe transport to the function's code, keeping the evaluator away.  Unevaluated vanishes before the argument is fed to the function, since its purpose is fulfilled.

Mapping a function across an unevaluated list of elements:

{x,  y,  z}  =  {77,  88,  99};

Map[Context,  Unevaluated[{x,  y,  z}] ]

Without the Unevaluated, the x, y, and z would become integers before Context could act on them:

Map[Context,  {x,  y,  z} ]

Scan[Information,  
      Unevaluated[{$Version,  $RecursionLimit}]]

If you've got a set of things inside Hold, and you want to map a non-holding function such as Head across them, then you can use the idiom:

   f /@ Unevaluated /@ Hold[e1, ..., en]

which will form this frozen expression, with the calls to f colored in blue:

   Hold[ f[Unevaluated[e1]], ..., f[Unevaluated[en]] ]

Now it is safe to let the elements evaluate.  You could do this by changing the outer head to List.  Here is a small example:

List  @@ 
Map[Head,  
        Map[Unevaluated, 
Hold[Print[1],  
            2  +  3]
]]

You can use the more complex structural and functional programming commands that you enjoy, too.  They don't care that the argument arrives unevaluated; it's just a structure to them.  Here's an example of Through, to produce a list of all the kinds of assignments made to a symbol:

$ValueTypes = {Attributes, DefaultValues, DownValues, FormatValues, 
        Messages, NValues, OwnValues, Options, SubValues, 
        UpValues};

??  $Version

Through[ $ValueTypes[Unevaluated[$Version]] ]

It's easier to read if we make a match-up and display it as a column:

Thread[$ValueTypes  ->  
          Through[$ValueTypes @ Unevaluated[$Version]]]  // 
      ColumnForm

Unevaluated must be wrapper before argument evaluation, not after, else it isn't stripped

Recall our discussion of the over-arching evaluator, and the fact that your inputs and commands have two stages:  their original form, and the reduced form with arguments all evaluated.

Unevaluated is not meant to be a function or stable data type.  It is to be used as a wrapper on an argument in stage 1, before argument evaluation.  It is a signal to the evaluator to suppress the usual evaluation of that argument.

   f[1, Unevaluated[2 + 2^2], 3]

Once the evaluator has made a note not to evaluate that argument, Unevaluated's purpose is fulfilled, so it vanishes before the argument is actually fed to f.  This is in contrast to Hold, which is an actual data type, if you will, and persists as a head until you discard it (with ReleaseHold or however you like).

For instance, I can extract the head of a sum and get Plus, as I expect:

Head[ Unevaluated[1 + 3.5 + Pi + x + (3 - I)^2] ]

But if I had used Hold instead of Unevaluated, it would not have worked right:

Head[ Hold[1 + 3.5 + Pi + x + (3 - I)^2] ]

Those of you who have experimented with Unevaluated have found that in some situations it doesn't vanish.  This makes it seem confusing and inconsistent, like Sequence.

The least confusing situation where Unevaluated persists is when it is the outermost head in the output.  This is not too surprising, since it's not an argument of anything.

Unevaluated[ Print[1] / 2^3 ]

Another case where Unevaluated is when it's an argument of a head that does nothing.  List is an example of an inert data type that performs no action:

{1,  Unevaluated[2^2]}

So is an arbitrary symbol with no definitions:

f[Unevaluated[1  +  0],  2]

When no code is invoked to "use it up", Unevaluated just sits there unused.

The subtle and confusing situation where Unevaluated persists is when an argument did not originally have a head of Unevaluated, but became Unevaluated[whatever] after argument evaluation finished.  In terms of the two stages of each input:

stage 1 (original input):  Unevaluated vanishes, nicely.

stage 2 (after arg evaluation):  Unevaluated persists, annoyingly.

In this example, the original argument of Print has head ToExpression.  ToExpression yields Unevaluated[1 + 2] after evaluation, but that's too late:

Print[ ToExpression["Unevaluated[1 + 2]"] ]

In this example, the argument's original head is a complex Function[...] expression, not even a symbol.  It yields Unevaluated[77 + 99^2], but again

Head[ Unevaluated[#1  +  #2^2] & [77,  99] ]

If I give an argument which, after evaluation, will become something whose head is Unevaluated - Unevaluated[arg] - and it won't work.

This subtle distinction of stages of your input has tripped up almost every Mathematica programmer I know, no matter how advanced.

Since in real programs, you often have to construct the arguments from pieces, and can't just write them out in final form in the function call, we'll have to learn methods of making sure the Unevaluated is literally present as a wrapper in the function call.

Several specific techniques

Manipulations

Use Function[] to make a temporary holding version of a function

Most built-in and user-defined functions let their arguments evaluate by default.  Suppose for a particular line of code, you need a version of Head that doesn't evaluate its arguments.  One way, of course, would be to temporarily give Head the HoldFirst attribute, but it's usually unsafe to change the definition of basic built-in functions.  Fortunately, the language enables you to give pure functions the same attributes you would give to symbols.  Here is the template for constructing a temporary holding version:

  MyHead  =  Function[e,  Head[ Unevaluated[e] ],  HoldFirst]

This is essentially the same as the more familiar, simpler pure function

  MyHead = Head[#]&

but it has to use the 3-argument form of Function with a named variable in order to give it the HoldFirst attribute.

Now you can use MyHead just like you would use Head.  If the argument comes in unevaluated, it will remain that way.  For instance:

MyHead  =  
      Function[e,  Head[ Unevaluated[e] ],  HoldFirst];

MyHead  /@  
      Unevaluated[{Print[1],  2  +  2^2,  x  =  3}]

There's no need to give the function a name; I just did that to make the example more concise.  Usually you use Function[] because you want to construct one-shot operators on the fly, to use in a single line of code.

Here's an example of a held list of elements:

heldElems  =  
      Hold[Print[1],  Print[2  +  3],  0  +  1,  1  +  2,  
        2  +  3,  0*1,  1*2*3,  4^4];

We want to group consecutive elements if they have the same head, i.e.

  Head[#1] === Head[#2] &

But this ordinary form of pure function will evaluate #1 and #2, which will destroy the structure in things like Print[1] and 0 + 1, so we have to prevent that.  We do it by converting that function to the longer form:

  Function[{e1, e2}, Head[Unevaluated[e1]] === Head[Unevaluated[e2]], HoldAll]

Again, it's essentially the same as the more familiar form, but it gives this construct the HoldAll attribute.  Here is the result in action:

Split[

Hold[Print[1],  
        Print[2  +  3],  0  +  1,  1  +  2,  2  +  3,  0*1,  
        1*2*3,  4^4], 

Function[{e1,  
          e2},  Head[Unevaluated[e1]]  ===  Head[Unevaluated[e2]],  
        HoldAll]

]

And here is an example where you want to test unevaluated products to see if they contain spurious zeros:

Map[
Function[e,  MemberQ[Unevaluated[e],  0],  
        HoldFirst], 
Unevaluated[{x * y,  
          u * 0 * v,  1 * 2 * 0}]
]

If you want to delete the zeros so that the products don't evaluate to zero, you can make a holding DeleteCases:

Map[
Function[e,  
        DeleteCases[Unevaluated[e],  0],  
        HoldFirst], 
Unevaluated[{x * y,  
          u * 0 * v,  1 * 2 * 0}]
]

Replace is one of these easiest methods for transforming a structure, and it's sort of "visual programming", making it very clear to the reader what is happening.

Replace[
      Hold[1  +  2,  Print[3,  4],  
        D[x^2,  x]], 
h_[
          elems___]  :>  {h,  
          elems}, 
{1}
]

patts  =  
      Replace[Unevaluated[{1  +  2,  Print[3,  4],  
            D[x^2,  x]}], 
h_[___]  :>  
          Blank[h], 
{1}
]

Suppose I want to take the factored form of an integer and typeset it nicely as a product of prime powers.  Obviously, I can't let things like  (3^3) (5^5) evaluate before I feed it to the typesetting function, since then it would become some integer and I'd lose the decomposed form.

n  =  79301169838123235887500;

factored  =  FactorInteger[n]

We're going to convert the inner lists to Power and the outer list to Times, so we need to have the Hold wrapper in place before we start:

held  =  Hold[ Evaluate[factored] ]

First, I convert each ordered pair {p, a} to the prime power that it represents:  (p^a).

Replace[
      held, 
{p_,  a_}  :>  
        p^a, 
{2}
]

Now I change the list to a product and wrap a call to MakeBoxes around it:

Replace[%, 
Hold[{elems___}]  :>  
        MakeBoxes[Times[elems],  
          TraditionalForm]
]

Once you've constructed a typeset box expression, you can use DisplayForm to see how it would display if you sent it to a front end output cell:

DisplayForm[%]

Function and With can stuff values into any expression, including held ones.

Both With and Function do direct substitution into the body, and for the most part they're equivalent ways of "filling in a template", the body being the template:

With[{p  =  2,  a  =  2,  q  =  5,  
        b  =  5}, 
MakeBoxes[p^a * q^b]  // 
        DisplayForm
]

Function[{p,  a,  q,  b},  
        MakeBoxes[p^a * q^b]  // DisplayForm] [2,  2,  5,  
      5]

Why would you use With or Function to substitute in 2 and 5 when you could just type this?

  MakeBoxes[2^2 5^5]

Answer:  p, a, q, and b are probably variables in a program you're writing, and you need to put their values, not their literal names, into the MakeBoxes command.  You can't use Evaluate, like this

  MakeBoxes[ Evaluate[p^a q^b] ]    (* does NOT work *)

because then the argument would collapse to an integer (besides, MakeBoxes is HoldAllComplete and doesn't respect Evaluate).  You can't use Evaluate in deep subexpressions of a held argument, you can use it only on the whole argument

  MakeBoxes[ Evaluate[p]^Evaluate[a] * Evaluate[q]^Evaluate[b] ]  (* No *)

In this situation, With and Function can jam those values in for you.  Since the initial values are probably those of variables in your program, here's an example of how you'd really use them in a program.

{a,  b,  c}  =  {1,  2,  3}; 

With[{a  =  a,  b  =  b,  
        c  =  c}, 
MakeBoxes[a^b  +  c*a]  // 
        DisplayForm
]

Later, I'll show techniques for tagging arbitrary subexpressions for evaluation, in a function called EvaluateAt (based on another new one called ReplaceAt).

Something that you may not know is that With initializations can use ':=' as well as '=', to cause the initialization not to evaluate.  For instance:

{a,  b,  c}  =  {1,  2,  3}; 

With[{expr  :=  a  +  b  +  c}, 
{expr,  
        Length[Unevaluated[expr]]}
]

It's true that if the local value of 'expr' is an unevaluated expression, then you could simply use that literal expression everywhere you need it instead of a local 'expr', but maybe it makes the code clearer if many places in a region of code all use exactly the same expression.  Some of them may need it unevaluated, some may be happy to let it evaluate.

Advanced note
The initializations in scoping constructs Module and With are not evaluated as calls to the Set or SetDelayed functions.  You can see this by either attaching a top-level trap to Set, or by using Block to temporarily disable Set.  Either way, you'll see that Module and With accomplish initializations in a magical internal way, not by calling the top-level Set function.

Strangely, if you ask Trace to report Set evaluation chains, it will report local variable initializations!  My best guess is that since we specify initializations with something that is syntactically Set[var, value], the evaluation chain for initialization is considered to begin with the expression Set[var, value], and this is good enough to convince Trace that it is a call to Set, even though technically some internal magic intervenes and performs assignments instead of letting Set do it.

I was tempted to consider this a bug, but one advantage - a significant one for kernel hackers - is that you can actually trap Set with the familiar idiom for trapping internal functions, and not get yourself into infinite recursion trouble when you do Block[{$TrapSet = False}, ...].  But it is an odd inconsistency in the language that you use the syntax Set[var, value] to specify an action that will not be carried out by Set, but by inaccessible internal magic.

Unprotect[Set]; 

$TrapSet  =  True; 

assign_Set  /;  $TrapSet  := 
Block[{$TrapSet  =  False}, 
Print @ 
          Unevaluated[
            assign]; 
assign
]

Module[{x  =  3},  x^2]

Block[{x  =  3},  x]

assign_Set  /;  $TrapSet  =.

Block[{Set}, 
Module[{x  =  3},  u  =  1;  
        x^2]
]

? u

Trace[Module[{x  =  3}, x^2], Set, 
      TraceInternal -> True]

Build up the arguments inside of Hold, then apply the function at the end

Sometimes it takes several steps to go from the original input to the final arguments you want to pass to a function.  In this case, it's usually good to wrap the inputs in Hold at the beginning and work with them, then replace Hold with f at the end.  We saw this in the last section using Replace to make the result look more and more like what we want.  The final step is often one of these:

   f @@ Hold[e1, ..., en]
   
   ReleaseHold @ Hold[f[e1, ..., en]]

Here's an example where my function is given an integrand and the ranges of the variables.  A typical call will look like this:

  f[x + y + z, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]

But I would like global values of the variables, if they should exist, not to interfere with computing this integral.  To prevent outside interference, you of course wrap the integral in Block with {x, y, z} local.  So I want to take the above and construct this expression:

  Block[{x, y, z},
    Integrate[x + y + z, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]
  ]

That looks awfully easy since I'm just wrapping a Block around the desired Integrate expression.

But remember that I don't know in advance what the variables are or how many there will be!  Here is the template for my function:

Attributes[f] = HoldAll;

f[iterand_, iterSpecs:{_Symbol, __}...] := ...

Let's look at the steps in constructing the Block from the input, and not evaluating it until it's all assembled.  We'll give {x, y, z} values at the beginning, so that if we make a mistake and expose anything to the evaluator too early, we'll know.

{x,  y,  z}  =  {77,  88,  99};

First wrap the iterSpecs in Hold so we can safely extract the variable names.

heldIterSpecs = Hold[{x,  -1,  1},  {y,  -1,  
            1},  {z,  -1,  1}]

heldVars  =  
      Replace[heldIterSpecs,  {s_Symbol,  ___}  :>  
          s,  {1}]

heldVarList  =  
      Replace[heldVars,  
        Hold[elems___]  :>  Hold[{elems}]]

This gives us argument 1 of Block, the local variable declaration.  Now we just need to append the body.  The body is simply Integrate[iterand, iterSpecs].  Those were the names of the pattern variables in f, so they'll get substituted directly in.  I write them out in my next input, since I'm in an interactive session, not inside my function body.

Append[heldVarList,  
      Unevaluated[
Integrate[
          x  +  y  +  z,  {x,  -1,  1},  {y,  -1,  
            1},  {z,  -1,  1}]
]]

Block  @@  %

Great, it works!  And we can see that it would have failed without our careful construction of Block:

Integrate[
      x  +  y  +  z,  {x,  -1,  1},  {y,  -1,  
        1},  {z,  -1,  1}]

Here it is all put together into a function:

\(\(Attributes[f]\  = \ HoldAll; \)\(
\)\)
f[iterand_,  iterSpecs : {_Symbol,  __} ... ] :=

Module[{heldIterSpecs,  heldVars,  
          heldVarList}, 

heldIterSpecs  =  Hold[iterSpecs]; 

heldVars  =  
          Replace[heldIterSpecs,  {s_Symbol,  ___}  :>  
              s,  {1}]; 

heldVarList  =  Replace[heldVars,  
            Hold[elems___]  :>  
              Hold[{elems}]]; 

Block  @@  Append[heldVarList,  
            Unevaluated[
Integrate[iterand,  
                iterSpecs]
]]
]

Here are some annoying assignments that will surely tell us if we evaluate anything:

{x,  y,  z}  :=  {Print[1],  Print[2],  Print[3]}

f[x^2  +  y^2  +  y^2, {x,  -1,  1}, {y,  -1,  1}, {z,  -1,  1}]

ClearAll["x",  "y",  "z"]

Construct a held result from parts

Sometimes it's fine for the inputs to evaluate, but the expression you construct from them must not evaluate.  When it's okay to evaluate the parts but not the whole, plain old pure functions are often quick and easy:

An assignment, on standby, waiting for ReleaseHold, or to be typeset and used as the limit of a Sum, or whatever:

Hold[Set[x,  #]] & [77]

A sum of numbers:

Hold[Plus[##]] &  @@  {6,  7.5,  8  -  3 I,  
        4/5}

Composition is another form of anonymous function, too, but without #n and ##n variables:

Composition[HoldForm,  Plus]  @@  {6,  7.5,  8  -  3 I,  
        4/5}

Wrap everything in a holding wrapper, do your manipulations, then finish with ReleaseHold.

Here I'll introduce HoldForm, which is cute because it holds just as Hold does, but it doesn't display itself.  Thus, you can see the essentials, instead of having the display crowded with Hold.  Of course, since you can't see HoldForm, you have to remember where you put it, so it can be deceptive.  You can use InputForm to reveal the HoldForm's, reminding yourself where they are.

atomsHeld  =  
      Map[HoldForm,  Unevaluated[2^1 * 3^2 * 5^3],  {-1},  
        Heads -> True]

Thread[atomsHeld,  HoldForm[Power]]

%  /.  HoldForm[Power]  ->  HoldForm[Plus]

ReleaseHold[%]

A nice alternative in a typesetting front end is to define yourself a wrapper that holds, just like Hold and HoldForm do, but which prints as a framebox or a colored background around its argument.  That way, it's not obtrusive, and yet it's visible so you don't forget it's there.  The typesetting rule is just two lines:

ClearAll["HoldFormFrame"]

Attributes[HoldFormFrame]  =  HoldAll; 

HoldFormFrame  /:  
      MakeBoxes[HoldFormFrame[expr_],  fmt_]  := 
TagBox[
        FrameBox @ MakeBoxes[expr,  fmt],  
        HoldFormFrame]

HoldFormFrame  /:  
      MakeBoxes[HoldFormFrame[expr_],  fmt_]  := 
TagBox[
        FrameBox @ MakeBoxes[expr,  fmt],  HoldFormFrame]

atomsHeld  =  
      Map[HoldFormFrame,  Unevaluated[2^1 * 3^2 * 5^3],  {-1},  
        Heads -> True]

Thread[atomsHeld,  HoldFormFrame[Power]]

%  /.  
      HoldFormFrame[Power]  ->  HoldFormFrame[Plus]

DeleteCases[%,  HoldFormFrame,  {-1},  
      Heads -> True]

Replace function names with temporary dummy symbols

In this technique, you replace "active" built-in functions with inert symbols of your own choosing.  This gives you a meaningless data structure that you can perform structural transformations on.  When you achieve the structure you want, you restore the original built-in functions.

atomsHeld  =  
      Unevaluated[2^1 * 3^2 * 5^3]  /.  {Times  ->  MyTimes,  
          Power  ->  MyPower}

Thread[atomsHeld,  MyPower]

%  /.  MyPower  ->  MyPlus

%  /.  {MyPlus  ->  Plus,  
        MyTimes  ->  Times}

This is very similar to the previous technique of turning every atom into Hold[a], in that you preserve the original structure but replace "active" parts with inactive things, and then undo it at the end.  This one replaces only the vital heads, though, not all the atoms.

A more subtle way to do the same thing is to make Module do the work for you.  You have to undo the change at the end, e.g. Plus$n -> Plus, but that's easily done with this type of rule:

  Plus -> Symbol["Plus"]

atomsHeld  = 
Module[{Times,  Power,  Plus,  
          expr}, 
expr  =  
          2^1 * 3^2 * 5^3; 
thread  =  
          Thread[expr,  Power]; 
plus  =  
          thread  /.  
            Power  ->  
              Plus; 
plus  /.  {Plus  ->  
              Symbol["Plus"],  
            Times  ->  
              Symbol["Times"]}
]

Advanced note:
If you like the Module technique and are too lazy to write out the s -> Symbol["s"] rules, or if you're using generated code and must compute those rules rather than type them in, here is a way to automate the x$n -> x rules.  It uses a slight hack:  you declare an extra local variable in the Module, which remains unused except for being passed to the function that creates the x$n -> x rules.  The reason it is so passed is to provide the value of n.  You can't use assume that $ModuleNumber will have the value you want at the end of the main Module, since functions called during execution of the Module's body may have had module's themselves, hence increasing $ModuleNumber beyond its original value.

UndoModuloLocals[sampleSym_Symbol] :=
Module[{sampleName, suffix, suffixLen, nameForm},
sampleName  =  
            SymbolName @ 
              Unevaluated[sampleSym]; 
suffix  =  
            StringTake[
              sampleName,  {StringPosition[
                    sampleName,  "$"][[-1,  
                    1]],  -1}]; 
suffixLen  =  
            StringLength[
              suffix]; 
nameForm  =  "*"  <>  
              suffix; 
s_Symbol  :>  
            With[{str  =  
                  SymbolName @ 
                    Unevaluated[s]}, 
Symbol @ 
                  StringDrop[str,  -suffixLen]  /;  
                StringMatchQ[str,  nameForm]
]
]

Module[{Times,  Power,  Plus,  expr,  
        sampleSym}, 
expr  =  
        2^1 * 3^2 * 5^3; 
thread  =  
        Thread[expr,  Power]; 
plus  =  
        thread  /.  Power  ->  Plus; 
plus  /.  
        UndoModuloLocals[sampleSym]
]

Use Block to temporarily nullify built-in or user-defined functions

One of my favorite techniques is to use Block to deactivate built-in functions for a while so I can safely work with expressions as meaningless structures.

I don't do much mathematics myself, but one question at the Chicago 1998 conference was how to prevent a mathematical function, perhaps it was Integrate, from acting until he had done some expanding, factoring, or other algebra on the arguments.

Suppose I have this integral:

Clear[x,  y]

Integrate[(x  +  y)^3,  x]

Now I decide I want to integrate the expanded form instead.  I can do it interactively in the front end by using the "Evaluate In Place" feature:

Integrate[Expand[(x  +  y)^3], x]

Integrate[(x^3) + 3 (x^2) y + 3 x (y^2) + (y^3),  x]

One way to do it programmatically is to deactive Integrate long enough to apply transformations:

Block[{Integrate}, 
int  =  
        Integrate[(x  +  y)^3,  x]; 
exp  =  
        MapAt[Expand,  int,  
          1]; 
exp
]

From the final form, it's obvious that it worked.  We could verify it by printing the intermediate expression while still in the Block:

Block[{Integrate}, 
int  =  
        Integrate[(x  +  y)^3,  x]; 
exp  =  
        MapAt[Expand,  int,  1]; 
Print["exp = ",  
        exp]; 
exp
]

Assistants in figuring things out

An assistant to understanding:  MapAt or ReplaceAll a Button to prominently display what targets are hit by your operation.

In the last section, toward the end I suggested a Hold-like wrapper that would display itself as a frame, which is less obtrusive visually than Hold[...] wrapped around everything in the expression.

In that vein, here is a technique that sometimes helps in debugging.  Use Map or ReplaceAll or other operations to wrap Button, or some other prominently visible markup, around certain targets, especially if you're not sure what the targets will be.

Map[Button,  
      ToExpression["2 + 4 I - 5/7",  InputForm,  
        HoldForm],  {-1}]

Map[Button,  
      ToExpression["2 + 4 I - 5/7",  InputForm,  
        HoldForm],  {-1},  Heads -> True]

Replace[
ToExpression["2 + 4 I - 5/7",  
        InputForm,  
        HoldForm], 
num_  /;  
          NumberQ @ Unevaluated[num]  :>  
        Button[num], 
{-1}
]

NumberQ @ Unevaluated[I]

Another assistant:  ParsedForm to show how input parses, before it begins to evaluate

When I'm writing typesetting rules, or analyzing code, I often need to search for patterns in unevaluated input or code.  Sometimes the actual structure in the unevaluated form isn't what I deduce from its displayed form or my past playing with FullForm of evaluated things.

Here's a wrapper I've used for many years to show me how things parse, before they begin evaluating.

Attributes[ParsedForm]  =  HoldAll; 

Format[ParsedForm[expr_]]  :=  HoldForm[FullForm[expr]]

It reveals the parsed form of differences, fractions, and "complex" numbers.

ParsedForm[x  -  y]

ParsedForm[1/5]

ParsedForm[2  -  5 I]

This makes it obvious that these things aren't the same as you think if you call FullForm on the evaluated forms a lot.

Using HoldForm to what it looked like before evaluation

A lot of people get confused by nested scoping constructs, in particular, the automatic renaming of the inner construct's local variables, e.g. x -> x$.  Using HoldForm, you capture on film what the outer construct did to the inner construct, before the inner construct even begins evaluating:

With[{a  =  3},  HoldForm @ Module[{x},  x  +  a]]

Module[{a  =  0},  
      HoldForm @ Compile[{x,  y},  a x  +  y]]

Function[{a},  HoldForm[f[x_,  y_]  =  a x  +  y]] [
      7]

The same technique reveals that Block doesn't participate in these lexical scoping activities.  If it is inside, its variables aren't renamed:

Module[{a  =  0},  
      HoldForm @ Block[{x,  y},  a x  +  y]]

And if it is outside, it doesn't perform renaming on constructs inside:

Block[{a  =  0},  
      HoldForm @ Module[{x,  y},  a x  +  y]]

More on principles and methods

Structural operations are your friends; they work well on unevaluated expressions.

Flatten

An example of Flatten:

ClearAll[f]

Attributes[f]  =  HoldAll; 

f[Xor[
          elems___]]  := 
Replace[
Sort[
          Flatten[Hold[elems],  Infinity,  Xor]], 
Hold[
            args___]  :>  
          HoldForm[CirclePlus[args]]
]

f[Xor[Xor[1  ==  1,  Xor[0  ==  1]],  
        Xor[Xor[2  ==  1,  1  ==  0],  
          2  ==  0]]]

Here is a function automatically flattens multiple levels of itself.  It also acts as the identity on a singleton.

ClearAll[f]

Attributes[f]  =  HoldAll; 

f[args___]  /;  MemberQ[Unevaluated[{args}], _f]  :=  
      Flatten[Unevaluated[f[args]],  Infinity,  
        f]

f[singleton_]  :=  singleton

f[elems___]  :=  Hold[elems]

f[f[1,  2],  f[3,  4,  5],  f[6,  f[7,  8]]]

f[1]

Usually people try to do this with Flat, but that causes infinite recursion because Flat also interferes with pattern-matching of your rules.

ClearAll[f]

Attributes[f]  =  {HoldAll,  Flat}; 

f[singleton_]  :=  singleton

f[elems___]  :=  Hold[elems]

f[f[1,  2],  f[3,  4,  5],  f[6,  f[7,  8]]]

f[1]

Thread

If your f is already a holding function, and you want to map it across a list, of course without letting the elements of the list evaluate before f gets to them, then you can do:

List  @@  (f  /@  Hold[e1,  …,  en])

ReleaseHold @ 
      Map[f,  Hold[{e1,  …,  en}],  {2}]

But an even more compact method is Thread, which is really a controlled Listable, just one application of Listable instead of recursive application of it:

Thread @ Unevaluated @ f[{e1,  …,  en}]

If you have to express it as a pure function, e.g. if f is a two-variable function, and one argument is some fixed value, then to make it holding, you must use Function[vars, body, attrs]:

List  @@  (Function[e,  f[0,  e],  HoldFirst]  /@  
          Hold[e1,  …,  en])

ReleaseHold @ 
      Map[Function[e,  f[0,  e],  HoldFirst],  
        Hold[{e1,  …,  en}],  {2}]

However, again Thread makes it short and elegant:

Thread[
      Unevaluated @ f[0,  {e1,  …,  en}],  -1]

Here's a real use from the top-level typesetting packages:

SetAttributes[{HeldOptionQ, HeldNonOptionQ}, HoldAllComplete]

HeldOptionQ[expr_] := OptionQ @ Unevaluated[expr]
HeldOptionQ[exprs__] := Thread[Unevaluated @ HeldOptionQ[And[exprs]], And]


HeldNonOptionQ[expr_] := Not @ HeldOptionQ[expr]
HeldNonOptionQ[exprs__] := Thread[Unevaluated @ HeldNonOptionQ[And[exprs]], And]

Another real use in the typesetting packages is when I want to map MakeBoxes, or its sister Parenthesize, across a list:

Thread[
Unevaluated @ 
        Parenthesize[{exprs}, fmt, 
          CompoundExpression], 
List, 
1
]

To feed the output of MakeExpression to something else without the HoldComplete wrapper.  Or in general, any function that returns result in Hold can feed its result, sans the wrapper, to another thing.

TagBox /: 
      MakeExpression[TagBox[GridBox[boxexpr_, opts___], Grid], fmt_] := 
      Thread[Grid[MakeExpression[GridBox[boxexpr], fmt], opts], HoldComplete, 
        1]

Grid is conveniently inert; it just sits there and does nothing to its argument.  If your f doesn't sit still, use Unevaluated or Block methods:

ReleaseHold @ 
          Thread[Unevaluated @ f[#, opts], HoldComplete, 1] & @ 
      MakeExpression[GridBox[boxexpr], fmt]

Block[{f}, 
ReleaseHold @ 
        Thread[f[MakeExpression[GridBox[boxexpr], fmt], opts], HoldComplete, 
          1]
]

In general, Thread can be used to manually implement one level of Listable.

Pointwise operators:  ReplacePart, Delete, FlattenAt, MapAt

ReplacePart gives you complete power to do whatever you want, though it takes a bit more work because you have to specify all the target locations.  With it, you can implement a ReplaceAt, which gives you even finer control than Replace with level specification.

Here's an EvaluateAt function that evaluates just the subexpressions you tell it to.  I wrote this for the Further Examples during Version 3.0 development, and it's not the most efficient method, as its use of Fold makes it O(n^2), but it illustrates what you can do:

EvaluateAt[expr_, positions_] := 
      Fold[ReplacePart[#1, Part[#1, Sequence @@ #2], #2] &, expr, 
        positions]

A faster implementation would be based on the 4-argument form of ReplacePart.  I will include this in a later revision of this document.

Identify what's bad to evaluate:  the whole, or the parts, or the return value?

If the whole, then Block is one of the easiest methods

If the parts, then you're more likely to need Unevaluated or Hold* stuff.  You could use Block, but then you have to assemble a list of all the types of parts and scope their heads.

If the return value must remain unevaluated, and you're going to return it to some arbitrary function calling you as a service, rather than you passing the unevaluated result immediately to some other function in your code, then you may have to return it wrapped in Hold or some holding container.  Like MakeExpression (whose return value is in HoldComplete) or Trace (whose return value wraps stages of evaluation in HoldForm) or DownValues (whose return value represents definitions, protecting the left-hand side with HoldPattern and the right-hand side with RuleDelayed)

Some subtle topics to demystify

Functions that hold some or all their arguments, e.g. Plot, Table, and HoldComplete, get all their power of preventing evaluation from attributes.

Some Mathematica users believe that functions such as Plot, Table, and HoldComplete have magical internal code to prevent their arguments from evaluating.  Well, there is no mysterious internal magic here.  These functions get all their power from the attributes they carry, e.g. HoldFirst, HoldRest, HoldAll, HoldAllComplete.  You can endow your own functions with these attributes.

If a function is HoldFirst, it will receive its first argument unevaluated, and the others evaluated.  It's that simple.  You the user can deprive any function of its power by using ClearAttributes.  Example:  Context must receive its first argument unevaluated, since it might be a symbol with a value.

x  =  777;

Context[x]

ClearAttributes[Context,  HoldFirst];

Context[x]

SetAttributes[Context,  HoldFirst];

It's actually the top-level evaluator that decides what arguments a function receives, not the function itself.  The evaluator always looks at a function call's arguments and does pre-processing, unless the function carries the attribute HoldAllComplete.  Even the HoldAll attribute allows a few kinds of pre-processing to take effect:  Evaluate take effect, Sequence is flattened, and UpValues of the arguments do fire.

Hold is the prototypical HoldAll function:

Attributes[Hold]

It lets Evaluate and Sequence do their thing:

Hold[Evaluate[1  +  2],  Sequence[7,  Print[8]]]

HoldComplete is stronger; it doesn't allow even this:

HoldComplete[Evaluate[1  +  2],  Sequence[7,  Print[8]]]

But deprive of its HoldAllComplete attribute, and it becomes powerless to hold anything.  However, you'd better not do this when running in the front end, because HoldComplete is used by the typesetting code,which is an integral part of the main loop when you're in a front end.

For more information, see "A.4.1 The Standard Evaluation Sequence" in The Mathematica Book, or for even more detail, Dave Withoff's talk from the 1992 conference Course Notes.

Misconception:  Block will deactivate absolutely all properties and meaningful behavior of a symbol in Mathematica.  Wrong!  Only rewrite rules are deactivated.

Basically, a command or function that performs an action or applies a transformation, e.g. OpenWrite, Map, and so on, you can deactivate.  Block will turn off just about all the these properties of a symbol (both top-level and built-in versions of these):

$ValueTypes = {Attributes, DefaultValues, DownValues, FormatValues, 
        NValues, OwnValues, Options, SubValues, UpValues}

which are the assignments to a symbol.  This is about what you expect, and won't surprise you, though note FormatValues, which means that Block will also turn off pretty-printing rules for the symbol, a fact that is often missed, and is sometimes useful, sometimes annoying.

But some symbols have a special meaning that is recognized by some other part of the system, such as the fact that Slot is recognized by Function as labelling the function's formal variables.  It may surprise you that such extrinsic properties are not deactivated by Block!

Here are a few  categories of properties that Block will not deactivate, to give you a feeling for the limits of Block:

(1)  Attributes, e.g. Listable and HoldAll.

(2)  Names of options, e.g. PlotPoints or WorkingPrecision.

(3)  The meta-expression status of the various pattern types:  Pattern, Blank*, Repeated*, Alternatives, Optional, PatternTest, Condition, HoldPattern (formerly Literal), Verbatim.

(4)  The fact that Slot[i] and SlotSequence[i], i.e. #n and ##n,  refer to the arguments of Function[body].

(5)  The status of being a lexical scoping construct, including Module, With, Function, Compile, the Rule* and *Set* family, Condition, when it comes to things like variable renaming x -> x$.  Though Block can certainly make any of these a do-nothing command.

(6)  Lots of other magic symbols like Evaluate, Sequence, Unevaluated; and just about any symbol that is simply a name or container for data that is recognized or acted upon by an actual command or function: Rule and RuleDelayed; LinkObject, InputStream, and OutputStream; Word and Number; MessageName, Label (for Goto); many others.

Further explanation and examples:

(1)  Attributes

They do not derive their power from having rewrite rules attached to them; i.e. they don't have "function definitions".  Their power is that major subsystems of the kernel, such as the evaluator, the pattern-matcher, and lexical scoping, recognize them conferring special properties to symbols.

Block'ing HoldAll doesn't affect HoldAll functions:

Block[{HoldAll,  
        f}, 
Attributes[
          f]  =  {HoldAll}; 
f[expr_]  =  
        0; 
f[Print[3]]
]

If HoldAll lost its meaning, then f would have let Print[3] evaluate, as below.

Block[{Attributes,  
        f}, 
Attributes[
          f]  =  {HoldAll}; 
f[expr_]  =  
        0; 
f[Print[3]]
]

(2)  Option names, and symbolic option values, are recognized by the parent function, they don't have their own values.  You must Block the parent function if you want to deactivate it.

(3)  Patterns are just data types recognized as special by one major subsystem of the kernel:  the pattern-matcher.  They don't have values.

Block[{Pattern, Blank}, 
Replace[0,  
        i_Integer  :>  
          Hold[i^2]]
]

(4)  Slot variables of Function are again data types given special meaning by their parent function.  Neither of these fails, nor should it:

Block[{Slot}, 
(#  +  1) & [
        0]
]

Block[{x}, 
Function[x,  x  +  1] [
        0]
]

But this will make Function a no-op:

Block[{Function}, 
Print[ {(#  +  1) & [
            0],  Function[x,  x  +  1] [
            0]} ]
]

(5)  Module and the rest of the lexical scoping family "respect" each other by not overwriting each other's local variables (well, Rule and Set do), and by renaming each other's variables if there is potential intersection of scope.  You can make Function a no-op, but it will still be respected as a scoping construct by a With that contains it, and thus can have its variables renamed.

Here's the renaming captured:

With[{a  =  1},  
      HoldForm[ Function[x,  x  +  a][2] ] ]

Here we prove that Function is a no-op, but renaming still happens.

Block[{Function}, 

With[{a  =  
            1},  Print[ Function[x,  x  +  a][
            2] ] ]

]

(6)  Miscelleaneous meaningful names without values.

Be careful what you deactivate.  If you make Module or LinkWrite or certain other things into no-ops, you might cripple the system.

You must deactivate the symbol which owns the definitions or rules

Sometimes you may guess wrong as to which symbol owns the definitons you want to deactivate.  For instance, if you want to disable typeset output in a procedure, Block'ing StandardForm will disable few, if any, output forms.

Block[{StandardForm},  Print[x^2  -  y/3]]

But this works as you wish:

Block[{Plus,  Power,  Times},  Print[x^2  -  y/3]]

Most formatting rules are associated with individual functions, not with types like OutputForm or StandardForm.  There are exceptions; TraditionalForm carries some formatting rules (and has an auto-loading rule attached to it).

Another case:  MessageName has only a formatting rule; it's not in charge of issuing messages:

Block[{MessageName},  1/0]

Message is in charge of this:

Block[{Message},  1/0]

Why is MakeBoxes so nasty, I mean HoldAllComplete?

It's not simply a user function for typesetting.  It's a core part of the main loop when the kernel is being run in a front end.  And any expression, including Sequence[1, 2] or Unevaluated[3 + 4], could be the result of an evaluation, assigned to Out[n].  Even a HoldAll function would flatten Sequence or discard Unevaluated.

Furthermore, a user could have a universal UpValue such as

  f /: _[fExpr_f, ___] := fExpr

She might do this to define some data type that should be "slippery", and not allow things to act on it, or to make the data type also canonicalize itself or alter itself depending on the caller.  In fact, Sequence itself could almost be implemented as a universal UpValue (maybe Dave Withoff or Roman Maeder remembers if that's not quite true).
 
But it would be a disaster if one of the main components of the main loop allowed itself to be rewritten or discarded, such as the output formatter, because then this part of the main loop could not complete.

So that's why we needed a few functions able to prevent any rewrites whatsoever from occurring.

When to use the different categories of holding stuff?

Here are some categories of holding methods we've discussed:

(1) Unevaluated

(2) the Hold* family and ReleaseHold

(3) give my function f some Hold* attribute

(D) HoldPattern is Unevaluated for patterns, but it can occur at any depth, and no matter where it occurs, it is transparent to the pattern matcher.  For purposes of pattern-matching, it's as if the HoldPattern wrapper isn't there, yet its effect is felt because it prevented evaluation at storage-time of the rule.

This section isn't very polished, but here are some of my thoughts on when to use each.

(1)  Use Unevaluated for one-shot passing of unevaluated argument.

(2)  Use Hold containers if you need to play with an expression for a while, can't just have it sit still for one operation.  Or if you need to return a value unevaluated.  Anything you return from a function will instantly get fully evaluated, so you have to use a protective container.

(3)  When your function most of the time needs to operate on held thing.

- anything that acts on a symbol itself as a name.  Context, AppendTo, SetDelayed.

- If you're making a programming construct that must establish a special environment before executing the body, e.g. scoping of vars, setting state vars, turning on logging or tracing, trapping calls to built-ins, etc.  Iterators like Table and Plot need to pre-scope the variable.

- When your function is a formatter, whose job is simply to print the structure as is for display, speech rendering, or whatever.  This applies to tex, typeset, or other output forms.

   Another way to think of this is that output formatting is a different subsystem from evaluation, so it doesn't recognize the evaluator's special flags such as Evaluate and Sequence as anything special.

Hold vs. HoldComplete (or attribute HoldAll vs. HoldAllComplete)

When is HoldAll a strong enough attribute for your function, and when is HoldAllComplete necessary?

Unless your function must treat Sequence[...] and Evaluate[...] as generic expressions with no meaning, or it needs to prevent UpValues of its arguments from firing, then you don't need HoldAllComplete.

Ask yourself:  Why is it compelling for me to override the normal semantics of Evaluate and Sequence and UpValues, to prevent f[Evaluate[1 + 2]] from calling f[3]?
It had better be that f almost always wants to consider Evaluate a dumb expression, not something meaningful.

Not many functions carry the attribute HoldAllComplete:

Select[Names["System`*"],  
      MemberQ[Attributes  @@  ToHeldExpression[#],  
          HoldAllComplete] &]

MakeBoxes, and its sibling Parenthesize, must be able to format absolutely any expression for output, as it is a critical part of the main loop when a front end is involved.  If the result of evaluation is Sequence[1, 2], or if you display DownValues[f] and a piece of code contains Evaluate[arg], MakeBoxes must treat it as a dumb expression.

Cardinal rule:  Formatting must never evaluate what it is given.  It should simply figure out how to display it, never evaluating any parts.

Not many functions are SequenceHold, either:

Select[Names["System`*"],  
      MemberQ[Attributes  @@  ToHeldExpression[#],  
          SequenceHold] &]

Other than the Rule* and *Set* family, which need to handle an rhs (right-hand side) of Sequence[...], there is only one function that prevents flattening of sequences:  Timing.  I don't offhand know why it is more compelling for Timing to handle Sequence input than, say, the Trace* family, so let's ask someone else this question.  In other words, why is it more unreasonable to require the user to do Timing[Unevaluated[Sequence[...]]] than to require Timing[Unevaluated[Sequence[...]]]?

Myth debunking:  HoldAllComplete isn't some super insulator against the parser, against generic structural operations or pattern-finders or the like.  It is somewhat more powerful than HoldAll, in four ways, and that's it!

A function h with the attribute HoldAllComplete, such as HoldComplete, is only slightly stronger than one with the HoldAll attribute, despite its reputation as some super insulator that prevents anything from happening inside it.  The differences are for arguments at level 1 of h[...]:

(1)  Sequence won't be flattened

(2)  Evaluate won't cause evaluation.

(3)  Unevaluated won't be discarded before the argument is fed to a definition.

(4)  g[...] won't cause an UpValue for g to fire even if the rule matches.

☺  Hence, you can modify or analyze held expressions with all the familiar functional and other commands, e.g. Map, ReplaceAll, FlattenAt, DeleteCases, Count, whatever you want.

Argument evaluation precedes {Listable, Orderless, Flat, ...}, and any other structure-rewriting attributes.

Thus, if you make nested Dot calls on actual matrices, the grouping you specified will be respected, even though Dot carries the attribute Flat.  You might think it would not because if you evaluate it for abstract symbolic arguments, it is treated as if it's associative:

Dot[Dot[A,  Dot[B,  C]],  Dot[D,  B]]

But if the symbols are actual matrices, then the innermost Dot's will evaluate fully before the outer Dot acts, so it will work fine.

In some cases, you want a function to invoke attributes on the original form of the arguments, not on the post-evaluated arguments.  You do that simply by adding HoldAll to the attributes:

Attributes[f]  =  {Flat};

SetAttributes[f,  HoldAll];

f[whatever]  :=  whatever

Wrapping an argument in Unevaluated does NOT prevent that argument's head from exercising its UpValues!

ClearAll["a"]; 
a  /:  _[___,  a,  ___]  :=  (Print["a fired"];  
        Null)

f[x_]  :=  HoldComplete[x]

f[a]

f[Unevaluated[a]]

The reason is that Unevaluated simply ensures that the symbol 'a' is passed to f in original form, then Unevaluated disappears.

So how do you assign new values to it?  Set and Unset and family don't work:

a  =.

a  =  0;

? a

TagUnset[
      Unevaluated[a], 
HoldPattern[
        HoldPattern[
_[___,  
            a,  ___]
]]]

??  a

HoldPattern @ HoldPattern[a]  =  0

? a

Print @ Unevaluated @ Definition[a]

Print @ Unevaluated @ FullDefinition[a]

This is a puzzle for the reader.

"Non-standard Evaluation":  That unexplained complicated thing.

Listing of types of special evaluation

There are different categories of  non-standard evaluation.

(1)  Left-hand side of assignments (NOT rules!) ∈ {*Set* and *SetDelayed* family, AddTo & SubtractFrom & TimesBy & DivideBy, AppendTo, PrependTo}.  Hopefully this is a complete listing of destructive functions in Mathematica.
How they are special:  They evaluate head and args, but don't let head act on args.  Of course, if head is a holding container, then args won't even evaluate, so this is consistent with evaluating ordinary expressions.  You could just about simulate what the partially evaluated lhs will be in the stored assignment:

H[e1,  …,  en]  :=  rhs

by evaluating the head and args separately, then sticking them into a template

HoldComplete[ #1[##2] ] & [H,  e1,  …,  
      en]

(2)  Iterators ∈ {Table & Do & While & For, Sum & Product, Plot and Play family},
but NOT functional iterators or recursors {Nest and Fold family, Array, Map and its many related things)
How they are special:  They dynamically scope the iterator variables (found in rgs 2 and beyond) then evaluate the iterand (arg 1) for all values of the iterators in sequence.

(3)  Misc. control structures:  {And, Or, If, Which, Switch)
How they are special:  They basically go from left to right, but don't necessarily evaluate all arguments.  In fact, except for the short-circuit And and Or, they are guaranteed not to evaluate all args if there are two or more branches (a single branch would be a degenerate case for If, Which, and Switch).

Switch[0, 
_String,  
      Print["String"], 
_Symbol,  
      Print["Symbol"], 
_Integer,  
      Print["Integer"]
]

(4)  Scoping constructs:  Module, With, Block, Function, Compile, Condition (of course, the *Rule* and *Set* family are scoping constructs, too, but when categorizing things according to uneval'n behavior, they don't belong in this category).
How they are special:  

Short Version:
- Evaluate initializations of localvars
- Perform actual scoping of declared local vars by either temporarily forgetting their own values (dynamic scoping) or by marking their occurrences in unevaluated body.
- Evaluate body (either with its fixed set of markings, known as static scoping; or with no markings cuz original symbols are being used simply with new values, known as dynamic scoping)

(5)  Miscellaneous:

Many others query or modify their argument, like Context and Protect, which act on symbols.  Nothing special; they just need to receive the symbol intact in case it has a value.

Some things set up a special environment, such as the Trace* and Stack* family, which turn on extra logging info.

Long Version:
First they look at the local variable declaration.  If there are any initializations, they evaluate those, in the outside scope.
Then they "perform localization" of the declared local vars.
Finally they evaluate the body with this localization "in effect".

ScopingConstruct[{v1  =  a1,  …,  
        vn  =  an}, 
body
]

"perform localization":

- Block simply saves the original values of the specified symbols then clears them.

- All the others, which are static scopers, take each local variable x, scan the unevaluated body for occurrences of x that are owned by this scoping construct, and mark them.  In the case of Module, the marking is visible at top-level:  x is replaced by a new, unique symbol x$n.  In the others, the marking stage cannot be captured on film!

"in effect":

  - For Block, the symbols you specified simply have temporary amnesia.  The body is executed in an environment where any time these symbols arise in the computation, whether they were originally in the text of body's code or not, they'll have the temporary values (or lack of values).
  
  - For static scopers, the unevaluated body has already had all owned instances marked.  In the case of Module, the dummy symbols will get evaluated when the evaluator reaches them [their turn comes up].  In the others, they do instant substitution, ReplaceAll-style (forgetting different levels of scoping respect, please), on the body before evaluating, so the "temporary variables" are too ephemeral for top-level film capture (unless withoff or bruce knows some method I don't).

Generating list of built-in funcs with Hold attributes

\(mappings\  = \ 
      Cases[Names["System`*"], 
symName_String\  :> \ 
          With[{holdAttrs\  = \ 
                Select[Attributes\  @@ \ ToHeldExpression[symName], \ 
                  StringMatchQ[ToString[#], \ "*Hold*"] &]}, \ \((Symbol[
                    symName]\  -> \ holdAttrs)\)\  /; \ 
              holdAttrs\  =!= \ {}]
]; \)
{funcsWithHoldAttrs,  
        holdAttrs}  =  {Identity[#1],  Union  @@  #2} &  @@  
        Thread[mappings,  Rule];

holdAttrs

ordinaryHoldFuncs  =  
      First  /@  Select[
          mappings, 
MemberQ[#[[2]],  
              HoldAll  |  HoldAllComplete  |  HoldFirst  |  
                HoldRest  |  SequenceHold] &]

nHoldFuncs  =  
      First  /@  Select[
          mappings, 
MemberQ[#[[2]],  
              NHoldAll  |  NHoldFirst  |  NHoldRest] &]

Select[Names["System`*"],  
      MemberQ[ToExpression[#,  InputForm,  Attributes],  
          NHoldAll  |  NHoldFirst  |  NHoldRest] &]

Always anticipate that users might send Unevaluated arguments into your function!
"Add a mental red flag to your programming habits"

Here I'm referring to any uses you make of the arguments passed to your function.  Take this:

FindThem[expr_,  patt_,  
        opts___]  := 
Module[{ ... }, 
Cases[Unevaluated[expr],  
            Unevaluated[
              patt]]; 
 ... 
]

If you want your function to "respect" Unevaluated as specified by the user, you have to wrap every instance of your pattern variables (in the example above, those are expr, patt, and opts) in Unevaluated when you pass it on to some built-in function (or even another top-level function).

Otherwise, the arguments carefully protected by the user will get evaluated when you operate on them.  I call these evaluation leaks, and they're very important to avoid in typesetting or code analysis tools.

Let's say you write a function to insert a given expression between every consecutive pair of elements in another expression.  Here's one way you might write it:

Clear[Intercalate]
Intercalate[list_, object_] := 
      Insert[list,  object,  List /@ Range[2, Length[list]]]

Works fine for "ordinary" expressions:

Intercalate[{1,  2,  3},  x]

But not for unevaluated stuff:

Intercalate[Hold[1,  2,  3],  Unevaluated @ Print[4]]

So here's another implementation that tries to keep the elements unevaluated until the end:

Intercalate[list_, 
        object_] := 
      Insert[list,  Unevaluated[object],  
        List /@ Range[2, Length[list]]]

Intercalate[Hold[1,  2,  3],  Unevaluated @ Print[4]]

But it doesn't work if the first argument is an unevaluated expression:

Intercalate[Unevaluated[2 * 3 * 4],  x]

From Times[2, 3, 4], it should have produced Times[2, x, 3, x, 4], i.e. 24 x^2, but the Times[2, 3, 4] collapsed to 24 too soon.

Looking back at our code, we realize that we forgot to wrap all our uses of list in Unevaluated:

Intercalate[list_, 
        object_] := 
Insert[
        Unevaluated[list], 
Unevaluated[
          object], 
List  /@  
          Range[2, 
            Length @ Unevaluated[list]]
]

Intercalate[Unevaluated[2 * 3 * 4],  x]

⚠ Check your entire function body for all occurrences of the pattern variables, and if they are passed to another function, wrap them in Unevaluated!

Now, for some functions, notably the whole class of functions we might dub "mathematical functions", this is probably pedantic and inconvenient.  Mathematical functions want to operate on and yield fully evaluated algebraic or numeric expressions.

But for any purely structural command - any auxiliary functions or utilities that might fall in the category of "Programming Functions" - they should be capable of acting on unevaluated expressions!

General Principle:

Protect your uses of the incoming variables from default interpretation by the language if the arguments are either passed with an explicit flag to prevent interpretation (Unevaluated) or the semantics of your function naturally doesn't want to use the default interpretation (e.g. a function that dumbly counts occurrences of things, who cares if "things" includes fancy objects like patterns).

Miscellaneous advanced techniques, and subtle topics

Using tests on patterns:
  /; MyTestQ @ Unevaluated[p]
instead of
  /; MyTestQ[p]

Patterns can be specified in two ways:

(1)  Structure.
Using the Blank* family, Pattern, Alternatives, Repeated and RepeatedNull, Optional

Examples

n_Integer

{n_Integer,  x_Real}

f[elems__,  n_Integer]

_Integer  |  _Rational  |  _Real

{z_Complex,  {_Real,  _Real} ... }

(2)  Boolean tests.
Using PatternTest (patt?func) or Condition (patt /; expr)

Examples:

n_Integer?Positive

x_String?MyTest

PatternTest (patt?func) and Condition (patt /; expr), are unlike the components of the pattern language because they perform evaluation on the prospective match, or parts thereof, instead of simply checking structure.  By default, they will evaluate each and every prospective match.  If you're searching something that contains function bodies, rules, or any sort of unevaluated code, then these tests will evaluate those things while checking if they match!  This is often the wrong thing to do, and if the unevaluated code contains things like assignments, it will change the state of your Mathematica session.

Hardly anyone is accustomed to this subtlety of pattern tests, so you have to train yourself to remember it, setting a mental flag on your usage of PatternTest and Condition.

Here's a surprisingly realistic example of how casual use of PatternTest can cause code to execute.  The user wants to find all Cell options whose values are themselves lists with suboptions.

thingsThatAreSubOptions  =  
      Cases[
Options[
          Cell], 
(Rule  |  RuleDelayed)[optName_,  
          optValue_List  /;  
            Not @ FreeQ[
                optValue,  _?OptionQ]]
];

Slot[1]Slot[1]

Whoa, why did red-underlined Slot[1] get written to a cell??

Answer:  One of the options of Cell is ButtonBoxOptions, which provides defaults for things like ButtonData :> data and ButtonFunction :> func.  Notice that the latter are delayed rules, because their rhs contains code!  Our condition on optValue_List used the very aggressive FreeQ test, which searches all levels of an expression for a match of the pattern.  The pattern we asked FreeQ to search for was _?OptionQ, which evaluates OptionQ on every prospective match!  Since FreeQ tests every subexpression from the top on down to the atoms, this evaluates code inside of ButtonFunction, particularly a pure function involving NotebookApply.  That's what printed then Slot[1]'s.

Here are a few other common types of tests.  The first in each pair carelessly evaluates; the second is the corrected version with no evaluation leaks.

\( (*\ \(Incorrect\)\(:\)\ *) 
things_List\  /; \ 
      Length[things]\  ≥ \ 
        2

 (*\ \(Correct\)\(:\)\ *) \)
things_List  /;  
      Length @ Unevaluated[things]  ≥  2

\( (*\ \(Incorrect\)\(:\)\ *) 
num_?
      NumberQ

 (*\ \(Correct\)\(:\)\ *) \)
num_?(Function[e,  NumberQ @ Unevaluated[e],  
          HoldAllComplete])

\( (*\ \(Incorrect\)\(:\)\ *) 
args___\  /; \ 
      FreeQ[{args}, \ _Rule\  | \ _RuleDelayed]

 (*\ \(Correct\)\(:\)\ *) \)
args___  /;  
      FreeQ[Unevaluated[{args}],  _Rule  |  _RuleDelayed]

Personally, I hate the appearance of x?(Function[...]) so I either define my own HoldAll or HoldAllComplete test function to make the code clearer:

x_?HeldNumberQ

or I use Condition, where I can make the code a little clearer by naming the parts I want to reference.

In general, the handful of raw objects of Mathematica are often specified using these patterns:

  x_Integer
  x_Rational
  x_Real
  x_Complex
  
  x_String
  x_Symbol
  
  Technically, these patterns catch more than the raw atoms.  Integer[0, "Hello"] is a perfectly valid expression whose head is Integer, therefore it matches _Integer.  In practice, rarely do these occur, so it would just make code scary looking to use anything other than the common and almost-correct idioms.
  
    But if you're writing advanced code that must not have any evaluation leaks, e.g. typesetting code or code analysis tools, you need the bullet-proof version.

Here's a template for bullet-proof pattern test:

x_RawType /; AtomQ @ Unevaluated[x]

where RawType ∈ {Integer, Rational, Real, Complex, Symbol, String}.

Often you won't need the AtomQ test, though, because you're selecting matches using one of the family of commands that takes a level specification, such as Replace, Cases, or MemberQ.  In that case, you can give a levelspec of {-1}, or {Infinity}, to the main command, which is a nice way to restrict the search space, relieving some of the burden on the actual pattern.

Template examples:

Cases[expr,  
      s_Symbol  :>  Context[s],  {-1}]

MemberQ[expr,  s_String ,  {-1}]

Replace[expr,  
      x_Real  :>  Sqrt[x],  {-1}]

You could define test to detect potentially dangerous subexpressions if you wish.  Look for expressions whose head has a Hold* attribute:

Attributes[HoldQ]  =  HoldAllComplete; 

HoldQ[
        s_Symbol  /;  
          AtomQ @ Unevaluated[s]]  := 
MemberQ[
        Attributes[s],  
        HoldFirst  |  HoldRest  |  HoldAll  |  
          HoldAllComplete]

ContainsUnevaluatedQ[expr_]  := 
MemberQ[
        Unevaluated[expr],  h_Symbol?HoldQ[___],  {0,  -1},  
        Heads -> True]

ContainsUnevaluatedQ[Options[Cell]]

You can also return a list of them to see what you're up against:

Cases[Options[Cell],  h_Symbol?HoldQ[___],  {0,  -1},  
      Heads -> True]

Obviously, many of these RuleDelayed's have atoms as their parts and are safe to evaluate, so you might want to prune this down to more dangerous things:

DeleteCases[%,  _  :>  _String  |  _Symbol]

Sometimes you want to specify that an argument not match a pattern, and since there is no PatternNot primitive in the language, you need to do this in a Boolean test.  One way is to use MatchQ.

f[x_, y_ /; Not @ MatchQ[Unevaluated[y], _List]]

⚠  Warning:  Before Version 3, you were virtually guaranteed that _Symbol would match only the atomic data type of 'symbols',  But in Versions 3 and beyond, Symbol can also be used as a function, e.g. Symbol["a"] ⟹ a, so if your program is dealing with unevaluated input or code of any sort, you have to now deal with the fact that _Symbol matches two classes of legitimate expressions:  atomic symbols, and calls of the Symbol function.  Example:

Symbol["a"]

Through[{FullForm,  AtomQ,  Head}[%]]

A weird pseudo-Symbol that you might run in to:  if you remove a symbol which is still currently in use in some definitions, then it will be replaced by an entity which prints like Removed["symName"] and which is considered an atom and has head Symbol.  It will match _Symbol, and you can assign to it, look up its information or context, and most if not all that other stuff you can do with symbols, but it's strange because it has no input form (that I know of) and Names[] seems unaware of its existence in any context, let alone the one that Context claims it is in.

x  =  doomed;  0

Remove["doomed"]

x

Through[{FullForm,  AtomQ,  Head}[x]]

isSymbol[_Symbol]  =  True; 
isSymbol[_]  =  False; 
isSymbol[x]

Evaluate[x]  =  777

Unevaluated @ Information[x]  /.  OwnValues[x]

Unevaluated @ Context[x]  /.  OwnValues[x]

Characters[%14]  // FullForm

Names["Global`*oom*"]

Names["Global`*"]

Select[Names[],  StringMatchQ[#,  "*doom*"] &]

Trott-Strzebonski method for In-Place Evaluation

One of the all-time cleverest idioms I've seen; this was discovered by Michael Trott and Adam Strzebonski a few years ago.  The template is a rule of the following form:

   lhs :> With[{eval = lhs}, eval /; True]

Suppose you want to replace a bunch of things inside a held expression, and have the replacements evaluate.  You don't want to evaluate the whole, just the pieces that are targeted.

SeedRandom[2^51]

jaggedTable  =  
      Table[Random[
          Integer,  {0,  5}],  {Random[Integer,  {1,  4}]},  {Random[
            Integer,  {1,  4}]},  {Random[
            Integer,  {1,  4}]}]

heldTable  =  Apply[Hold,  jaggedTable,  {0,  1}]

heldTable  =  Apply[Plus,  heldTable,  {-2}]

heldTable  /.  
      p_Plus  :>  
        With[{eval  =  p},  eval  /;  True]

You can also do this with ReplacePart, but it's harder to code, and has a worse time and space complexity for a large number of substitutions (and using Fold with ReplacePart would be O(n^2)).

My Block trick for trapping calls to built-in functions

Prototypical example to use as a template:

wasProtected  =  Unprotect[Get]; 

$TrapGet  =  True; 

\(g_Get\  /; \ $TrapGet\  := 
Block[{$TrapGet\  = \ 
            False}, 
Print[
          Unevaluated[
            g], \ " was evaluated!"]; 
g
]
\)
Protect  @@  wasProtected;

You are quite free to make the lhs of the rule more complicated; perhaps you need to name some arguments of Get so you can refer to them.  The same template applies. For instance:

\(Get[filename_String, \ 
          opts___]\  /; \ $TrapGet\  := 
Block[{$TrapGet\  = \ False}, 
If[
          StringMatchQ[
            filename, \ "http://*"], 
Run["wget", \ 
            filename], 
Get[
            filename]
]
]\)

I recommend that you hang the condition /; $TrapGet off the lhs, not the rhs, because then you can revoke the definition by plopping the whole lhs into an Unset command:

Unset[Get[filename_String,  opts___]  /;  $TrapGet]

Also, an important limitation:  can't be used for recursive, e.g. Module as tgayley pointed out?

But using a count variable and checking EvenQ[count++] might do it if there is one recursion per trap?  Never did find out for sure.

Another limitation:  probably can't trap SetDelayed, Condition, Block, or CompoundExpression with it.  Try to find work-around for this!

One alternative to Block is my old method:  manually set and unset the var, must wrap in CheckAbort to prevent dirty state change.

One-step evaluation using expr /. DownValues[f], and family.

Let's say you want to Map or MapAt an existing function f deep into a held expression, and simply have f perform its rewrite rule on the argument without any more evaluation.

ClearAll[f, array]

f[x_]  :=  x  +  x^2  +  x^3

array  =  Array[Subtract,  {3,  4}]

Map[f,  Hold[Evaluate[ array ]],  {3}]

%  /.  DownValues[f]

You could write a routine to extract the names of symbols occurring at each stage, accumulate their various *Values into a list, and apply that list of rules.  To attempt to simulate the evaluator, you'd have to make sure UpValues fires befored DownValues, and lots of details like that.

You could Nest this routine n times, or do FixedPoint of it to crudely simulate the evaluator.

Traps used for tracing should not evaluate what they print or memoize

Many of you have written things like this to see when a rule fires:

ClearAll["f"]
f[a_,  b_]  /;  (Print["a = ",  a];  
          Print["b = ",  b];  False)  :=  $Failed

f[Unevaluated[1  +  2],  Unevaluated[3*4]]

But sometimes f,whether it's yours or an internal function, will encounter things that are bits of unevaluated code, say in the middle of an evaluation, or during a trace, or whatever.  This is a case where you want to prevent evaluation:

ClearAll["f"]
f[a_,  b_]  /;  (Print["a = ",  Unevaluated[a]];  
          Print["b = ",  Unevaluated[b]];  
          False)  :=  $Failed

f[Unevaluated[1  +  2],  Unevaluated[3*4]]

Or if you really want to be defensive and are concerned that UpValues might fire on Print[thing] before Print can evaluate, use two levels of protection.  Either Unevaluated @ HoldForm[thing] or HoldForm @ HoldForm[thing], or perhaps best of all, define yourself a HoldAllComplete version of HoldForm.

How to pass arguments to HoldAllComplete functions (such as HoldComplete itself), since Evaluate no longer forces evaluation:  Function @@, With, Block, Replace, ReplacePart

.Of course, HoldAllComplete is a bit of a pain, since when you're writing code in a module and need to pass the value of a variable, like myexpr, into it, you can't use Evaluate like you could with Hold and friends.  So here is a list of some techniques for passing into HoldAllComplete wrappers:

Passing it fully evaluated:

MyHolder[#] & [myexpr]

MyHolder  @@  {myexpr}

With[{myexpr  =  myexpr}, 
MyHolder[
        myexpr]
]

As always, you can temporarily neutralize with Block.  Keep in mind that myHolder would prevent UpValues of its arguments from firing, but will not do so when you Block it, therefore it's possible for this to not be equivalent to the other techniques.

Block[{myHolder}, 
myHolder[
        myexpr]
]

Replace is useful if you know that your HoldComplete contains a particular form, e.g. s_Symbol or Plus[a_, b_], for instance if it came out of MakeExpression, or Extract or ToExpression with the container argument specified to be HoldComplete.

Replace[HoldComplete[myexpr],  
      HoldComplete[Plus[a_,  b_]]  :>  
        MyHolder[a,  b]]

Padding it one-step evaluated, or passing something you construct from parts:

With[{e  :=  Plus[a,  b]}, 
MyHolder[
        e]
]

MyHolder[myexpr]  /.  OwnValues[myexpr]

ReplacePart[HoldComplete[myexpr],  
      Unevaluated @ Plus[a, b],  {{1}}]

(* 
      This will let Set decide what to evaluate: *) 
Set  @@  
      HoldComplete[f[x_,  0],  rhs]

Use strings for symbol names or even to store FullForm of an expression

This is the extreme of preventing interpretation of your expressions:  making them no longer expressions, but raw strings.

This is mainly useful for persistent storage, and is essentially what Save does when it writes out code.

You can even use Unevaluated as a persistent head, but I don't recommend it for most cases.

Since Unevaluated is strange in acting differently depending on whether it's there before or after arg evaluation, I don't recommend using it as a persistent head until you're very comfortable with it.  Even then, someone who has to modify your code later might not be comfortable with it and might easily be misled into treating it like an ordinary head.

Its ordinary use as an ephemeral flag is fine, and not likely to cause you any problems.

Related (another example of a more general issue) issue:  when to wrap incoming argument in Verbatim in case it's a pattern and you're going to pass it to a function that does use pattern semantics when given patterns.

A related issue:  if you are quite sure that an argument should always be considered a literal expression, never a pattern, then you'd better anticipate that a user could pass a pattern there.  For instance, I once wrote a function to take a list and give you a list of all its distinct elements together with the count of their occurrences in the list:  Frequencies.

Frequencies[
        list_]  := 
{#,  Count[list,  #]} &  /@  
        Union[list];

This doesn't work if list contains some patterns!

list  =  {1,  2.5,  
        2.5,  _Integer,  _Integer,  _Real,  _Real,  _Real,  _Symbol,  _Symbol,  _Symbol};

Frequencies[list]

Well, shucks!  _Symbol occurs 3 times, not 0!  And this result implies that the original list had a total of 6 elements:

Plus  @@  Map[Last,  %]

when we know darn well it had more:

Length[list]

Some examples

I will add quite a few examples from my scratch work in the next revision of this document.

To analyze the code in a package:  read the statements from the file as a list of Hold[stmt]

Suppose you want to analyze usages in the package, e.g. symbols.

heldStatements  =  
      ReadList["MyPackage.m",  Hold[Expression]];

HoldCompleteForm:  a non-printing variant of HoldComplete (just as HoldForm is to Hold)

MyHoldForm is a little stronger than HoldForm:

(1)  Prevents Sequence and Evaluate wrappers on arguments intact (and Unevaluated, but that's as much because of not calling any code on the args)

(2)  Prevents  UpValues of its arguments from firing and thus rewriting it.

\(Attributes[HoldCompleteForm]\  = \ HoldAllComplete
\)
Format[HoldCompleteForm[expr_]]  :=  
      HoldForm @ HoldForm[expr]

This relies on the simple fact that anything deeper than level 1 in a holding container won't be touched even if it's wrapped in Evaluate or Sequence, or has UpValues.  For instance:

Hold[{Evaluate[1  +  2],  Sequence[3,  4]}]

Function[e,  {Evaluate[1  +  2],  Sequence[3,  4]}]

Hence, there was no need to use two layers of Hold.  I could have used a non-holding head at the inner level (though of course I want it to be non-printing):

Format[HoldCompleteForm[expr_]]  :=  
      HoldForm @ SequenceForm[expr]

??  HoldCompleteForm

But just as for HoldForm, several args don't work.  If you want n args, you maybe want Sequence as the displayed head, not sure.  If so, don't use SequenceForm.
(Though HoldForm of n args may have printed as Sequence in V2, not sure.)

HoldCompleteForm[Evaluate[1  +  2],  Sequence[3,  4]]

{HoldCompleteForm[Evaluate[1  +  2]],  
      HoldCompleteForm[Sequence[3,  4]]}

Another implementation of the Format rule (following $Output to be pedantic):
[Hmmm, $Output likely has FormatType->StandardForm, which isn't what we want?  Revisit this...]

Format[HoldCompleteForm[expr_]]  :=  
      ToString[Unevaluated[expr],  
        Sequence  @@  Options[$Output]]

Format[HoldCompleteForm[expr_]]  :=  
      ToString[Unevaluated[expr],  OutputForm,  
        Sequence  @@  Options[$Output]]

But this implementation is not as correct, cuz it formats it as a string, whereas normally HoldForm would format as an expression, which makes a difference if the output format is typeset.  The "output format" could be either the default (in $Output) or a one-shot deal like expr //TraditionalForm, at run-time, you just don't know.

Set and SetDelayed can be more flexible.

- Evaluate certain parts of SetDelayed rhs as exceptions
- Don't evaluate certain parts of Set rhs as exceptions

- Properly scope pattern vars of Set when conducting assignment to be stored.

I will include these examples in the next revision of this document.

Temporarily deactivate kernel functions that open files for writing

Here's a crude "scoping construct" that deactivates file writing commands for the duration of execution of its body:

$FileWritingFunctions = {Put, PutAppend, OpenWrite, OpenAppend, Save, 
        DumpSave,  Splice, Display, Write, WriteString, 
        Encode}; 

Attributes[NoFiles] = HoldFirst; 

NoFiles[expr_] := 
      Unevaluated@Block[$FileWritingFunctions, expr] /. 
        OwnValues[$FileWritingFunctions]

This is untested, but it illustrates that you can implement your own debugging/testing tools with the techniques described in this talk.