Why isn't Lookup treated like other symbols?

With Mathematica 10, I wanted to overload Lookup using TagSetDelayed, but it doesn't work. For instance, if I define two objects with head TempHead

t1 = TempHead[a -> 1, b -> 2, c -> 3];
t2 = TempHead[c -> 3, d -> 4, e -> 5];


I can overload Plus as usual:

TempHead /: Plus[t1_TempHead, t2_TempHead] := TempHead @@ Join[List @@ t1, List @@ t2]


So:

t1 + t2
(* TempHead[a -> 1, b -> 2, c -> 3, c -> 3, d -> 4, e -> 5] *)


But, if I do the same thing with Lookup, it doesn't work:

TempHead /: Lookup[t1_TempHead, t2_TempHead] := TempHead @@ Join[List @@ t1, List @@ t2]
Lookup[t1,t2]
(* Lookup::invrp: The argument TempHead[a->1,b->2,c->3] is not a valid Association or a list. >> *)


Further, you cannot even use Unprotect to overload Lookup. I thought this was a bug, but when I reported it to Wolfram, they said Lookup was designed to give an error on all objects that aren't Associations. Certainly there are Mathematica functions that give errors (e.g. Part, when you try to access outside the length of a List), but you can usually still overload them. Does anyone know if there is a good reason for implementing Lookup this way? It seems to break with the "Everything is an expression" principle that Wolfram is always touting. Are there other symbols that act like Lookup?

• You seem to misunderstand what ´TempHead /: Lookup[t1_TempHead, t2_TempHead]´ actually does (which caused some confusion for RunnyKine and m_goldberg, see below): It adds a definition to (the UpValues) of ´TempHead´, not to ´Lookup´. That's why unprotecting ´Lookup´ doesn't help of course. – sebhofer Aug 20 '14 at 23:40

Warning: Modifying a built-in function is not advised

As @m_goldberg already stated, Lookup has Attributes HoldAllComplete, so a workaround will be to remove this Attribute:

Edit: As per m_goldberg's recommendation

attr = Attributes[Lookup];
Attributes[Lookup] = {};


Now

t1 = TempHead[a -> 1, b -> 2, c -> 3];
t2 = TempHead[c -> 3, d -> 4, e -> 5];



Finally:

Lookup[t1, t2]


Gives the desired output:

TempHead[a -> 1, b -> 2, c -> 3, c -> 3, d -> 4, e -> 5]

Remember to restore the Attributes when you're done

Attributes[Lookup] = attr;

• Don't you think removing HoldAllComplete is dangerous to the normal functioning of LookUp? – m_goldberg Aug 20 '14 at 20:25
• @m_goldberg Well, Unprotecting any built-in function and modifying it is "dangerous" to the normal functionality of that function :) – RunnyKine Aug 20 '14 at 20:27
• @m_goldberg, I have added that disclosure but I need you to clarify something for me. Is this question by itself not assuming a modification of a built-in function? If so, shouldn't the OP add that disclosure? – RunnyKine Aug 20 '14 at 20:35
• I don't think the OP contemplated modifying any built-in functions. He seems unaware of the difference between standard evaluation and non-standard evaluation, so he thought creating up-values, which does not involve modifying built-ins, would work. Modifying Lookup may be required, but it was not assumed a priori. – m_goldberg Aug 20 '14 at 20:43
• The OP clearly states: "I wanted to overload Lookup using TagSetDelayed. – eldo Aug 20 '14 at 20:55

Lookup has the attribute HoldAllComplete, which means the kernel evaluator will not see its arguments and, therefore, will not look at its up-values.