Problem
How to get the head, size, dimensions, etc. of a symbol without evaluating it? Since Mathematica does not allocate fix storage space and type to symbols it is not trivial to query runtime properties of variables. The problem is that one cannot measure e.g. size without evaluating at least a little, though in Mathematica, evaluation could cause all kinds of problems. In certain cases, extra evaluation during query could cause the loss of the original data, other unwanted side effects or even hangup in extreme cases where evaluating the expression is computationally expensive. Let's assume that we are only interested in OwnValues
and only in accessing the bytesize of the expression. Imagine you want to check your memory to see what is the size of actual symbol values (like Workspace does in Matlab). For lots of symbols, huge values and non-static expressions a complete scan could easily choke your machine.
Method 1: Sandbox
One possible way is to evaluate the expression in a safe environment that does not allow memory leaks. For example, in a local kernel without the possibility of changing state of the original kernel. This has at least three limitations: unnecessary copying of expressions from kernel to sandbox, inconsistency (might yield different results) and the fact that computationally expensive calculations would still be performed.
Method 2: Evaluate only immutable expressions
Another method is to limit size-queries to already calculated, immutable expressions only, leaving those that can potentially cause side effects untouched. This method would be safe in the sense that it would not try to re-evaluate huge expressions that are not static (being set with e.g. SetDelayed
). Though it would require a test whether OwnValues
of a symbol would further transform if evaluated or not. As a matter of fact, immutability is not even a necessity: we could measure size for symbols which are:
- consistent: evaluate to the same result;
- contained: without any side effects;
- cheap: possibly without expensive computation.
For example, f:=1+1
could be evaluated to measure size as it is cheap, does not have side effects and does not change the previous value of f
. But f:=(x++;RandomReal[])
should not be evaluated for measurement as it has a side effect changing the global state and it would erase any previous value of f
.
Simple problem case
Evaluating the following two definitions we assign values to e
and f
:
e = {1};
f := {Print[0]; 1}
{e == f, e === f} (* ==> {True, True} *)
It seems that f
is numerically and structurally identical to e
, thus having actual value {1}
but it also has the own value {Print[0]; 1}
. How can one measure the memory-requirement of the actual value of f
without triggering the re-evaluation of OwnValue
s?
A more problematic case is the following:
g := Table[1, {RandomInteger@100000}]
{ByteCount@g, ByteCount@OwnValues@g} (* ==> {287984, 336} *)
Clearly, g
has a certain actual value with a certain size (probably it's different on your machine) that has not much to do with the actual size of its OwnValues
. Now any such ByteCount
call would of course re-evaluate g
which is to be avoided as it might involve unwanted side-effects.
The problem with Method 2 is that there is no safe way (at least that I know of) which could test whether an expression is immutable (assuming it is more complex than an atom; Mr.Wizard offered a step
function, but I failed to apply it to this case), consistent, has no side effects and is cheap to evaluate. OwnValues
unfortunately does not store how a symbol was set (using Set
or SetDelayed
) thus one cannot easily exclude symbols that are unsafe to re-evaluate.
Questions
How to measure the bytesize of the value of a "nonstatic" symbol (g
) that should not be re-evaluated?
Is there a method to ascertain whether an expression can be safely evaluated?
Is there a method to safely check whether an expression is immutable?
Is there a method to safely check whether an expression is consistent, has no side effects and is cheap to evaluate?
I found the following posts extremely useful:
Implementing a safe ValueQ that does not evaluate its argument and Chat about custom valueQ between Mr.Wizard & Leonid The discussion and the post made it clear that there should be at least two approaches to define a sensible new
valueQ
: one to check if there is any value defined for a symbol and the other to check if it will be transformed or not during evaluation. I am certainly interested in the second approach.How can I test properties of a symbol from the string name without the symbol completely evaluating It is related, but it stops at the property of whether a symbol has a value or not.
var:= stuff
, and writevar[]:=stuff
instead - but you have to be consistent with this. If this is someone else's code, you can't do much without developing some sophisticated code analysis tools which would to some extent reconstruct the stronger type system. But even then, things like memory requirements are hard to automatically extract, they can easily be data-dependent (and usually are). $\endgroup$