Consider the following code running on a fresh Mathematica session with no symbols defined:
p[s_String] := Protect[s];
p["x"]
This doesn't do anything because there is no symbol named x
yet, so no symbols match the string pattern "x"
. No problem, we can resolve this by using Symbol
:
p[s_String] := Protect[Symbol[s]];
p["x"]
This doesn't work either, since Protect has the attribute HoldAll
. So we can use Evaluate
:
p[s_String] := Protect[Evaluate[Symbol[s]]];
p["x"]
Great! Now it works. Except... If the symbol we want to protect does already exist, then it won't work:
y = 1;
p[s_String] := Protect[Evaluate[Symbol[s]]];
p["y"]
This will execute Protect[1]
because Symbol["y"]
evaluates to 1
. How can one write a function p
which protects a symbol, given via a string, whether or not it already exists?
Thanks.
EDIT: A solution was given in the comments:
p[s_String] := Protect @@ ToExpression[s, StandardForm, Hold];
However, now I have another similar issue. I would like to find out if s is a proper symbol, so that e.g. p["1"]
or p["a b"]
will return an error message. So I tried the same trick with Head
:
p[s_String] :=
If[Head @@ ToExpression[s, StandardForm, Hold] === Symbol,
Protect @@ ToExpression[s, StandardForm, Hold],
Print[s, " is not a symbol!"]];
This works only if the symbol was not defined previously. For example, if I type x = 1
and then p["x"]
I will get x is not a symbol
because its Head
is Integer
. So again, it's the same problem as above: How can I look at the symbol itself without it being replaced by its value?
p[s_String] := If[MemberQ[Names[s], s], Protect[s]]
$\endgroup$Protect @@ ToExpression[s, StandardForm, Hold]
? $\endgroup$