2
$\begingroup$

This question already has an answer here:

I am redefining some of the standard math functions. I know this is dangerous, so I am trying to be extra careful. (For instance, in the redefinitions, I make sure to only match a custom head)

The redefinitions generally went smoothly. However, I noticed that the following code bit produces an error, but only when you run it the first time (using a "fresh" Kernel):

Unprotect[Plus];
Plus[p_customHead, q_Quantity] := p + q
Protect[Plus];
-> SetDelayed::write: "Tag Plus in p_customHead+q_Quantity is Protected. "

If you run the snippet a second time, it works, and the subsequent code behaves as expected (my actual redefinition is a bit more complicated and produces results that are different from a simple p+q).

I already feel uneasy about redefining the standard math functions, and this behaviour makes me doubt if I should venture any further in this direction. Is this sort of thing to be expected when using Unprotect?

$\endgroup$

marked as duplicate by Mr.Wizard Oct 25 '14 at 5:02

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • $\begingroup$ Sorry for the duplicate - I saw the StackOverflow question/answer too late. $\endgroup$ – Martin J.H. Oct 20 '14 at 15:52
  • $\begingroup$ Related: (18468) $\endgroup$ – Mr.Wizard Oct 20 '14 at 16:31
4
$\begingroup$

I found an answer on StackOverflow, which I cannot reduce any further, so I'll quote:

As you might well know, Mathematica loads binary MX files that implement some of its functionality. These MX files store implementations as well as definitions and attributes.

This is insidious, but your Unprotect[Rule] is undone by Mathematica's newly loaded MX file, and this explains why it worked the second time. Because Mathematica had already loaded all MX files it needed.

If you first evaluate all the symbols in your expression, then it stops complaining:

I modified my code accordingly, and now it works:

Quantity;
Unprotect[Plus];
Plus[p_customHead, q_Quantity] := p + q
Protect[Plus];

Addendum As foreshadowed by Leonid's comment (see also this question and the section "DownValues vs UpValues: System-wide changes vs. locality" in this answer), I ran into weird problems when I tried to evaluate deeply nested expressions. After switching to UpValues, these problems went away.

The code changes were surprisingly minimal: I only had to put customHead /: in front of the offending assignments. After the change, there is no need to Unprotect the built-in functions anymore.

With these changes, the example code from the question/answer boils down to a single line:

customHead /: Plus[p_customHead, q_Quantity] := p + q
$\endgroup$
  • 3
    $\begingroup$ As a general comment, I would much rather use UpValues on customHead, than add a DownValue to Plus, which is generally a pretty error-prone operation and should be avoided when possible. $\endgroup$ – Leonid Shifrin Oct 20 '14 at 16:21

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