# How is Attributes protected and yet can still be set?

The Attributes function itself has the attributes:

Attributes[Attributes]

{HoldAll,Listable,Protected}


In particular, it is Protected which prevents me from redefining it:

Attributes = Foo

During evaluation of In[2]:= Set::wrsym: Symbol Attributes is Protected. >>

Foo


however, I am able to modify Attributes if I associate to a symbol:

Attributes[Foo] = {Protected}

{Protected}


which seems strange to me, because other functions which are Protected can't do this. For example, with this newly protected Foo function, the following fails:

Foo[a] = 5

During evaluation of In[5]:= Set::write: Tag Foo in Foo(a) is Protected. >>

5


So how does the Protected attribute really work, and what makes the situation with the Attributes function different from my simple Foo function? Is it possible to have Foo work in the same way as Attributes?

It is because Attributes have UpValues(*) associated with them so at the end you are not trying to Set to Attributes[Foo] but it will be translated.

You can mimic that with e.g. UpSetDelayed (^:=):

ClearAll[f]

Set[f[x_], attr_] ^:= SetAttributes[x, attr];

SetAttributes[f, {Protected, HoldFirst}]


f = 2

Set::wrsym: Symbol f is Protected. >>

f[x] = HoldFirst (*no error*)

Attributes[x]

{HoldFirst}


(*) Though I'm not sure if that is indeed the functionality used since <<GeneralUtilities and PrintDefinitions @ Attributes shows something like _[___, Attributes, ___] := <<kernel function>>;. It's probably done in a slightly different way, not accesible to user(?), but I believe my point is valid.

• Thanks for that! I originally figured it could be to do with Set`, but I had no idea that it could be used in this way. – JP-Ellis Apr 27 '16 at 6:36