5
$\begingroup$

If you use ToExpression directly like this

ToExpression /@ Names["*`*"]

enter image description here

You will get a chunk error information.I try to find which function make this behavior,so I make a custom cache to collect all function be executed:

tem = <||>;
cache := (AssociateTo[tem, # -> #]; #) &
ToExpression[cache[#]] & /@ Names["*`*"]

The last of tem is

Last[tem]
DataPaclets`FinancialDataDump`channel10

This function abort the caculation:

ToExpression[Last[tem]]

enter image description here

But I don't know which function result to this

enter image description here

In this post,I try to find all function which can not get a Normally result(Such as ToExpression["Plot"] get Plot or ToExpression["Sin"] get Sin,then this define a normal case,and the ToExpression["$Version"] wil not give $Version but give its value,I will think that as unnormal here).How to implement it?

$\endgroup$
  • 1
    $\begingroup$ Have you looked at using Check? $\endgroup$ – m_goldberg Dec 16 '16 at 20:24
  • $\begingroup$ Assigned Symbols evaluate to something other than themselves, e.g. foo = 1; ToExpression[foo] returns 1. Do you wish to consider that a normal result? $\endgroup$ – Mr.Wizard Dec 16 '16 at 22:00
  • $\begingroup$ @m_goldberg Of course,I have.But the Check can help a little here I think,such as that output of Buzz. $\endgroup$ – yode Dec 16 '16 at 23:25
  • $\begingroup$ @Mr.Wizard I have uptate your case in the post. :) $\endgroup$ – yode Dec 16 '16 at 23:42
8
$\begingroup$

Reflection in Mathematica is a tricky business. This makes the definition of a "normal result" tricky as well. This response will point out some of those difficulties and provide some tools to deal with them.

Core Issue

The core issue is that naive use of ToExpression to convert a string into a symbol will cause the symbol to be evaluated. For example:

ToExpression["Red"]
(* RGBColor[1, 0, 0] *)

Notice how it returns the value of the symbol Red instead of the symbol itself.

Loading Symbols Can Be Dangerous

Thus, when we evaluate ToExpression /@ Names["*`*"] we are evaluating a very large number of symbols. This is a dangerous operation. Many symbols are never meant to be evaluated in isolation.

The question gives us a few examples. Let us look at the first. In a fresh kernel session (mine is V11.0.1), evaluate:

Quantity;

"CalculateScan`UnitScanner`Private`AbsorbNumbers" // ToExpression

(* 
  During evaluation of In[1]:= Quantity::nonopt: Options expected
  (instead of CalculateScan`UnitScanner`Private`opts:OptionsPattern[])
  beyond position 2 in Quantity[...]. An option must be a rule or a list of rules.
*)

The problem is that AbsorbNumbers has a pattern as its value. By itself, that pattern contains an evaluation leak which generates a (harmless) message.

This example might be harmless, but many symbols are not so harmless. Evaluating an arbitrary symbol might:

  • trigger auto-loading of a package
  • produce output
  • download from the Internet
  • attempt to access or modify cloud objects
  • load or flush caches
  • change system settings
  • load large expressions into memory
  • play audio or make sounds
  • re-evaluate expressions that were evaluated earlier within a session

These actions are not entirely safe.

Should We Detect Such Failures?

It might be possible to assemble a list of symbols that cause trouble. For example, we could use Check to identify symbol evaluations which issue messages and CheckAll to find evaluations that Throw or Abort. But such tests are too late -- whatever harm the evaluation caused is already done.

Therefore, I suggest that it is too harmful to attempt to evaluate all symbols in the system. We need another approach.

An Alternate Approach

It is safer to inspect symbols without evaluating them. We can easily prevent the evaluation like this:

ToExpression["Red", InputForm, HoldComplete]

(* HoldComplete[Red] *)

This, however, does not tell us anything about Red itself. We can use functions OwnValues, DownValues and UpValues to get some information about symbols:

OwnValues[Red]
(* {HoldPattern[Red]:> RGBColor[1, 0, 0]} *)

DownValues[AbsoluteCurrentValues]
(* {{HoldPattern[AbsoluteCurrentValue[System`FEDump`option_]] :> ..., ... }*)

UpValues[Capitalize]
(* {HoldPattern[Internal`ArgumentCountRegistry[Capitalize]] :> {1,1}} *)

We can combine these functions with ToExpression to get information about a symbol in string form in a relatively safe manner:

ToExpression["Red", InputForm, OwnValues]
(* {HoldPattern[Red]:> RGBColor[1, 0, 0]} *)

However, for the case at hand there is a problem with these information functions. They are HoldAll but not HoldAllComplete. So if we are going to scan across all symbols, there is still a chance for potentially dangerous evaluation leaks.

I prefer to use a set of undocumented (V11.0.1) information functions:

Names["System`Private`Has*Q"] // Map[Symbol /* SymbolName]
(* {HasAnyCodesQ,HasAnyEvaluationsQ,HasDelayedValueQ,HasDownCodeQ,
    HasDownEvaluationsQ,HasImmediateValueQ,HasNoCodesQ,
    HasNoEvaluationsQ,HasOwnCodeQ,HasOwnEvaluationsQ,
    HasPrintCodeQ,HasSubCodeQ,HasSubEvaluationsQ,
    HasUpCodeQ,HasUpEvaluationsQ} *)

These functions have a couple of advantages that are relevant to the current discussion. First, they are HoldAllComplete so they will prevent as many evaluation leaks as is possible from high-level code. Second, they are aware of built-in kernel definitions that are invisible to DownValues et al.

Here is a useful helper function:

info =
  Names["System`Private`Has*Q"] //
  Map[StringReplace[SymbolName[#], "Has"~~n__~~"Q" :> n] -> #&[Symbol[#]]&] //
  Apply[Hold] //
  Replace[#, s_Symbol :> ToExpression[#2[1], InputForm, s], {2}] &[#, Slot]& //
  Replace[_[r__] :> Function[Null, <| "Name" -> #, r |>, HoldAllComplete]];

We can use it like this:

info["Sin"]
(* <| Name -> "Sin"
    , AnyCodes -> True
    , AnyEvaluations -> True
    , DelayedValue -> False
    , DownCode -> True
    , DownEvaluations -> True
    , ImmediateValue -> False
    ...
    |>
*)

This tells us that Sin has built-in down-value definitions even though DownValues[Sin] returns nothing.

Armed with this helper, we can ask various questions:

$allInfo = info /@ Names["*`*"] // Dataset;

What are all the symbols with no evaluation rules at all?

$allInfo[Select[#NoEvaluations &], "Name"]

What are all the symbols that have built-in function definitions?

$allInfo[Select[#DownCode&], "Name"]

What are all the symbols that have function definitions but are not built-in?

$allInfo[Select[#DownEvaluations && ! #DownCode &], "Name"]

Addendum: Some Debugging Tricks

OK, so evaluating lots of symbols is dangerous and we should not do it. Fine. But the question remains: how can we identify which symbols are causing problems?

Unfortunately, the problematic evaluations take different forms, so no one technique will find them all. But here are a few tricks that will often bear fruit.

Debugger: Break At Messages

We can use the debugger to find the source of the first message. Turn on the debugger and check the Break at Messages setting. Then evaluate:

ToExpression /@ Names["*`*"]

The debugger will stop at the first message. The stack window shows:

debugger screenshot

We can see ToExpression[CalculateScan`UnitScanner`Private`AbsorbNumbers] on the stack.

Debugger: Forced Break

Next, let's consider the "Buzz" that appears as output when scanning the symbols. This is not accompanied by a message, so the "break at messages" trick is not going to work. The "Buzz" is very strange because it actually generates output and causes a beep to sound from the speaker. Since it generates output, we might guess that it is using Print. So let us use Trace to set up a trap for calls to Print and force the debugger to stop there:

Trace[ToExpression /@ Names["*`*"]
, _Print?(RuntimeTools`BreakNow[]&)
, TraceInternal -> True
]

"Buzz" Trace screenshot

We see that GeneralUtilities`Buzz is the culprit. What a strange symbol. It should probably be a function... but we may have just stumbled upon a nice tool for finding evaluation leaks.

If the culprit had not been using Print, we might have tried other guesses like CellPrint, or even Play or Beep to try to catch the sound.

Brute Force

We got lucky in the last case because we correctly guessed that the buzzing was caused by a call to Print. But what if we had no idea at all about the cause? Well, we can always resort to brute force.

Manual experimentation quickly reveals that "Buzz" appears when we scan symbols beginning with "B":

ToExpression /@ Names["*`A*"]

(* no "Buzz" *)

ToExpression /@ Names["*`B*"]

(* "Buzz" appears *)

We could continue in this fashion using a divide-and-conquer approach to narrow down the range of symbols that could be responsible. In this case, we will assume that there are not that many symbols that start with "B", so let's just print them all out and then look for the "Buzz":

Names["*`B*"] // Map[(Print[#]; ToExpression[#]) &]

"Buzz"

There it is, right where we found it before in GeneralUtilities`Buzz.

$\endgroup$
  • $\begingroup$ It's seen some copy error in info? $\endgroup$ – yode Dec 17 '16 at 18:39
  • $\begingroup$ What error are you seeing? The definition as written works for me (using V11.0.1). I do not see a missing & in the definition (it uses an explicit Function[...] form). $\endgroup$ – WReach Dec 17 '16 at 18:46
  • $\begingroup$ Sorry,I forget to Clear to the old version maybe.And your answer amazing me again. :) $\endgroup$ – yode Dec 17 '16 at 18:53
  • $\begingroup$ Can you show me how do you find that "CalculateScan`UnitScanner`Private`AbsorbNumbers" cause that?And that Buzz $\endgroup$ – yode Dec 17 '16 at 18:55
  • 1
    $\begingroup$ I think the answer is "no" for all intents and purposes. As I noted in my response, the only way to really tell is to actually evaluate all the names. And that will cause all kinds of harmful side-effects. I advise against it, but if one is brave: $bad = Cases[Names["**"], n_ /; CheckAll[Quiet@Check[ToExpression@n; False, True], 0 != Length@Last@{##} || # &]]`. Be prepared to dismiss many pop-up dialogs and wait a very long time... assuming the expression even finishes without crashing the kernel or running out of memory. $\endgroup$ – WReach Mar 16 '17 at 17:51
3
$\begingroup$

One possible approach is to use ValueQ to see if a Symbol is considered to have a value. (Caveat: this still causes evaluation as is the subject of Implementing a safe ValueQ that does not evaluate its argument.)

Because many Symbols are defined to load additional libraries the first time they are used you will get a lot of false positives the first time this is run, so run it a second time for more useful results. I use Quiet to suppress the messages that would otherwise be generated.

Cases[
 ToHeldExpression @ Names["*`*"],
 Hold[s_Symbol] /; Quiet @ ValueQ @ s :> HoldForm[s]
]
{AASTriangle, DataPaclets`CalendarDataDump`Aberration, AbortKernels, 
NIntegrate`AbscissasWeightsIntegration, 
Statistics`Library`AbsoluteCorrelationDefinition, AbsoluteCorrelationFunction, 
RandomProcesses`Library`AbsoluteCorrelationFunctionFromSlices, 
TemporalData`AbsoluteDuration, . . . }

If you describe the motivation behind this question I might be able to refine this result.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.