HoldFirst being overridden by Activate [duplicate]

So here's the problem a=1;a=2 works because of the HoldFirst attribute of Set, so that it does not become 1=2 But a=1;Activate[Inactivate[a=2]] does not because the attributes of Set is lost during Inactivate. So how do I avoid this problem?

Update So I've read the answers and it was a brilliant solution. The reason for my use of Inactivate is is meta-programming, where the symbols are Inactive during the construction to avoid messing everything up. But I used Set in the code so that's why I encountered this problem.

• Any solution will probably include a lot of trickery - the problem is that the only composite head that can have attributes is Function[...], but there is no way to prevent expressions of the form Function[...][...] from evaluating. You could of course use a different way to inactivate the heads, but making them composite seems like the best way if one wants to preserve the structure of the expression. Jan 15 '19 at 12:58
• One could argue that it is exactly what should be expected to happen since you are inactivating Set so it behaves as it wasn't there. If you don't wan't it, what do you expect from Inactivate?
– Kuba
Jan 15 '19 at 13:01
• maybe Activate[Inactivate[Inactive[a] = 2]]?
– kglr
Jan 15 '19 at 13:02
• Maybe you can use Hold and ReleaseHold? Jan 15 '19 at 13:32
• @Kuba I'm guessing that the OP is looking for a variation of Inactive[Set] that has the HoldFirst attribute of Set. But since Inactive[Set] is a composite head, it cannot have attributes, as far as I know. Jan 15 '19 at 16:33

[Edit: As noted in the comments, you're probably better off using Hold,ReleaseHold etc. to solve your problem, since Inactivate was never designed for this use case. Having said that, below you'll find one possible attempt to replicate the desired behaviour as closely as possible]

The goal

For this answer, I'll try to address the following requirements for a new function myInactivate:

• myInactivate should replicate the behaviour of Inactivate for cases where there are no Hold attributes at play. This includes:
• Nice typesetting
• Localized inactivation in the sense that parts are inactivated separately
• A way to activate only parts again (see possible extensions below)
• Inactivated symbols should still have the same Hold attributes as the original symbol

Examples

You can find the code for myInactivate,myActivate, etc. at the end of the answer.

myInactivate can be used just like Inactivate:

a = 1;
myInactivate[a = 2]
(* myInactive[Set][a, 2] *)

myActivate[%]
(* 2 *)


It also supports the typesetting of Inactive expressions:

myInactivate[Sum[f[a = 2, z], {n, 1, 2}]]


You can filter out all inactive heads using myInactiveQ:

myInactivate[Sum[f[a = 2, z], {n, 1, 2}]] //
Cases[#, _?myInactiveQ, All, Heads -> True] &
(* {myInactive[Sum], myInactive[f], myInactive[Set]} *)


You can also manually create inactive symbols using myInactive:

myInactive[Set][a, 2]


Possible extensions

To make something like this really something with more control than Hold and related functions, one would need to implement the two argument forms of Inactivate and Activate (i.e. filtering of what gets inactivated). This would then allow for selective inactivation, something that is difficult to achieve with Hold and friends.

How it works

As noted in the comments, composite heads (e.g. Inactive[Set]) are out, as they can't have any attributes. So the only thing we can to is to replace the heads with a new, inert symbol. This is exactly what myInactive does (let sym be the symbol to inactivate):

• If not already done, it creates a new symbol (e.g. inactivesym), with the same attributes as sym (except Protected and Locked, for obvious reasons).
• It adds the new symbol inactivesym to inactSymbols, the replacement list to revert inactivation.
• It adds a typesetting rule to typeset inactivesym[...] as Inactive[sym][...] (wrapped in an InterpretationBox, to ensure that the output can be copied)
• It adds a typesetting rule to typeset inactivesym as myInactive[sym]
• It marks inactivesym as myInactiveQ

You'll also notice the special casing of List and Rule: Apparently, Inactivate doesn't touch some inert heads such as List and Rule, so I've added them here as well.

Code

inactSymbols = <||>;

Attributes[myInactiveQ] = {HoldFirst};
myInactiveQ[_] := False

Attributes[myInactive] = {HoldFirst};
myInactive[h_] := myInactive[h] = With[
{s = Unique["inact" <> SymbolName@Unevaluated@h]},
Attributes[s] = Complement[Attributes[h], {Protected, Locked}];
MakeBoxes[s[args___], frm_] ^:= With[
{b = MakeBoxes[Inactive[h][args], frm]},
InterpretationBox[b, s[args]]
];
AppendTo[inactSymbols, s -> h];
MakeBoxes[s, frm_] ^:= MakeBoxes[myInactive[h], frm];
myInactiveQ[s] ^= True;
s
]
myInactive[s_?myInactiveQ] := s
myInactive[s : List | Rule] := s

Attributes[myInactivate] = {HoldFirst};
myInactivate[expr_] := Replace[
Unevaluated@expr,
{
i : HoldPattern[myInactive[h_][args___]] :> i,
h_Symbol[args___] :> With[
{in = myInactive[h]},
in[args] /; True
]
},
All
]

myActivate[expr_] := expr /. inactSymbols

• What features are you trying to address in general? Can you update OP to make it clear what do we aim for? One could ask why not HoldForm + ReleaseHold.
– Kuba
Jan 16 '19 at 9:12
• @Kuba I have no idea what OP wants to do with this - I agree that in general, Hold and friends are probably more suited, this is just an attempt to provide a solution if OP really wants something in the style of Inactivate. Jan 16 '19 at 9:15