Let's say I want to overload the built-in function Lookup, to handle my data wrapped in myObject. One would use TagSet or TagsetDelayed (f /: lhs = rhs or f /: lhs := rhs) like this:

myObject /: Lookup[o_myObject, args___] := Lookup[First[o], args];

This won't work because the HoldAllComplete attribute of Lookup prevents checking the head of the argument (everything is done internal to Lookup, which I don't want to meddle with).

obj = myObject[<|a -> 1, b -> 2|>]
Lookup[Evaluate[obj], b]
Lookup::invrl: The argument myObject[<|a->1,b->2|>] is not a
               valid Association or a list of rules. >>

Is there any way to overload such a function to handle arbitrary input wrappers?

  • 3
    $\begingroup$ Probably not (that is, unless you want to add DownValues to Lookup, and I wouldn't do that). HoldAllComplete is hard to bargain with. But if you define your own data type, you could define your own heads for lookup. So, what are the cases where this is a real problem then? $\endgroup$ Commented Mar 10, 2016 at 15:24
  • 1
    $\begingroup$ One other thing you could try would be lexical substitutions / code generation. Something like withLookup = Function[code, Unevaluated[code] /. HoldPattern[Lookup[o_myObject, args___]]:>Lookup[First@obj, args], HoldAll]. But this is of course limited and can't be made fully dynamic without introducing a fully typed code (type system). $\endgroup$ Commented Mar 10, 2016 at 15:28
  • 4
    $\begingroup$ You could self-answer based on what is currently known. The votes indicate that people are interested. If we overlooked something, perhaps someone will enlighten us. $\endgroup$ Commented Mar 10, 2016 at 17:15
  • 1
    $\begingroup$ @Mr.Wizard Thanks for the extra work. To be honest, I gave up on the issue shortly after posting, realizing that whatever I do, it won't be robust. So I left this project of mine for a year, and now that you provided some workaround, I thought that that's the best one can achieve. I'm not satisfied with your solution (extra [] is not nice), but I have to accept the limits. That is my main issue with Mathematica recently: it is no use introducing new, compact objects (a la FittedModel for example) as one cannot really integrate it with System functions properly. $\endgroup$ Commented Feb 10, 2017 at 11:36
  • 1
    $\begingroup$ @Mr.Wizard My original context was as simple as my example: to have an object that stores lots of values in an association but is formatted as a compact thing (myObject), not to clutter the screen. But then I wanted to have all the Association-related facilties to work with it (like Normal, Join, Lookup, Dataset, etc.). And then I realized at Lookup that I couldn't do it. And I didn't want to introduce my own functions to go with myObject, as Leonid has suggested. $\endgroup$ Commented Feb 10, 2017 at 11:40

1 Answer 1


This "unanswered" question has been sitting for too long.

The documentation for HoldAllComplete says (emphasis mine):

HoldAllComplete not only prevents arguments from being evaluated, but also prevents Sequence objects from being flattened, Unevaluated wrappers from being stripped, and upvalues associated with arguments from being used.

So this attribute exists expressly to prevent upvalues such as the one you make from being active.

However since Lookup happily evaluates whatever first argument it is given you are free to use other evaluation rules on myObject, for example:

myObject[asc_Association][] := asc

obj = myObject[<|a -> 1, b -> 2|>];

Lookup[obj[], b]

This may be a tautology but your example doesn't make clear what you're really trying to do.

Perhaps you wish to escape from Lookup entirely. This is one approach:


myObject[asc_Association][] := 
  Return[#, Lookup] & /@ 
      HoldForm[Lookup[_, args___]] :>
        myLookupSurrogate[asc, args]

obj = myObject[<|a -> 1, b -> 2|>];

Lookup[obj[], b]
myLookupSurrogate[<|a -> 1, b -> 2|>, b]

This still requires adding [] to a use of obj but it at least seems close to the spirit of what you're apparently seeking.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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