# How do I use a passed-in symbol as a tag to define UpValues?

ClearAll@foo;
foo[tag_] := (
tag /: tag[i_] := tag[[i]]
);
a = {7, 8, 9};
foo[a];
a[2]


I wanted the above to output 8, but encountered an error:

TagSetDelayed::sym: "Argument {7,8,9} at position 1 is expected to be a symbol. "

I think I understand that. It's currently a List, not a Symbol. So, I tried adding

SetAttributes[foo, HoldFirst];


after which I encountered another error:

TagSetDelayed::tagnf: "Tag a not found in {7,8,9}[i$_]." Okay, so tag evaluated, I believe because it was in the form _[___]. So next, I added Unevaluated: foo[tag_] := ( tag /: Unevaluated[tag][i_] := tag[[i]] );  But this resulted in TagSetDelayed::tagpos: "Tag a in Unevaluated[a][i$_] is too deep for an assigned rule to be found."

This, I don't understand...

-

Your problem has nothing to do with the function foo, but rather with the definition itself. Observe:

a = {7, 8, 9};

a /: a[i_] := a[[i]]


Because heads evaluate first you cannot even use the attempted definition for a while a has a direct (OwnValue) assignment:

ClearAll[a]
a /: a[i_] := z[i]

a = {7, 8, 9};

a[2]

{7, 8, 9}[2]


Further, TagSet serves no purpose here as you are actually defining a DownValue rule rather than an UpValue rule:

DownValues[a]

{HoldPattern[a[i_]] :> z[i]}

-
Thank you. I'm going to have to take some time to understand this. But meanwhile, could you confirm something? I'd like to be assign to the results of such an expression, i.e. a[2] = 42 to make a {7, 42, 9}. I'm essentially trying to write a function that implements @ssch's answer here: mathematica.stackexchange.com/questions/34850/…. I must retain the use of UpValues then, correct? (Perhaps I simplified the example too far.) – Andrew Cheong Jan 25 '14 at 18:13
@acheong87 That appears to be different from what you attempted in this question. I am not sure how ssch's method fails you. If you explain what you are actually trying to do I can probably help. Also, you may way to read this. – Mr.Wizard Jan 25 '14 at 18:47
Okay, I understand now that you're (of course) completely right; my issue had nothing to do with the passing of a symbol, but rather my attempt to define an UpValue on a symbol that already had an OwnValue (if that's the right way of describing it). My real question, it turns out, is, Is it possible for a symbol to (at least appear to) have both an OwnValue (data) as well as an UpValue (a setter/getter function)? Not sure if I should edit this question (making the current answers irrelevant), or if it's worth asking a new question. – Andrew Cheong Jan 26 '14 at 2:03
@acheong87 I think that would be better as a new question, but first make sure you understand what an UpValue is; as I noted your example in this question does not create an UpValue definition; an UpValue much be attached to a Symbol that appears as the head of an expression at level one in the left-hand-side pattern, such as a in {a[x_], y_} ^:= x^y – Mr.Wizard Jan 26 '14 at 2:36

Mr.Wizard told you what you did wrong but he didn't answer the implied question of how to accomplish what you want to do. Here is one way to do it.

ClearAll[foo, a];
SetAttributes[foo, HoldFirst];
foo[var_Symbol, data_List] := (Set[var[#], data[[#]]] & /@ Range[Length[data]])

foo[a, {7, 8, 9}];
a[2]

8


DownValues @ a

{HoldPattern[a[1]]:>7, HoldPattern[a[2]]:>8, HoldPattern[a[3]]:>9}

-