3
$\begingroup$

Suppose that someone (e.g. the author of a package I need to use) modifies the upvalues of a system function in the following way

Unprotect[Series];
Series /: Series[x_foo, rest__] := mySeries[x, rest]
Protect[Series];

So that evaluating

Series[foo[ep], {ep, 0, 2}]

yields

mySeries[foo[ep], {ep, 0, 2}]

Now I'd like to modify some of these definitions without modifying the source code of a package.

Normally I would do this by loading the original package and then running some patching code that modifies the relevant up- and downvalues introduced by the package. However, in this case this doesn't seem to be possible, as

UpValues[Series]

returns an empty list. So I'm wondering where these custom upvalues are saved and if there is a way to retrieve them?

P.S. I'm not advocating tampering with system functions, but there are packages (such as this one) that do this kind of stuff and have no analogues, so that one simply has to use them for the relevant calculations. I'm not the author of the package, so I'm in no position to fix the code and redistribute it to my colleagues (even privately). Loading the original package and applying custom patching code (that everyone can inspect) afterwards is the best solution so far.

$\endgroup$
6
  • $\begingroup$ Try GeneralUtilities`Definitions[Series] $\endgroup$ – Jason B. Mar 31 '20 at 15:29
  • 1
    $\begingroup$ UpValues are attached to the symbol on which you want the override the other one, which is what makes them a local and reasonably safe method to override functions. In your example, they should've been attached to foo: UpValues[foo]. But what you did was not adding UpValues - you actually added DownValues for Series, even though you used TagSetDelayed. To add UpValues for foo, you should've done foo /: Series[x_foo, rest__] := mySeries[x, rest], and in that case, it would also not be necessary to Unprotect the Series symbol. $\endgroup$ – Leonid Shifrin Mar 31 '20 at 15:30
  • $\begingroup$ @LeonidShifrin For foo /: Series[x_foo, ...] I agree. But here we have Series/: Series[x_foo,...] so UpValues[foo] returns an empty list. As I have already stated in the question, it is not my code and I wouldn't have done it this way. $\endgroup$ – vsht Mar 31 '20 at 15:35
  • 2
    $\begingroup$ @vsht See my updated comment - you have actually created a DownValue for Series, rather than UpValue for foo. $\endgroup$ – Leonid Shifrin Mar 31 '20 at 15:36
  • 1
    $\begingroup$ @vsht Ok, I posted the answer are requested. $\endgroup$ – Leonid Shifrin Mar 31 '20 at 17:25
4
$\begingroup$

Why it did not work

UpValues are attached to the symbol on which you want the override the other one, which is what makes them a local and reasonably safe method to override functions. In your example, they should've been attached to foo: UpValues[foo]. But what you did was not adding UpValues - you actually added DownValues for Series, even though you used TagSetDelayed.

UpValues and TagSetDelayed

It may be an important point to emphasize: the use of TagSetDelayed does not guarantee the creation of UpValues - rather, TagSetDelayed is a more general (w.r.t. say SetDelayed) construct which can create different kinds of definitions - depending on where the symbol that is used as a tag, is found in the definition being created.

OTOH, TagSetDalayed is generally more specific / precise than UpSetDelayed, since the latter will attach UpValues to all symbols which are at the right level on the l.h.s. of the definition, while the former only attaches definition to a single symbol / tag that one specifies. Which is why TagSetDalayed is usually a preferred way to attach UpValues to a symbol.

The correct form

To add UpValues for foo, you should've done

foo /: Series[x_foo, rest__] := mySeries[x, rest]

and in that case, it would also not be necessary to Unprotect the Series symbol.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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