What's the difference between Inactive and HoldForm?

Updated

Both Hold and Inactive block evaluation; the key difference is that Inactive is meant to be wrapped around heads rather than a whole expression. Inactivate does this.

Inactivate[1 + 2 + 3 * 4 ^ 5 ] // FullForm
Inactive[Plus][1, 2, Inactive[Times][3, Inactive[Power][4, 5]]]

It is of course possible to use Inactive directly, and it will behave like any symbol with holding attributes.

Inactive[1 + 2 + 3 * 4 ^ 5] // FullForm
Inactive[Plus[1, 2, Times[3, Power[4, 5]]]]

But in general there is no reason to use it this way. Note that while Activate and ReleaseHold are comparable, there is no analog to Inactivate. The point is to use these auxiliary functions.

Because Inactivate wraps heads, it can accept an optional second argument constraining which heads to inactivate.

Inactivate[1 + 2 + 3 * 4 ^ 5, Plus] // FullForm
Inactive[Plus][1, 2, 3072]

Activate can similarly accept an optional second argument.

Inactivate[1 + 2 + 3 * 4 ^ 5];
Activate[%, Power] // FullForm
Inactive[Plus][1, 2, Inactive[Times][3, 1024]]

Another interesting consequence of using Inactivate is that atomic symbols will get evaluated.

Hold @ {$WolframUUID}
Hold[{$WolframUUID}]
Inactivate @ {$WolframUUID}
{"0e2497dc-9281-48f3-8e84-14b5e2587446"}

One difference is that NDSolve directly supports Inactive. It can be used to specify operators such as divergence ($\nabla\cdot$) without automatically evaluating them to components. This is described here.


Although mfvonh's answer is a nice summary of Inactive formal properties, I think it misses several important points, which are both shown in the "Scope" and "Applications" section of the documentation. For me the main point seems to be (2), as I don't know how this could be achieved using Hold.

1) Inactive can be used to illustrate formal mathematical identities, e.g.,

Table[Block[{e = Inactivate[n + m]}, e == Activate[e]], {n, 0, 3}, {m,
 0, 3}] // Grid // TraditionalForm

2) It can be used in formal mathematical manipulations (as hinted at by Szabolcs' answer), e.g.,

D[Inactive[Integrate][f[x], {x, a[x], b[x]}],x]
(*-f[a[x]] Derivative[1][a][x] + f[b[x]] Derivative[1][b][x]*)

3) It can be used for easy programmatic code transformation, as Inactivate automatically wraps around all heads:

 def = Inactivate[for[f_, max_] := For[x = 1, x < max, x++, Print@x]];
 def/.Inactivate[For[i_ = init_, i_ < max_, i_++, body_] :> Do[body, {i, init, max}]]
 (*forSquares[f_,max_]:=Do[Print[f[x^2]],{x,1,max}]*)

So the use cases are quite different from the ones of Hold/ReleaseHold. I don't think (2) could be easily achieved with Hold, and (3) is definitely more elegantly solved by using Inactivate.