Function Repository Resource:

BlockProtected

Source Notebook

Modify definitions of protected symbols and ensure that their attributes are restored

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["BlockProtected"][{sym1,sym2,},expr]

evaluates expr with symbols symi unprotected and restores their protected attribute before returning the result.

ResourceFunction["BlockProtected"][{,symi=vali,},expr]

sets initial values for the symi.

ResourceFunction["BlockProtected"][{syms}]

represents an operator form of ResourceFunction["BlockProtected"] that can be applied to an expression.

Details

ResourceFunction["BlockProtected"] has the attribute HoldAll.
All the protected symi are unprotected before evaluating expr and reprotected before returning the result.
If a symbol symi is initially unprotected and becomes protected during evaluation of expr, it will be unprotected again when evaluation completes.
ResourceFunction["BlockProtected"][{syms}][expr] is equivalent to ResourceFunction["BlockProtected"][{syms},expr].
ResourceFunction["BlockProtected"] returns a Failure object for invalid argument patterns rather than remain unevaluated.

Examples

Basic Examples (2) 

Modify the definition of a protected symbol:

In[1]:=
sym = 1; Protect[sym];
In[2]:=
ResourceFunction["BlockProtected"][{sym}, sym = 2]
Out[2]=

The value has changed:

In[3]:=
sym
Out[3]=

The Protected attribute is restored:

In[4]:=
Attributes[sym]
Out[4]=

Modify the definition of a protected function:

In[5]:=
f[x_] := 1/x;
Protect[f];
In[6]:=
ResourceFunction["BlockProtected"][{f}, f[0] = Infinity]
Out[6]=

The definition has changed:

In[7]:=
Definition[f]
Out[7]=

Scope (3) 

Modify multiple protected symbols:

In[8]:=
{x, y} = {1, 2};
Protect[x, y];
In[9]:=
ResourceFunction["BlockProtected"][{x, y}, {x, y} = {3, 4}]
Out[9]=

The definitions have changed:

In[10]:=
Definition[x]
Out[10]=
In[11]:=
Definition[y]
Out[11]=

Use an initial value:

In[12]:=
Protect[n];
ResourceFunction["BlockProtected"][{n = 0}, Table[++n, 10]]
Out[12]=
In[13]:=
Definition[n]
Out[13]=

Get the operator form of BlockProtected:

In[14]:=
count = 0;
Protect[count];
withCounter = ResourceFunction["BlockProtected"][{count}]
Out[14]=

Use the operator form:

In[15]:=
withCounter[Table[++count, 5]]
Out[15]=

The value of count was changed:

In[16]:=
Definition[count]
Out[16]=
In[17]:=
withCounter[++count]
Out[17]=

Create another operator form that initializes a value:

In[18]:=
withResetCounter = ResourceFunction["BlockProtected"][{count = 0}]
Out[18]=
In[19]:=
withResetCounter[Table[++count, 5]]
Out[19]=

Now the value is always reset before evaluating:

In[20]:=
withResetCounter[++count]
Out[20]=

Applications (2) 

A protected symbol cannot usually be cleared:

In[21]:=
z = 1; Protect[z];
In[22]:=
ClearAll[z]

Clear protected symbols with BlockProtected:

In[23]:=
ResourceFunction["BlockProtected"][{z}, ClearAll[z]]

The value is removed:

In[24]:=
z
Out[24]=

Write a protected function that caches results in its definition:

In[25]:=
CachedResourceFunction[id_] := ResourceFunction["BlockProtected"][{CachedResourceFunction},
   CachedResourceFunction[id] = ResourceFunction[id, "Function"]
   ];
In[26]:=
Protect[CachedResourceFunction];

The results are cached for faster subsequent evaluations:

In[27]:=
AbsoluteTiming[CachedResourceFunction["GrayCode"]]
Out[27]=
In[28]:=
AbsoluteTiming[CachedResourceFunction["GrayCode"]]
Out[28]=

The cached value is stored in the definition:

In[29]:=
Definition[CachedResourceFunction]
Out[29]=

Having the symbol be protected avoids accidental modifications:

In[30]:=
ClearAll[CachedResourceFunction]
In[31]:=
Definition[CachedResourceFunction]
Out[31]=

Properties and Relations (4) 

Only the Protected attribute is modified within BlockProtected:

In[32]:=
a = 1; SetAttributes[a, {Constant, Protected}];
In[33]:=
ResourceFunction["BlockProtected"][{a}, Unprotect[a]; Attributes[a]]
Out[33]=

The attribute is restored when exiting BlockProtected:

In[34]:=
Attributes[a]
Out[34]=

If a symbol is protected when entering BlockProtected, it will be protected when exiting, even if all other definitions are cleared:

In[35]:=
ResourceFunction["BlockProtected"][{a}, ClearAll[a]; Attributes[a]]
Out[35]=
In[36]:=
Attributes[a]
Out[36]=

If a symbol is unprotected going into BlockProtected, it will be unprotected when coming out:

In[37]:=
b = 2; SetAttributes[b, {Constant}];
In[38]:=
ResourceFunction["BlockProtected"][{b}, Protect[b]; Attributes[b]]
Out[38]=
In[39]:=
Attributes[b]
Out[39]=

BlockProtected will ensure that attributes for symbols are restored even if evaluation is interrupted:

In[40]:=
Unprotect[f]; ClearAll[f];
f[x_] := 1/x;
Protect[f];
In[41]:=
ResourceFunction["BlockProtected"][{f}, f[0] = Infinity; Abort[]]
Out[41]=
In[42]:=
Definition[f]
Out[42]=
In[43]:=
Catch[
 ResourceFunction["BlockProtected"][{f}, Throw[f[0] = 0]]
 ]
Out[43]=
In[44]:=
Definition[f]
Out[44]=

BlockProtected is functionally similar to using Unprotect and Protect around the evaluation:

In[45]:=
modifyProtected // ClearAll;
modifyProtected // Attributes = {HoldAll};
modifyProtected[f_, eval_] :=
  Module[{result},
   Unprotect[f];
   result = eval;
   Protect[f];
   result
   ];
In[46]:=
modifyProtected[f, f[0] = "modified"];
Definition[f]
Out[46]=

However, this does not prevent evaluation interruptions from leaving symbols in an unprotected state:

In[47]:=
modifyProtected[f, f[0] = "unprotected"; Abort[]];
Out[47]=
In[48]:=
Definition[f]
Out[48]=

Possible Issues (3) 

Symbols that are locked and protected cannot be localized with BlockProtected:

In[49]:=
locked = 1;
locked // Attributes = {Locked, Protected};
ResourceFunction["BlockProtected"][{locked}, locked = 2]
Out[49]=

The definition is unchanged:

In[50]:=
Definition[locked]
Out[50]=

BlockProtected only ensures that symbols are unprotected before evaluating; it does not prevent symbols from being protected during evaluation:

In[51]:=
counter = 1;
Protect[counter];
ResourceFunction["BlockProtected"][{counter}, counter++; Protect[counter]; counter++]
Out[51]=

The second increment of counter failed since it became protected:

In[52]:=
counter
Out[52]=

Local variables must be symbols:

In[53]:=
ResourceFunction["BlockProtected"][{f[1]}, f[1] = 1]
Out[53]=
In[54]:=
ResourceFunction["BlockProtected"][{f}, f[1] = 1]
Out[54]=

Requirements

Wolfram Language 11.3 (March 2018) or above

Version History

  • 2.0.0 – 09 February 2021
  • 1.0.0 – 15 August 2018

Related Resources

License Information