32
$\begingroup$

I read the answers to this question (What are the use cases for different scoping constructs?) and this one (Condition, Block, Module - which way is the most memory and computationally efficient?).

According to those, Block is safer (if something aborts, it restores the values) and faster (perhaps something to do with the low-level pointer redirection that I believe it uses) than Module, but less memory-efficient if the function is defined a certain way.

That being said, (1) why does Leonid say that Module is "safer" when it doesn't have as-good garbage collection, and (2) if I am to use Module for most of the time, what are some of the "advanced" uses which require Block?

$\endgroup$
2
  • 2
    $\begingroup$ With Block[], you can localize changes to system constants, e.g. Block[{$RecursionLimit = Infinity}, (* stuff *)]; you can't do that with the other scoping methods. $\endgroup$ Oct 4, 2012 at 22:17
  • $\begingroup$ For another perspective on temporal efficiency there is this question, mathematica.stackexchange.com/questions/8226/…. $\endgroup$ Oct 5, 2012 at 6:22

2 Answers 2

47
$\begingroup$

Safety

Module is safer than Block because:

  • It is a lexical scoping construct, which means that variable bindings are only tied to a specific piece of code. Variables outside that piece of code are never affected by these bindings.

    In contrast, Block basically binds a variable to a piece of execution stack, not a piece of code. Such bindings are much harder to understand and debug, since execution stack is not something carved in stone, it is dynamic and usually data-dependent.

  • The way Module resolves variable collisions is such that the integrity of inner or outer level bindings is never broken (at least in theory - in practice the lexical scoping is emulated in Mathematica and can be broken, but let's say this is very unlikely to happen by itself).

    In contrast, nested Block-s will simply have the variable value be the one (re)defined most recently, and also those different Block-s can be in different functions - while nested Module-s normally are in one function.

Both these points lead to the same conclusion that code which uses Block is harder to understand and debug. Basically, it is almost the same as using global variables (which are however guaranteed to get back their values after Block executes).

Advanced uses of Block

Probably the main one is to change the order of evaluation non-trivially, in a way not easily possible with other constructs. Block-ed functions or symbols forget what they were, and therefore evaluate to themselves. This often allows to alter the order of evaluation of expressions in non-trivial ways.

I will show a couple of examples.

Example: emulating OptionValue

Here is one, from this answer: a possible emulation of OptionValue, which is one of the most magical parts of the pattern-matcher:

Module[{tried},
  Unprotect[SetDelayed];    
  SetDelayed[f_[args___, optpt : OptionsPattern[]], rhs_] /; 
    !FreeQ[Unevaluated[rhs], autoOptions[]] :=
     Block[{tried = True},
       f[args, optpt] :=  
         Block[{autoOptions}, autoOptions[] = Options[f]; rhs]] /; ! TrueQ[tried];
  Protect[SetDelayed];]

the usage:

Options[foo] = {bar -> 1};
foo[OptionsPattern[]] := autoOptions[]
foo[]


(* {bar -> 1}  *)

Villegas-Gayley trick of function's redefinition

(call:f[args___])/;!TrueQ[inF]:=
   Block[{inF=True},
     your code;
     call
   ]

allows you to inject your own code into another function and avoid infinite recursion. Very useful, both for user-defined and built-in functions

Safe memoization

fib[n_]:=
 Block[{fib},
   fib[0]=fib[1]=1;
   fib[k_]:= fib[k] = fib[k-1] + fib[k-2];
   fib[n]
 ]

The point here being that the memoized values will be cleared automatically at the end.

Making sure the program does not end up in an illegal state in case of Aborts or exceptions

a = 1; b = 2;
Block[{a = 3, b = 4},
   Abort[]
]

The point here is that the values of a and b are guaranteed to be not altered globally by code inside Block, whatever it is.

Change the order of evaluation, or change some function's properties

Comparison operators are not listable by default, but we can make them:

Block[{Greater},
  SetAttributes[Greater, Listable];
  Greater[{1, 2, 3, 4, 5}, {5, 4, 3, 2, 1}]
]

(*  {False, False, False, True, True}  *)

Preventing premature evaluation

This is a generalization of the standard memoization idiom f[x_]:=f[x] = ..., which will work on arguments being arbitrary Mathematica expressions. The main problem here is to treat arguments containing patterns correctly, and avoid premature arguments evaluation. Block trick is used to avoid infinite recursion while implementing memoization.

ClearAll[calledBefore];
SetAttributes[calledBefore, HoldAll];
Module[{myHold},
   Attributes[myHold] = {HoldAll};
   calledBefore[args___] :=
     (
       Apply[Set,
         Append[
           Block[{calledBefore},
             Hold[Evaluate[calledBefore[Verbatim /@ myHold[args]]]
           ] /. myHold[x___] :> x
         ], True]];
       False
     )
]

Block is used here to prevent the premature evaluation of calledBefore. The difference between this version and naive one will show upon expressions involving patterns, such as this:

calledBefore[oneTimeRule[(head:RuleDelayed|Rule)[lhs_,rhs_]]]
calledBefore[oneTimeRule[(head:RuleDelayed|Rule)[lhs_,rhs_]]]

(*
  False
  True
*)

where the naive f[x_]:=f[x]=... idiom will give False both times.

Creating local environments

The following function allows you to evaluate some code under certain assumptions, by changing the $Assumptions variable locally. This is just a usual temporary changes to global variables expressed as a function.

ClearAll[computeUnderAssumptions];
SetAttributes[computeUnderAssumptions, HoldFirst];
computeUnderAssumptions[expr_, assumptions_List] := 
   Block[{$Assumptions = And[$Assumptions, Sequence @@ assumptions]}, 
       expr];

Local UpValues

This example came from a Mathgroup question, where I answered using Block trick.

The problem is as follows: one has two (or more) long lists stored in indexed variables, as follows:

sym[1] = RandomInteger[10^6, 10^6];
sym[2] = RandomInteger[10^6, 10^6]; 
sym[3] = ...

One has to perform a number of operations on them, but somehow knows (symbolically) that Intersection[sym[1],sym[2]] == 42 (not true for the above lists, but this is for the sake of example). One would therefore like to avoid time-consuming computation

Intersection[sym[1],sym[2]];//AbsoluteTiming

(* 
   {0.3593750, Null}
*)

in such a case, and use that symbolic knowledge. The first attempt is to define a custom function like this:

ClearAll[myIntersection];
Attributes[myIntersection] = {HoldAll};
myIntersection[sym[i_], sym[j_]] := 42;
myIntersection[x_, y_] := Intersection[x, y];

this uses the symbolic answer for sym[_] arguments and falls back to normal Intersection for all others. It has a HoldAll attribute to prevent premature evaluation of arguments. And it works in this case:

myIntersection[sym[1], sym[2]]

(* 42 *)

but not here:

a:=sym[1];
b:=sym[2];
myIntersection[a,b];//Timing

(*  {0.359,Null} *)

The point is that having given myIntersection the HoldAll attribute, we prevented it from match the sym[_] pattern for a and b, since it does not evaluate those and so does not know what they store, at the moment of the match. And without such capability, the utility of myIntersection is very limited.

So, here is the solution using Block trick to introduce local UpValues:

ClearAll[myIntersectionBetter];
Attributes[myIntersectionBetter] = {HoldAll};
myIntersectionBetter[args___] :=
   Block[{sym},
      sym /: Intersection[sym[a_], sym[b_]] := 42;
      Intersection[args]];

what this does is that it Block-s the values of sym[1], sym[2] etc inside its body, and uses UpValues for sym to softly redefine Intersection for them. If the rule does not match, then the "normal" Intersection automatically comes into play after execution leaves Block. So now:

myIntersectionBetter[a,b]

(* 42 *)

This seems to be one of the cases where it would be rather hard to achieve the same result by other means. Local UpValues I find a generally useful technique, used it in a couple more situations where they also saved the day.

Enchanced encapsulation control

This will load the package but not add its context to the $ContextPath:

Block[{$ContextPath}, Needs[your-package]]

This will disable any global modifications that the package being loaded could make to a given symbol:

Block[{symbolInQuestion}, Needs[the-package]]

There are many more applications, Block is a very versatile device. For some more intricate ones, see e.g. this answer - which provides means for new defintions to be tried before the older ones - a feature which would be very hard to get by other means. I will add some more examples as they come to mind.

$\endgroup$
6
  • $\begingroup$ What exactly does Block do in the noUsage function? $\endgroup$
    – Rojo
    Oct 5, 2012 at 3:15
  • $\begingroup$ WOw, again an amazing answer +1 $\endgroup$ Oct 5, 2012 at 8:00
  • $\begingroup$ Great answer... thanks for sharing! $\endgroup$
    – sebhofer
    Oct 5, 2012 at 9:34
  • $\begingroup$ Regarding the safe memory usage when defining functions, which was fib in your example, what's the danger of having all those extra DownValues for fib? In fact, if I kept them, the next time I called fib it would be faster, right? In other words, what is the use of constraining the self-made DownValues (f[x_]:=f[x_]=...) with Block? Does it somehow cause a memory leak? $\endgroup$
    – VF1
    Oct 5, 2012 at 14:18
  • $\begingroup$ @VF1 This depends on the situation. Sometimes you want to keep them for future calls. Sometimes, however, they are only needed to speed up that single computation, and future calls are unlikely to hit the same arguments. In those cases, keeping these extra defs would just slow down the hash lookup and hog the memory, so they better be removed after the call. Block allows you to do that automatically. B.t.w., a long overdue here on SE question IMO (your main one I mean). Thanks for the accept. $\endgroup$ Oct 5, 2012 at 14:22
14
$\begingroup$

Briefly, Block allows you to temporarily change global definitions and functions in a way that Module does not. This is both its strength and weakness.

If you use Block[{x = 5}, (* stuff *)] without realizing that something deep inside "stuff" relies on x you may break things. On the other hand you can use this power intentionally to do some interesting things.

Change global settings

With a recursive definition for Fibonacci numbers:

f[0] = 0; f[1] = 1;
f[n_] := f[n] = f[n - 1] + f[n - 2]

We need a larger value for $RecursionLimit to get the 300th number in the series:

Block[{$RecursionLimit = 500}, f @ 300]

222232244629420445529739893461909967206666939096499764990979600

Change the meaning of built-in syntax

listSample := {12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5};

Block[{Times = List}, listSample]
{{12, 12.5, 13, 13.5, 14, 14.5},
 {12, 12.5, 13, 13.5, 14, 14.5}}

Additional example (more advanced).

Change the behavior of some internal functions

One can use this method to Save only the direct definitions of expr, rather than also all linked definitions as is the default behavior:

Block[{FullDefinition = Definition},
  Save["filename.m", expr]
]

Temporarily clear definitions

x = 1; (* global definition *)

D[Sin[x], x] (* this now fails *)

General::ivar: 1 is not a valid variable. >>

Solution:

Block[{x}, g[x_] = D[Sin[x], x]]

We now have the correct Definition for g: g[x_] = Cos[x]

$\endgroup$
6
  • $\begingroup$ Are those really the only uses? Everything you mentioned goes under "temporarily clear definitions" to me. $\endgroup$
    – VF1
    Oct 4, 2012 at 22:32
  • 3
    $\begingroup$ @VF1 What applications are you envisioning? Those are pretty useful abilities IMHO. $\endgroup$
    – Mr.Wizard
    Oct 4, 2012 at 22:37
  • 1
    $\begingroup$ I do not deny that your abilities are indeed useful. But those were things that I already knew and ones that Leonid mentioned in his answer to my first linked question. In that same answer, he alluded to other, "advanced," uses of Block. I was thinking there would be something clever, like the use of Module for defining functions. $\endgroup$
    – VF1
    Oct 4, 2012 at 23:04
  • $\begingroup$ @VF1, they will all fall in temporarily clear definitions because that's what Block does. But there are very creative uses of temporarily clearing definitions, like the ones mentioned and others. They mentioned typical examples but when you get the hang of it, custom uses come naturally and you begin to feel that Module has nothing to do. Say you do a recursive function f[n_]:=f1[f2[f3[f4[f[n-1]]]]], it may be the case that by changing it to Block[{f}, f1... you delay f evaluation and get a less deep recursion stack. $\endgroup$
    – Rojo
    Oct 5, 2012 at 3:33
  • $\begingroup$ That example and others may fall in the category of using Block to control the evaluation of inner parts of some code, without having to actually modify or mess with the internals. And, knowing there's a way to do that can open up doors on how you wish to design your own code $\endgroup$
    – Rojo
    Oct 5, 2012 at 3:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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