25

Mathematica has a built-in function ValueQ. Quoting the docs,

ValueQ[expr] gives True if a value has been defined for expr, and gives False otherwise.

...

ValueQ gives False only if expr would not change if it were to be entered as Mathematica input.

This works nicely with symbols that only have OwnValues:

x = Print["boo!"]
ValueQ[x]

(* ==> True *)

It doesn't work so nicely with functions, though:

f[x_] := Print[x]
ValueQ[f[1]]

(* 1 ==> True *)

This gives True, but also evaluates f[1] completely, printing 1. This is clearly dangerous, and it is important to be aware of this. Unfortunately, the docs make no mention of this under the "Possible Issues" section!

Why this happens is clear if we look at the implementation of ValueQ for non-symbols:

ValueQ[expr_] := ! Hold[Evaluate[expr]] === Hold[expr]

Question: Is it possible to implement a more robust version of ValueQ, which does not evaluate its argument in an unexpected an possibly dangerous way?

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • This is especially weird since ValueQ has the atttribute HoldAll. Maybe you discovered a bug? – David Feb 08 '12 at 04:39
  • 8
    @David HoldAll attribute only says what will happen to the function's arguments before they are passed to the function, but nothing about how the function itself evaluates them. A situation when function is not supposed to evaluate arguments passed to it but does that nonetheless, is called evaluation leak, and is something to watch out for when you develop HoldAll etc functions. For the case at hand, this was discovered before, perhaps more than once, e.g. here. – Leonid Shifrin Feb 08 '12 at 06:00
  • There are several ways to handle the meaning of ValueQ, as Leonid and I have been discussing. I deleted my answer until I have time to consider all this and expand/revise accordingly. – Mr.Wizard Feb 08 '12 at 09:24
  • @Leonid I am dissatisfied with the function in its current state; it's just too weird to get True for Hold[2] or "a" + "b" or x[1][2] (where x is undefined). I am exploring another possibility now. – Mr.Wizard Feb 08 '12 at 09:56
  • @Mr. Wizard I see. – Leonid Shifrin Feb 08 '12 at 10:03

2 Answers2

17

Preamble

This has been discussed before, and this problem was also identified and partially addressed in the same question. I will use a slightly simpler implementation which also covers UpValues. It is probably not complete either, but it covers many common cases of interest.

Implementation

Here is the code:

ClearAll[symbolicHead];
SetAttributes[symbolicHead, HoldAllComplete];
symbolicHead[f_Symbol[___]] := f;
symbolicHead[f_[___]] := symbolicHead[f];
symbolicHead[f_] := Head[Unevaluated[f]];

ClearAll[valueQ];
SetAttributes[valueQ, HoldAllComplete];
valueQ[a_Symbol] /; OwnValues[a] =!= {} :=
    With[{result = (# =!= (# /. OwnValues[a])) &[HoldComplete[a]]},
       result /; result];

valueQ[a : f_Symbol[___]] /; DownValues[f] =!= {} :=
    With[{result = (# =!= (# /. DownValues[f])) &@HoldComplete[a]},
       result /; result];

valueQ[a_] :=
    With[{sub = SubValues[Evaluate[symbolicHead[a]]]},
      With[{result  = (# =!= (# /. sub)) &[HoldComplete[a]]},
          result /; result] /; sub =!= {}
    ];

valueQ[a_] :=
   With[{upsyms  =
       Flatten@Cases[Unevaluated[a], s_Symbol :> UpValues[s], 1, Heads -> True]},
          With[{result  = (# =!= (# /. upsyms)) &[HoldComplete[a]]},
             result /; result] /; upsyms =!= {}
   ];

valueQ[_] := False;

Symbolic heads are further discussed in this answer. The order of definitions is important, and roughly corresponds to the order of steps applying those global rules, in the main evaluation sequence.

Examples

a := Print["*"];
b[1] := Print["*"];
c[1][4] := Print["*"];
d /: f[x_Integer, d, y_Integer] := Print["*"];

valueQ /@ Unevaluated[{a, b[1], c[1][4], f[1, d, 2]}]

(*
  ==> {True, True, True, True}
*)

Limitations

I did not include the NValues (this can be done, but the question is whether we really want to do that). This seems to pretty much exhaust the set of things we can do without really evaluating an expression in question. In certain cases, the results will be different from ValueQ, for example:

{valueQ[N[Pi]],ValueQ[N[Pi]]}

(*
  ==> {False,True}
*)

Summary

The code above was not meant to be absolutely complete, and probably can not be, since not everything is exposed to the top-level / end user. But it is hoped that it covers many cases of interest, and can be further extended to cover some that it misses currently. Note that, since internal global rules are not available at the top-level, valueQ is mostly limited to user-defined or top-level functions and variables. If one wants to include system symbols with internal rules, I don't see other ways than allowing the expression to evaluate.

This may also explain (to some extent), why built-in ValueQ was written the way it was - to also cover the system symbols and be general. On a deeper level, this seems to reflect that the separation between internal and top-level rules is rather artificial and sometimes flies in the face of the core language semantics, particularly when one wants to write some general functions related to introspection, such as ValueQ.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • This is probably obvious, but here is another case where valueQ and ValueQ differ: {valueQ@{1 + 1}, ValueQ@{1 + 1}}. Overall I think valueQ is much more useful. – Ajasja Apr 23 '13 at 14:23
  • 1
    @Ajasja Good point, thanks. Generally, picking one over another is a hard question, because there is no direct mapping between Mathematica evaluation sequence and our expectations of usefulness in this or that situation (evaluation sequence usually contains steps which we consider trivial and others we consider important, but from the system's viewpoint all steps have the same degree of importance. So, filtering out "trivial" evaluations is to a large degree a subjective matter). That said, I agree that more often than not I find ValueQ to not be appropriate for the task, unlike valueQ. – Leonid Shifrin Apr 23 '13 at 14:55
  • Interestingly, under v8 and v9, valueQ /@ Unevaluated[{a, b[1], c[1][5], f[1, d, 2]}] returns {True, True, False, True} instead of four True-s. Did I miss something? – István Zachar Jun 11 '13 at 08:27
  • @IstvánZachar Thanks, you spotted a typo. Should have been c[1][4]. It is unclear to me how this leaked into the answer, usually I copy the output directly from Mathematica. Will edit now. – Leonid Shifrin Jun 11 '13 at 09:51
  • Ah, ok, I assumed that it was deliberate to call with a different argument than in the definition. – István Zachar Jun 11 '13 at 11:54
15

Using the core of my new step function:

SetAttributes[valueQ1, HoldAll]

valueQ1[expr_] :=
 Module[{P, R = False},
   P = (P = Return[R = True, TraceScan] &) &;
   TraceScan[P, expr, TraceDepth -> 1];
   R 
 ]

SetAttributes[valueQ2, HoldAll]

valueQ2[expr_] :=
 Module[{P, R = False},
   P = (P = Return[R = True, TraceScan] &) &;
   TraceScan[P, expr];
   R 
 ]

SetAttributes[valueQ3, HoldAll]

valueQ3[expr_] :=
  Block[{Print},
    TraceScan[
      Null &, expr, _,
      If[# =!= HoldForm[#2], Return[True, TraceScan]] &
    ] // TrueQ
  ]

Long overdue update.

valueQ1 is my proposal for an alternative to ValueQ which leaks far less often. In most cases it returns the same answer that ValueQ does. It gives True if the entire expression is transformed in the course of evaluation.

valueQ2 is a trigger-happy version of Q1 that returns True if any evaluation takes place for the given expression. Leonid favors this one as being the most "pure" within Mathematica's framework, but it also makes for a lot of (arguably) false-positives.

valueQ3 is an attempt to get behavior closer to ValueQ (than Q1), and no leaks, but it may not be robust. The purpose of Blocking Print is NOT to hide the leaks (i below is used to check this), but a work-around because Print caused the method to fail; it is unknown to me what other function calls would also cause failure.

Here is a table of results for these functions compared to ValueQ:

ClearAll[a, b, c, d, f, g, gg, x];
i = 0;
a := Print["*a"];
b[1] := (i++; Print["*b"])
c[1][4] := (i++; Print["*c"])
d /: f[x_Integer, d, y_Integer] := (i++; Print["*d"])
gg[x_] := (i++; Print["*gg"]; False)
g[x_] /; gg[x] := x^2
x = 1;

Mathematica graphics

Results in red are tests that leaked.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 1
    Trace and friends have to evaluate the expression being traced, if I am not mistaken. – Leonid Shifrin Feb 08 '12 at 06:17
  • No I did not yet - my comment was just based on the general considerations. I will look into it. – Leonid Shifrin Feb 08 '12 at 06:29
  • Yes. For example, here: valueQAlt[{b[1]}] - it leaks evaluation. – Leonid Shifrin Feb 08 '12 at 06:32
  • This is not the point. The point is that we should be able to feed any expression into valueQ, and be sure that it won't be evaluated. Imagine using valueQ inside e.g. Cases, something like Cases[Unevaluated[expr],sub_/;valueQ[sub]:>HoldComplete[sub],Infinity]. In other words, at least in my interpretation, this question is in the first place about making valueQ with a well-defined and general evaluation semantics. – Leonid Shifrin Feb 08 '12 at 06:41
  • Well, take some g[b[1]] with undefined g in place of a List, if you wish - it then will make sense also in more narrow context. – Leonid Shifrin Feb 08 '12 at 06:44
  • This is what I am thinking myself about at the moment. If valueQ[{f[1]}] should give False, then your approach does not seem to work. But, alternatively, we may define the semantics of valueQ such that it gives True whenever an expression at all evaluates if we let it - in this formulation, your approach works and my does not. So, the question is, which semantics is the "right" one. I would think that valueQ[{f[1]}] should return False, but this is not that clear-cut to me. And, your approach is both more elegant and more general than mine. So, I don't know, really. – Leonid Shifrin Feb 08 '12 at 06:55
  • Here is a problem though: ClearAll[f, g];f[x_] := False;g[x_] /; f[x] := x^2;valueQ[g[1]] – Leonid Shifrin Feb 08 '12 at 07:04
  • @LeonidShifrin, can you explain why With[{x = {f}},valueQ[x]] gives a different result than With[{x := {f}},valueQ[x]] with Spartacus's valueQ? Some kind of internal optimization avoiding reevaluation of x? In any case, it's an inconsistent solution whatever the interpretation of valueQ if its result depend on internals such as this one – Rojo Feb 08 '12 at 08:12
  • @Spartacus, the previous comment is for you too... I'm also willing to talk about this issue but there's probably no good solution – Rojo Feb 08 '12 at 08:13
  • @Leonid let us delete these comments since they are archived in the chat (I'll leave that link). – Mr.Wizard Feb 09 '12 at 06:37
  • @Rojo I realize that we never answered your question. Factually it is because of the difference between With[{x = {f}}, TracePrint[x]] and With[{x := {f}}, TracePrint[x]] but that may not be the answer you were looking for. It is my opinion that Leonid has a better grasp of the evaluation process to answer why there is this difference. Also, have you had the chance to try my valueQ3 yet? It is quite experimental but I believe may be the best. I have not updated my answer with a description of each as I want to talk to Leonid first. – Mr.Wizard Feb 09 '12 at 06:42
  • @Spartacus, it works way better than the other one, nice. However, the thing with Print is just a lie, haha. It tries to prevent the user from learning that evaluations happen, but they still happen. Try valueQ3[x=8] and see how x gets the value. And, that lie has sideffects. Such as (contorted example) g[Null] := 8; g[Print[2]] returns 8, but valueQ[g[Print[2]]] gives False. So I think it's going great, but it would be better without the Block to Print, what do you think? – Rojo Feb 09 '12 at 07:26
  • @Rojo I haven't spent any time on that today. The purpose of Block[{Print} . . . was NOT to fake the tests but to deal with a problem I had with TraceScan. See the chat log above for more. Thank you for your testing an examples. I shall try to see if the issues can be addressed or if this is destined to fail. – Mr.Wizard Feb 09 '12 at 07:39
  • @Rojo the second example g[Print[2]] is easy to explain because it relies on Print which I specifically Blocked. Consider that a corner case. The case with Set is far more interesting, and concerning, because last night I thought that would be intercepted. – Mr.Wizard Feb 09 '12 at 07:44
  • @Spartacus my bad then, not a lie (I didn't understand the particular issue with Print but it's ok). I honestly don't know how one could prevent all or most of the evaluations, hope you find a way. But I still consider it very useful if you prevent some of the evaluation while making it behave like the built in. And this version almost does that. So good job – Rojo Feb 09 '12 at 09:02
  • 1
    @Rojo Thanks. Slowly I am forming ideas about the utility of these functions. Leonid's is more like a "HasDefinitionQ" than ValueQ. My valueQ1 is similar to ValueQ but leaks less (though it still leaks). valueQ2 is really more like a "NotInertQ". The third function is experimental. I see why something like valueQ3[x = 8] leaks (while valueQ3[x = 2 + 2] doesn't), and I am not confident that it can be made to work. I think that I would have to compile a list of built-in "verbs" that specifically take action such as Set and Print and catch those before evaluation. – Mr.Wizard Feb 09 '12 at 09:11
  • 1
    I don't think there's a way to implement the built-in's behaviour without leaking in many cases. Because how could you tell if a condition's evaluation is necessary to tell if it matches or is simply the function doing it's work as in Print, Do, etc? – Rojo Aug 15 '12 at 11:14