Skip to main content

error - How to find all function which cannot be ToExpression?


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?



Answer




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
]



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[#]) &]


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


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...