I'll cover a few typical uses of `Block`, neither of which is possible using `Module` or `With`.
**Temporarily removing definitions**
When you do
Block[ {a = x}, ... ]
the original definition of `a` is effectively replaced by whatever new definition is given in the first argument of `Block`, for the duration of the evaluation of `Block` only. If we give no definition, `Block` temporarily "undefines" whatever was passed to it as first argument. This works even for built-ins:
Block[ {Print}, Print["boo!"]; ]
prints nothing.
**Temporarily redefining symbols**
`Block` is also commonly used to temporarily change the value of system variables. Take for example this simple recursive implementation of a list maximum function:
max[{a_}] := a
max[list_List] :=
With[{m = max@Rest[list]}, If[First[list] > m, First[list], m]]
For a long list it fails because the value of `$RecursionLimit` is too low. But we can increase `$RecursionLimit` only temporarily using `Block`:
Block[{$RecursionLimit = 1000}, max[RandomInteger[10000, 300]]]
**Implementing functions that localize their arguments**
Functions like `Table`, `Sum`, `Plot`, `FindRoot`, `NIntegrate`, etc. use `Block` to localize their variable.
Here's a possible implementation of a `table` function which works like `Table`:
Clear[table]
SetAttributes[table, HoldAll]
table[expr_, {x_, min_, max_, step_}] :=
Block[{x},
x = min;
Reap[While[x <= max,
Sow[expr];
x += step
]][[2, 1]]
]
We can use it just like `Table`:
table[i, {i, 1, 100, 4}]
(*
==> {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, \
61, 65, 69, 73, 77, 81, 85, 89, 93, 97}
*)
Using `Block` made sure that this function will work even if `i` has a value globally.
-------
**``Internal`InheritedBlock``**
Here it's also worth mentioning ``Internal`InheritedBlock``. Like with `Block`, any changes made to the local symbols of `InheritedBlock` are lost when it finishes evaluating. However, unlike `Block`, it keeps the original definition of the localized symbols too.
This is useful for modifying existing (or built-in) functions temporarily. Here's an example to illustrate:
`Print` does not have the `HoldAll` attribute:
Print[1 + 1]
(* ==> 2 *)
We can assign `HoldAll` to `Print` temporarily:
Internal`InheritedBlock[
{Print},
SetAttributes[Print, HoldAll];
Print[1 + 1];
]
(* ==> 1+1 *)
As soon as `InheritedBlock` exists, this behaviour is reverted:
Print[1 + 1]
(* ==> 2 *)