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]=
Image

The value has changed:

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

The Protected attribute is restored:

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

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]=
Image

The definition has changed:

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

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]=
Image

The definitions have changed:

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

Use an initial value:

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

Get the operator form of BlockProtected:

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

Use the operator form:

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

The value of count was changed:

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

Create another operator form that initializes a value:

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

Now the value is always reset before evaluating:

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

Applications (2) 

A protected symbol cannot usually be cleared:

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

Clear protected symbols with BlockProtected:

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

The value is removed:

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

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]=
Image
In[28]:=
AbsoluteTiming[CachedResourceFunction["GrayCode"]]
Out[28]=
Image

The cached value is stored in the definition:

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

Having the symbol be protected avoids accidental modifications:

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

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]=
Image

The attribute is restored when exiting BlockProtected:

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

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]=
Image
In[36]:=
Attributes[a]
Out[36]=
Image

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]=
Image
In[39]:=
Attributes[b]
Out[39]=
Image

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]=
Image
In[42]:=
Definition[f]
Out[42]=
Image
In[43]:=
Catch[
 ResourceFunction["BlockProtected"][{f}, Throw[f[0] = 0]]
 ]
Out[43]=
Image
In[44]:=
Definition[f]
Out[44]=
Image

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]=
Image

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

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

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]
Image
Out[49]=
Image

The definition is unchanged:

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

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++]
Image
Out[51]=
Image

The second increment of counter failed since it became protected:

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

Local variables must be symbols:

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

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