# How do I identify the source of a “Tag times protected” error?

I have some code that looks like

Table[
a = 1;
b = {2, 3}
c = i;,
{i, 2}
]


which gives an error:

Set::write: Tag Times in c {2,3} is Protected. >>

In this case, it is quite clear that there is a semicolon missing after b = {2, 3}, which is causing this error. However, sometimes I encounter this in large code blocks spanning several lines, which is very difficult to debug.

How can I automate this semicolon hunting to make debugging easier?

-
Worth to mention that Tag Times ... is Protected message is in 90% cases the result of a missing semicolon. – Kuba Feb 3 at 7:02
Please, upvote the comment of Kuba! – Rexcirus Mar 1 at 20:36

Here is a function findBadSets that will find any explicitly bad Set/SetDelayed attempts in a given expression. Simply wrap it around a syntactically complete block of code, or follow the block with // findBadSets and the errors are printed one per row, protected symbol followed by complete left-hand side for each bad Set:

(* your example *) // findBadSets


Code for the function:

SetAttributes[findBadSets, HoldFirst]

Cases[
Unevaluated @ expr,
/; MemberQ[Attributes@head, Protected] :>
-1] // Column


-
WoW, so useful! – matheorem Nov 15 '13 at 1:32
@matheorem My pleasure. :-) – Mr.Wizard Nov 15 '13 at 19:03
That's certainly a faq. – Kuba Feb 3 at 6:44
@Kuba thanks for tagging. – Mr.Wizard Feb 3 at 6:54
This is a perfect example of what we could get from code helping functions. For some time now that WRI talks about the eventual inclusion of code improvement suggestion tools. A typical example given is the suggestion of WL functions that could do exactly what the user is programming with a more complex code. But even simpler things can be included, like the small code of Mr. Wizard, but also, for instance, a warning check of "all" the things listed on our common pitfalls post. Is there a frontend framework missing for this purpose? I would even be willing to participate/\$ on a crowdfunding... – P. Fonseca Feb 3 at 8:46

One can use Trace for this. I stuck in an extra, different error to show it is omitted in the output. It should also be clear how to trace other error messages.

foo = Trace[
Table[
a = 1/0;
b = {2, 3}
c = i;,
{i, 2}],
HoldPattern@Message[Set::write, ___],
TraceAbove -> True]
(* Power::infty, Set::write errors *)


If you would like a function like Mr.Wizard's to apply to a code block, we can wrap it up like this:

traceSet = Function[code,
Trace[
code,
HoldPattern@Message[Set::write, __],
TraceAbove -> True],
HoldAll]


Here is a way to view the list of lists of lists of output, somewhat reminiscent of WReach's traceView. (His function is built on TraceScan, which I could not get to work in the way above. The option TraceAbove -> True seems to be ignored. Is that a bug?)

Clear[ov];
ov[{e1_HoldForm, rest___}, open_: False] :=
OpenerView[{e1, Column[ov[#, open] & /@ {rest}, Dividers -> All]}, open];
ov[e_, _] := e


Example:

ov[foo, True]


Now you can see the offending code comes from

a = 1/0; b = {2, 3} c = i;


which leads to the actual error, {2, 3} c = i. Note that the error message already informs us that the immediate source is c {2,3}.

If it's a very large chunk of code, you can select the bottom segment of the evaluation chain as follows. The length of the chain is controlled by

Length@First@pos == 5


which can be adjusted to suit:

Cases[foo,
e_List /;
With[{pos = Position[e, HoldPattern@Message[Set::write, ___]]},
Length[pos] == 1 && Length@First@pos == 5], Infinity] //
Column[#, Dividers -> All] &


One could also apply the OpenerView to each element in the output by adding to the pattern in the second argument of Cases the code :> ov[e, True] to make it a transformation rule.

-