I am developing a (large) package which does not load properly anymore.
This happened after I changed a single line of code.
When I attempt to load the package (with Needs), the package starts loading and then one of the setdelayed definitions “comes alive” (ie. Is somehow evaluated), gets trapped in an error trapping routine loaded a few lines before and the package loading aborts.
The error trapping routine with abort is doing its job, except that it should not have been called in the first place, during the package loading phase.
The error message reveals that the wrong argument is in fact a pattern expression which I use on the lhs of a setdelayed definition a few lines later.
Something like this:
……Some code lines
Changed line of code
g[x_?NotGoodQ]:=(Message[g::nogood, x];Abort[])
……..some other code lines
g/: cccQ[g[x0_]]:=True
When I attempt to load the package, I get:
g::nogood: Argument x0_ is not good
As you see the passed argument is a pattern and it can only come from the code line above.
I tried to find the reason for this behavior, but I have been unsuccessful so far. So I decided to use the powerful Workbench debugging tools .
I would like to see step by step (or with breakpoints) what happens when I load the package. I am not yet too familiar with WB, but it seems that ,using Debug as…, the package is first loaded and then eventually debugged with breakpoints, ect. My problem is that the package does not even load completely! And any breakpoint set before loading the package does not seem to be effective.
So…2 questions:
- can anybody please explain why these code lines "come alive" during package loading? (there are no obvious syntax errors or code fragments left in the package as far as I can see)
- can anybody please explain how (if) is possible to examine/debug package code while being loaded in WB?
Thank you for any help.
Edit
In light of Leonid's answer and using his EvenQ example:
We can avoid using Holdpattern
simply by definying upvalues for g BEFORE downvalues for g
notGoodQ[x_] := EvenQ[x];
Clear[g];
g /: cccQ[g[x0_]] := True
g[x_?notGoodQ] := (Message[g::nogood, x]; Abort[])
Now
?g
Global`g
cccQ[g[x0_]]^:=True
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
In[6]:= cccQ[g[1]]
Out[6]= True
while
In[7]:= cccQ[g[2]]
During evaluation of In[7]:= g::nogood: -- Message text not found -- (2)
Out[7]= $Aborted
So...general rule:
When writing a function g, first define upvalues for g, then define downvalues for g, otherwise use Holdpattern
Can you subscribe to this rule?
Leonid says that using Holdpattern
might indicate improvable design. Besides the solution indicated above, how could one improve the design of the little code above or, better, in general when dealing with upvalues?
Thank you for your help
Leaving aside the WB (which is not really needed to answer your question) - the problem seems to have a straightforward answer based only on how expressions are evaluated during assignments. Here is an example:
To make it work, I deliberately made a definition for
notGoodQ
to always returnTrue
. Now, why wasg[x0_]
evaluated during the assignment throughTagSetDelayed
? The answer is that, whileTagSetDelayed
(as well asSetDelayed
) in an assignmenth/:f[h[elem1,...,elemn]]:=...
does not apply any rules thatf
may have, it will evaluateh[elem1,...,elem2]
, as well asf
. Here is an example:The fact that
TagSetDelayed
isHoldAll
does not mean that it does not evaluate its arguments - it only means that the arguments arrive to it unevaluated, and whether or not they will be evaluated depends on the semantics ofTagSetDelayed
(which I briefly described above). The same holds forSetDelayed
, so the commonly used statement that it "does not evaluate its arguments" is not literally correct. A more correct statement is that it receives the arguments unevaluated and does evaluate them in a special way - not evaluate the r.h.s, while for l.h.s., evaluate head and elements but not apply rules for the head. To avoid that, you may wrap things inHoldPattern
, like this:This goes through. Here is some usage:
Note however that the need for
HoldPattern
inside your left-hand side when making a definition is often a sign that the expression inside your head may also evaluate during the function call, which may break your code. Here is an example of what I mean:This code attempts to catch cases like
h[f[something]]
, but it will obviously fail sincef[something]
will evaluate before the evaluation comes toh
:For me, the need for
HoldPattern
on the l.h.s. is a sign that I need to reconsider my design.EDIT
Regarding debugging during loading in WB, one thing you can do (IIRC, can not check right now) is to use good old print statements, the output of which will appear in the WB's console. Personally, I rarely feel a need for debugger for this purpose (debugging package when loading)
EDIT 2
In response to the edit in the question:
Regarding the order of definitions: yes, you can do this, and it solves this particular problem. But, generally, this isn't robust, and I would not consider it a good general method. It is hard to give a definite advice for a case at hand, since it is a bit out of its context, but it seems to me that the use of
UpValues
here is unjustified. If this is done for error - handling, there are other ways to do it without usingUpValues
.Generally,
UpValues
are used most commonly to overload some function in a safe way, without adding any rule to the function being overloaded. One advice is to avoid associatingUpValues
with heads which also haveDownValues
and may evaluate -by doing this you start playing a game with evaluator, and will eventually lose. The safest is to attachUpValues
to inert symbols (heads, containers), which often represent a "type" of objects on which you want to overload a given function.Regarding my comment on the presence of
HoldPattern
indicating a bad design. There certainly are legitimate uses forHoldPattern
, such as this (somewhat artificial) one:Here it is justified because in many cases
Plus
remains unevaluated, and is useful in its unevaluated form - since one can deduce that it represents a sum. We needHoldPattern
here because of the wayPlus
is defined on a single argument, and because a pattern happens to be a single argument (even though it describes generally multiple arguments) during the definition. So, we useHoldPattern
here to prevent treating the pattern as normal argument, but this is mostly different from the intended use cases forPlus
. Whenever this is the case (we are sure that the definition will work all right for intended use cases),HoldPattern
is fine. Note b.t.w., that this example is also fragile:The reason why it is still mostly OK is that normally we don't use
Plus
on a single argument.But, there is a second group of cases, where the structure of usually supplied arguments is the same as the structure of patterns used for the definition. In this case, pattern evaluation during the assignment indicates that the same evaluation will happen with actual arguments during the function calls. Your usage falls into this category. My comment for a design flaw was for such cases - you can prevent the pattern from evaluating, but you will have to prevent the arguments from evaluating as well, to make this work. And pattern-matching against not completely evaluated expression is fragile. Also, the function should never assume some extra conditions (beyond what it can type-check) for the arguments.