2 added 340 characters in body
source | link

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.

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}

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.

1
source | link

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}