How to make Mathematica variables declarative instead of just-in-time?
You are looking for $NewSymbol
which is run every time a new symbol is created. For example, let say you only want x
, y
, and z
as symbols, then declare them initially
In[63]:= {x, y, z}
(*Out[1]= {x, y, z}*)
Then, set $NewSymbol
to issue a message when it is used, e.g.
In[2]:= $NewSymbol::undeclared = "`1` was not previously declared.";
In[3]:= $NewSymbol := Message[$NewSymbol::undeclared , #1] &
In[4]:= q
(*
During evaluation of In[4]:= $NewSymbol::undeclared: q was not previously declared.
Out[4]= q*)
But, no message is issued with x
.
In[5]:= x = 5
(*Out[5]= 5*)
Additionally, you can create your own cell style that will treat variable declarations as expected using a custom CellEvaluationFunction
CellEvaluationFunction -> (Block[{$NewSymbol}, ToExpression[#]]&)
For instance, you can add it to the "Code"
cell, e.g.
Cell[StyleData["Code"],
CellEvaluationFunction -> (Block[{$NewSymbol}, ToExpression[#]]&)
]
Edit: method extended for multiple contexts and unlocking mehtod added.
Let's protect whatever is a new symbol.
In old answer I've manually excluded symbols matching name$digits
but that wasn't necessary as according to $NewSymbol
details:
$NewSymbol
is not applied to symbols automatically created by scoping constructs such asModule
.
BeginPackage["Lock`"];
contextLock; contextUnlock;
Begin["`Private`"];
SetAttributes[{contextLock, contextUnlock}, HoldFirst];
$LockedContexts = <||>;
contextLock[context_: $Context] := Which[
$LockedContexts === <||>
, setLocking[]; $LockedContexts[context] = {}
, Not@KeyExistsQ[$LockedContexts, context]
, $LockedContexts[context] = {};
];
contextUnlock[context_: $Context] /; KeyExistsQ[$LockedContexts, context] := (
ToExpression[#, StandardForm, Unprotect] & /@ $LockedContexts[context]
; ToExpression[#, StandardForm, Remove] & /@ $LockedContexts[context]
; KeyDropFrom[$LockedContexts, context]
; If[$LockedContexts === <||>, $NewSymbol =.];
)
setLocking[] := $NewSymbol := If[
MemberQ[Keys[$LockedContexts], #2]
, AppendTo[$LockedContexts[#2], #2 <> #1]
; ToExpression[#2 <> #1, StandardForm, Protect]
] &;
End[];
EndPackage[];