5
$\begingroup$

Not even "formal symbols" such as \[FormalX] are guaranteed to always be symbolic. Their Protected argument is forgotten when they are used in Block and consorts, causing functions relying on symbolic variables to misbehave:

foo[n_] := Exponent[\[FormalX]^n, \[FormalX]];

foo[5]
Attributes@\[FormalX]

Table[{Attributes@\[FormalX], foo[5]}, {\[FormalX], 
  1}](*or Block[{\[FormalX]},...]*)

5

{Protected}

{{{}, 0}}

Why does Block clear Attributes? Is Unprotecting and changing a (system) symbol so common that it was decided that Block should do the Unprotecting unsolicitedly?

Is the only way to be sure that some symbol does not have an OwnValue to use Module or Block?

$\endgroup$
  • 2
    $\begingroup$ SetAttributes[x, Protected]; Table[x, {x, 2}]? $\endgroup$ – Michael E2 Aug 30 '16 at 14:24
  • 2
    $\begingroup$ That is the point of Block, isn't it? Or is your question why Table is based on Block? $\endgroup$ – Kuba Aug 30 '16 at 14:30
  • 1
    $\begingroup$ If you're looking for something to eliminate OwnValues, check out Internal`LocalizedBlock. $\endgroup$ – rcollyer Aug 30 '16 at 14:55
  • 1
    $\begingroup$ Or InternalInheritedBlock` perhaps. $\endgroup$ – Daniel Lichtblau Aug 30 '16 at 15:22
  • $\begingroup$ @DanielLichtblau that, too. But, then you have to remove those pesky *Values that remain. :) $\endgroup$ – rcollyer Aug 30 '16 at 15:37
6
$\begingroup$

It is illustrative to compare Block, Internal`InheritedBlock, Module, and With. Both Module and With create unique versions of the variables which are not accessible from the outside (lexical scoping, and not without its issues), e.g.

x = 2 y^2 - 7;
With[{y = 5}, x]
Module[{y = 5}, x]

where both With and Module return -7 + 2 y^2. With has the added ability to bypass Hold attributes, which is very useful sometimes. Because of this, it would be difficult to use them to run arbitrary code passed in by a user. In contrast, Block and Internal`InheritedBlock allow you to temporarily augment/overwrite an existing variable, and guarantee that the changes are reset.

A useful example of augmentation, is automatically resetting changes made to default Options, e.g.

Internal`InheritedBlock[{Plot},
  SetOptions[Plot, PlotStyle -> {Red, Blue, Green}];
  Options[Plot, PlotStyle]
]
(* {PlotStyle -> {Red, Blue, Green}} *)

vs

Options[Plot, PlotStyle]
(* {PlotStyle -> Automatic} *)

which can be used to generate many plots where the options are uniform, without resorting to crafting a unique theme. A more interesting example is this graphics parser which uses Internal`InheritedBlock to mimic a stack in tracking the state. If you want a more extensive augmentation, though, you still need to Unprotect the symbol. This is where Block comes in as quite often you do not want to just augment the behavior, but overwrite it entirely.

This is the use case for Plot, Table, etc. where the user supplies a symbol/expression that needs to be evaluated without worrying about whether it has *Values. Internal`LocalizedBlock extends this further by localizing things like Subscript[x, 1] which Block cannot handle.

Of course all these can be merged. Consider this answer from Leonid which traces what packages auto-load another package. It uses Module to set up a closure which uses the Villegas-Gayley pattern to augment Needs. Here Block plays the important role of blocking recursive execution.

$\endgroup$
  • $\begingroup$ Take a look here. Is our suspicion that this is a RegionPlot (not Graphics) option true? If yes, is it a bug that the option is passed down to Graphics? Just mentioning in case there's an opportunity for improvement. There's no practical problem. $\endgroup$ – Szabolcs Sep 14 '16 at 14:27
6
$\begingroup$

Block does something very simple: it just (temporarily) removes all definitions directly associated with a symbol, and nothing else. That includes:

  • OwnValues, DownValues, UpValues, SubValues, NValues, FormatValues, DefaultValues, Messages, Attributes

All these are considered to be associated directly with the symbol, in the sense that Attributes[x] are considered to belong to x and not to Attributes.

Don't think of this as "Block does Unprotect, then block does ClearAll". Think of it as all symbol properties being reset to the default value, which is empty, {}, except for some special builtins such as $ContextPath or $Assumtpions.

Related:

$\endgroup$
  • $\begingroup$ One could argue that the documentation is the root of a confusion since it repeats "values" which may be understood as Attributes are excluded. $\endgroup$ – Kuba Aug 31 '16 at 9:44
0
$\begingroup$

This is not an answer as to why, wolfram-language-design wise, but to how:

It seems Block[{x = new}, ...code...] effectively does the following:

newValue = new;
allValues = allValuesAndAttributesAssociatedWith[x];
Unprotect[x];
ClearAll[x];
x = newValue;
try {
    ...code...
} finally {
    allValuesAndAttributesAssociatedWith[x, allValues]
}

where the pseudo-code finally-block is executed no matter what happens inside ...code..., even on Abort or Throw.

I tried to capture the exact order of execution of all steps.

ClearAll[x] clears all kinds of attributes and values associated with x, including Messages, FormatValues etc.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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