# When is a symbol a Symbol? Is there an easy Mathematica way to test if an object is a symbol sort of like a SymbolQ?

Yes I know there is no built-in native function called SymbolQ (but JavaScript does). However, could one be simulated to work for most cases? I often rely on objectName[symbol] and makeRuleRow[symbol] to return the name of a defined variable and its value in a ready-to-use row for structured Grid layouts of results to computations. However, sometimes an error is returned if a variable is not a Symbol which leaves me asking, "When is a symbol a Symbol?"

I would like to catch such errors and return as much useful information as possible. That is why I ask if there is an easy hack for determining if a variable is a symbol.

Here is some working code where I might use such a function...

SetAttributes[symbolQ, HoldAllComplete];
symbolQ[x_] := ResourceFunction["SymbolQ"][x];

SetAttributes[{objectName}, HoldFirst];
objectName = Function[Null, SymbolName[Unevaluated[#]], {HoldFirst}];
objectName::usage =
"objectName@# returns Unevaluated shortened SymbolName.";

SetAttributes[{makeRuleRow}, HoldFirst];
makeRuleRow[symbol_, altname_ : Null, desc_ : Null] :=
Module[{name = "", prepend = ""},
If[ResourceFunction["SymbolQ"][symbol] === False &&
altname === Null,
Return[Row[{Style["Argument ", Red], symbol,
Style[" is not a symbol. Use altname in makeRuleRow.", Red]}]
], False
];
name = If[StringQ[altname], altname, objectName[symbol]];
prepend = If[StringQ[desc], desc <> " ", ""];
{Row[{Style[prepend, Brown], name, rule}],
]


The following is how it would be used for most cases (including an error) expected to be encountered when setting up name-value pairs for Grid row elements...

xxx = 123;

makeRuleRow[xxx] (* this outputs name and value *)
makeRuleRow[xxx, "alternate name"] (* this creates alternate name *)
makeRuleRow[xxx, "alternate name", "this is a symbol"] (* this prepends a description and creates alternate name *)
makeRuleRow[69] (* this generates an error message suggesting a fix *)
makeRuleRow[69, "XXX"] (* bypasses error by creating alternate name *)
makeRuleRow[69, "XXX", "not a symbol"] (* bypasses error by creating alternate name and prepend a description *)


The actual output when done correctly conveniently makes {name ->, value} rows ready to be inserted into two-column Grid layouts...

{xxx -> ,123}
{alternate name -> ,123}
{this is a symbol alternate name -> ,123}
Argument 69 is not a symbol. Use altname in makeRuleRow.
{XXX -> ,69}
{not a symbol XXX -> ,69}

• You mean something like this? resources.wolframcloud.com/FunctionRepository/resources/SymbolQ – Sjoerd Smit Jul 12 at 20:24
• Is it enough just to check that SymbolName works? Something like: symbolQ[x_]:=Quiet[Check[StringQ@SymbolName[x], False, General::sym], General::sym] – flinty Jul 12 at 20:39
• @JulesManson You can just click on the code blocks on that page to copy code you can paste into your notebook. For example, clicking on the first block copies ResourceFunction["SymbolQ"][x] to the clipboard. The function will download automatically. You can also download the source notebook if you want to see how it works internally. – Sjoerd Smit Jul 12 at 20:50
• @JulesManson - you can just do symbolQ = ResourceFunction["SymbolQ"]. My kernel init.m file is filled with definitions like that. – Jason B. Jul 12 at 21:02
• @SjoerdSmit Sure thing, I don't dispute that your plan for filing a bug is the right thing to do. I was trying to hint that the design itself is problematic. Actually, this problem shows just one facet of it, it doesn't stop here. – Leonid Shifrin Jul 13 at 8:27

I'd probably use x_Symbol in a function argument to control evaluation. Otherwise, one might do the following (thanks to @Leonid for pointing out an oversight).

If the argument is to be evaluated before testing:

SymbolQ = MatchQ[#, t_Symbol /; AtomQ[t]] &


If the argument is not to be evaluated:

SymbolQ = Function[s,
MatchQ[Unevaluated@s, t_Symbol /; AtomQ[Unevaluated@t]],
HoldAllComplete];


Examples with the second definition:

SymbolQ@Plot

(*  True  *)

x = 1;
SymbolQ[x]

(*  True  *)

Clear[y];
SymbolQ@y[1]

(*  False  *)


Here's what I had in mind for makeRuleRow:

ClearAll[makeRuleRow];
SetAttributes[makeRuleRow, HoldFirst];
makeRuleRow[symbol_Symbol, altname_ : "", desc_ : ""] :=
"execute body of function";
makeRuleRow[symbol_, altname_ : "", desc_ : ""] :=
Null /; (Message[makeRuleRow::sym, symbol, 1]; False);

makeRuleRow[123]


makeRuleRow::sym: Argument 123 at position 1 is expected to be a symbol.

(*  makeRuleRow[123]  *)

makeRuleRow[y]

(* "execute body of function"  *)


1. You could use Replace or Switch to define name in either way below:

ClearAll[makeRuleRow];
SetAttributes[{makeRuleRow}, HoldFirst];
makeRuleRow[symbol_, altname_ : Null, desc_ : Null] :=
Module[{name = "", prepend = ""},
name = Replace[Unevaluated@symbol, {
s_Symbol :> objectName[symbol]
, s_ /; StringQ@altname :> altname
, _ -> $$Failed} ]; prepend = If[StringQ[desc], desc <> " ", ""]; {Row[{Style[prepend, desccolor], name, rule}], TraditionalForm[symbol]} /; FreeQ[name,$$Failed]];
makeRuleRow[symbol_, altname_ : Null, desc_ : Null] := Null /; (
Message[makeRuleRow::args, makeRuleRow]; False);


2. Or:

ClearAll[makeRuleRow];
SetAttributes[{makeRuleRow}, HoldFirst];
makeRuleRow[symbol_, altname_ : Null, desc_ : Null] :=
Module[{name = "", prepend = ""},
Switch[Unevaluated@symbol
, s_Symbol, name = objectName[symbol]
, s_ /; StringQ@altname, name = altname
, _, name = $$Failed ]; prepend = If[StringQ[desc], desc <> " ", ""]; {Row[{Style[prepend, desccolor], name, rule}], TraditionalForm[symbol]} /; FreeQ[name,$$Failed]];
makeRuleRow[symbol_, altname_ : Null, desc_ : Null] := Null /; (
Message[makeRuleRow::args, makeRuleRow]; False);


Some may prefer Switch because they know it from another language or just find it easier to read. Too many commas for me, and I find the Replace method easier.

3. There are a few ways to handle complicated argument checking. Another is to call an "internal" version which throws $Failed when there's is an error: func[symbol_, altname_ : Null, desc_ : Null] := Module[{res}, res = Catch[iFunc[symbol, altname, desc], func]; res /; FreeQ[res, $$Failed] ]; iFunc[symbol_, altname_, desc_] := Module[{ ...}, If[error1, Message[func::err1, ...]; Throw[$$Failed, func] ]; If[error2, Message[func::err2, ...]; Throw[$Failed, func]
];
...
res (* return result *)
];


4. Yet another way is to have the outer function process the arguments and call the internal function with canonicalized arguments (for example, iMakeRuleRow[name_, desc_]) or indicate an error. The internal function then can assume the arguments are valid.

• first off thank you for taking the time to answer this post. :) The first definition with symbol_Symbol works perfect in filtering out non-symbols. How could I modify it so that makeRuleRow still executes if symbol_Symbol is not a Symbol but altname_ is given as a string (not Null). BTW I modified my function a little. The updated version is shown at the top. The argument altname_ provides an alternative variable name to display if the first argument is not a Symbol. So to encapsulate I only want it to fail if both symbol_Symbol and altname_ do not pass. – Jules Manson Jul 12 at 23:58
• @JulesManson I see, I did not appreciate the role of altname. See my update – Michael E2 Jul 13 at 3:12
• i want you to know that i really appreciate your help. I noticed a lot of advanced features (at least to me) in both solutions which I know I will love learning. I think I will go with your ReplaceAll version. I also hate all those commas from switch statements which I believe come from procedural languages. Mathematica is primarily a functional language and that is how I like it. Just one last question. Where do I put the argument checking functions func and ifunc? Should it go in my notebook where I am using the makeRuleRow? – Jules Manson Jul 13 at 4:40
• +1. One tiny nitpick is that as written, your function will give True also for e.g. SymbolQ[Symbol[123]]. So I'd throw in e.g. AtomQ test after the pre-screening _Symbol pattern: SymbolQ = Function[s, MatchQ[Unevaluated@s, t_Symbol /; AtomQ[Unevaluated[t]]], HoldAllComplete]. – Leonid Shifrin Jul 13 at 13:43
• @JulesManson I meant func to stand for makeRuleRow (and iFunc for iMakeRuleRow). I meant func[]/iFunc[] to illustrate a general strategy, and the internal details I presented won't necessarily match exactly the details of makeRuleRow[]. The last point I thought would be clearer if I called the function func by a name different from makeRuleRow. So if you're talking about the approach I've just numbered 3, I would put the argument checking in iMakeFunction (represented by the If[error1,...]... statements. – Michael E2 Jul 13 at 14:27

I found my answer thanks to Sjoerd Smit who referenced me to the Mathematica Function Repository. And yes it is appropriately called SymbolQ which is used like the following...

xxx = 123
ResourceFunction["SymbolQ"][xxx] (* returns True *)


A little bit ugly and long but it works. But why not fix if it isn't broken? And that is what I tried to do...

SetAttributes[symbolQ, HoldAllComplete];
symbolQ = ResourceFunction["SymbolQ"][#] &;
symbolQ[xxx] (* returns False *)


However Sjord came up with a solution that looks eerily similar to mine which leaves me scratching my head, why doesn't my alias work?...

SetAttributes[symbolQ, HoldAllComplete];
symbolQ[x_] := ResourceFunction["SymbolQ"][x];
symbolQ[xxx] (* returns True *)

• Your function does not work correctly, because Mathematica is first replacing symbolQ with the ownvalue ResourceFunction["SymbolQ"][#] &, and then applying it to xxx, so the HoldAllComplete attribute never comes into play. You can see that when you run Trace@symbolQ[xxx]  with your function. – Hausdorff Jul 12 at 22:41
• There is more detail here – Hausdorff Jul 12 at 22:51
• In the comment to your question I have hinted why your alias didn't work. It is due both to a specific approach being used in the design / implementation of ResourceFunction, and to the general fact that it is hard and non-trivial to maintain attributes for SubValues - based definitions. – Leonid Shifrin Jul 13 at 13:45
• As a general rule: attributes don't affect OwnValues (like symbolQ = ...) because the transformation will happen before the attributes can take effect. That's why I used a definition based on DownValues (symbolQ[arg___] := ...). – Sjoerd Smit Jul 13 at 14:30
• And to add: you could also use symbolQ = Function[x, ResourceFunction["SymbolQ"][x], HoldAllComplete];. In that case, you attach the attribute to the anonymous function instead. – Sjoerd Smit Jul 13 at 14:33

SymbolQ[_Symbol] = True
SymbolQ[_] = False


?

• That's what I had in mind, tho' with the attribute HoldFirst. Actually, I thought the pattern could go directly in the def. of makeRuleRow and skip SymbolQ altogether... – Michael E2 Jul 12 at 22:50
• @MichaelE2 please bare with me as I am still new to mathematica. could you elaborate a little more on how i could use that for makeRuleRow[]? – Jules Manson Jul 12 at 23:00
• @JulesManson I added a shortened paradigm to my answer. – Michael E2 Jul 12 at 23:08

I want to add something to the discussion about the ResourceFunction SymbolQ. The OP observed that doing something like:

x = 1;
symbolQ = ResourceFunction["SymbolQ"];
ResourceFunction["SymbolQ"][x]
symbolQ[x]
(* True *)
(* False *)


does not work because the attributes of the resource function are not applied correctly. However, I just discovered that you can do the following instead:

x = 1;
symbolQ = ResourceFunction["SymbolQ", "Function"];
ResourceFunction["SymbolQ"][x]
symbolQ[x]
(* True *)
(* True *)


It seems like ResourceFunction["SymbolQ", "Function"] will give you direct access to the function without having to go through the ResourceFunction wrapper. This is also nice because it avoids some evaluation overhead from ResourceFunction.

• +1. I am not a big fan of the ResourceFunction design in general, but within what it is, this is definitely a useful thing to know. – Leonid Shifrin Jul 28 at 15:06
• @SjoerdSmit Thanks for the update. I also have a question about resource functions. Are they ever promoted to Mathematica native code in updates? If some have been promoted in the past (due to for example popularity or usefulness) I can see SymbolQ getting a bump up. – Jules Manson Aug 4 at 17:48
• @JulesManson It's difficult to say; it's possible they might make it into the language. That said, SymbolQ is already a built-in function. It's just a wrapper for DeveloperHoldSymbolQ`. – Sjoerd Smit Aug 4 at 18:14