It is know that some built-in functions are system function and changing their properties may cause trouble.

Suppose for example I want to change features of Cases:

SetAttributes[Cases, HoldFirst]

This will create a problem in MMA.

Is there a method to copy the built-in functions (for example Cases) so that the new named function can be used as if it is the built-in functions and then I can do whatever changes I want to the new function?

This works but creates problem in MMA:

SetAttributes[Cases, HoldFirst];
Cases[1 + 3, _, {-1}]
(*{1, 3}*)

I tried this but it does not work:

f = Cases;
SetAttributes[f, HoldFirst];
f[1 + 3, _, {-1}]




To get it out of the way, for the specific example given you could use Unevaluated:

Cases[Unevaluated[1 + 3], _, {-1}]
{1, 3}

To actually be able to modify a System function I recommend Internal`InheritedBlock:

SetAttributes[cases, HoldAll]

cases[args___] :=
    SetAttributes[Cases, HoldFirst];

cases[1 + 3, _, {-1}]
{1, 3}

This does not make additional definitions convenient however. I am working on that.

Experimental construct

I think this may be useful. The idea is to have to associate cases with Cases only once, then be able to work with cases as desired. It is limited to DownValues and Attributes for now as I cannot think of a clean way to extend it to SubValues, UpValues, etc. That can probably be done with Stack but I am not as comfortable with that method as Leonid is so I shall leave it to a last resort.

SetAttributes[{clone, parent}, HoldAll]

clone[from_, to_] := Scan[(#[to] = #[from];) &, {DownValues, Attributes}]

parent[lhs_ -> rhs_] := (
  clone[lhs, rhs];
  x_rhs :=
    Internal`InheritedBlock[{rhs = lhs},
      clone[rhs, lhs];

Call it before definitions are made to cases:

parent[Cases -> cases];

Then add definitions to cases as desired:

SetAttributes[cases, HoldFirst]               (* test of Attributes *)

cases[a_, b_, "foo"] := cases[2^a, b, {-1}]   (* test of DownValues *)


cases[1 + 3, _, "foo"]
{2, 1, 3}
  • 1
    $\begingroup$ +1. I have to point out, that your experimental construct is very similar to the one I described here - same ideas about double-cloning, and Block-ing. $\endgroup$ Feb 7 '15 at 14:15
  • $\begingroup$ @Leonid Fair enough. I did link that thread in a Related: comment. I starting working on this before looking at that, remembered you once wrote a clone function, looked at it and decided it was more complicated than I wanted here, and finished what you see above. I have no doubt you could do this more robustly and probably include some Stack magic to provide full emulation, and I encourage you to do so if you have time. $\endgroup$
    – Mr.Wizard
    Feb 7 '15 at 14:35
  • $\begingroup$ Re: links - you are right, I haven't checked those. Although, given your answer, it would perhaps make more sense to mention them directly in it, but that's of course up to you. Besides, your construct is still different and used in a different context. Re: clone - there is actually a better way, exposed by Szabolcs here. $\endgroup$ Feb 7 '15 at 14:42
  • $\begingroup$ @Leonid If I had based my code on yours I would have linked from within the answer as that's my standard practice. (As I'm sure you've seen.) ExtendedFullDefinition and friends don't work with core functions, correct? So specifically not applicable here? $\endgroup$
    – Mr.Wizard
    Feb 7 '15 at 14:57
  • $\begingroup$ @Leonid Okay, I could at least use that to copy attributes and downvalues instead of my clone, but I'd need to change the "ExcludedContexts" option which ultimately makes it just as complex. $\endgroup$
    – Mr.Wizard
    Feb 7 '15 at 15:06

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.