I think it is worth to point out another one peculiarity of `With` as compared to `Module` and `Block` which is little-known: `With` doesn't evaluate it's last argument at all, while both `Module` and `Block` evaluate their last arguments. In other words, the last argument of `With` will be evaluated only after leaving the `With` construct. This can be easily proven as follows:
With[{}, Stack[_]]
Module[{}, Stack[_]]
Block[{}, Stack[_]]
> {}
>
> Module[{}, Stack[_]]
>
> Block[{}, Stack[_]]
One can see that in the case of `With` the stack is empty because evaluation of `With` is already finished when `Stack[_]` is being evaluated, while in the case of `Module` and `Block` the `Stack[_]` is evaluated inside of the scoping construct.
----------
Another thing which is useful to know is that all these constructs support **delayed assignments** for local variables:
With[{a := Random[]}, {a, a, a}]
Module[{a := Random[]}, {a, a, a}]
Block[{a := Random[]}, {a, a, a}]
> {0.637223, 0.284761, 0.180292}
>
> {0.139856, 0.55708, 0.585556}
>
> {0.888018, 0.961141, 0.451441}
An example of use:
- [Using `With[…]` with a list specification as a variable](https://mathematica.stackexchange.com/a/204119/280)