The scope of \newcommand is the entire page


To illustrate the problem, in this question I am including

\renewcommand{\sin}{\cos}

$\renewcommand{\sin}{\cos}$Now anyone who uses \sin in an answer or a comment will get $\cos$ instead.

(I considered exploiting this when asking some simple trig question on main and then watching the confusion, but decided not to be evil.)

It would be good if the scope of \newcommand and friends could be limited to the current question/answer/comment, but I don't know whether this is possible.

-
Let's try an example in a comment: $\sin \pi = 0$. Indeed, it makes me look like a fool. – Nate Eldredge May 4 '12 at 22:17
This is a known issue. – Mariano Suárez-Alvarez May 4 '12 at 22:20
This is known, but this can be rather easily remedied: You can edit the malicious post; you can \renewcommand; and you can flag for moderator with a comment explaining what is happening. Perhaps we should institute a norm that whenever someone is intentionally breaking $\LaTeX$ the post will be flagged for moderator attention (even after correcting) and the moderators will warn the user, since breaking math display on a mathematical site is a first-degree level of trolling! – Asaf Karagila May 4 '12 at 22:26
Someone could want to copy over latex code that they already have with their custom commands. – Phira May 5 '12 at 0:52
@J.M.: As my previous comment shows, it breaks things just as well. In which case flagging for a moderator attention is needed. $\renewcommand{sin}{\text{Beer is Good!}}$ – Asaf Karagila May 5 '12 at 12:14
I commented about that here some time ago. Related question: meta.math.stackexchange.com/questions/3667/… – Willie Wong May 7 '12 at 7:39
@t.b. I would not prohibit them. I personally prefer \geqslant ($\geqslant$) over geq ($\geq$) and thus write \let\geq\geqslant in the beginning of my posts. (I don't want to write \geqslant every time.) Same with \phi ($\phi$) and \varphi ($\varphi$). – barto Apr 10 '15 at 12:29
I found that in order to include such definitions, they have to be put between dollar signs so that MathJax can see them. This leads to a space being included, which is the rendering of this empty equation. Is there a way to suppress this space? – A. Donda Apr 17 '15 at 15:56
@A.Donda Put it in the same equation as the first usage (or any other existing MathJax), rather than making the definition stand on its own, i.e. $\DeclareMathOperator{\ran}{ran}\ran f=\emptyset$ to get $\DeclareMathOperator{\ran}{ran}\ran f=\emptyset$. – Mario Carneiro May 7 '15 at 18:45

As Mariano points out, this has been reported before. Because of that conversation, MathJax v2.0 includes an extension (the begingroup extension) that would allow you to isolate the effects of \def, \newcommand, etc. to a single question, answer, or comment, but it would require changes to the SE code to force that to be used.

The changes would be to include begingroup.js in the TeX extensions array for the site's configuration, and outputing a $\begingroup$ at the beginning of each questions/answer/comment and an $\endgroup$ at the end. (These might want to be enclosed in a hidden <div> or some other tag so that they don't introduce any unwanted space.) The preview code would also have to be modified to include these, but that would need to be a bit more sophisticated, since the typesetting can be canceled in the middle (by new characters being typed) so the final \endgroup would need to be handled separately in that case. I would be happy to work that out if the powers-that-be wanted to coordinate efforts on that.

Edit: Asaf asks whether you can do anything like this "by hand". I had considered telling you about the \require{} command that will load extensions that haven't been included in the configuration, but I didn't. That's because the current preview code will not work well with the begingroup extension. If you include a $\begingroup$ in your post, but haven't yet typed the $\endgroup$, then each character you type will cause the post to be reprocessed, and each reprocessing will cause a new \begingroup to be performed without a corresponding \endgroup. This will use up memory that will not be freed (until you go to another page), and can slow MathJax down.

Similarly, if you have a long post, then even if you do have matching \begingroup and \endgroup tags, if you type fast, each letter will cancel MathJax in the middle of what it is doing, and so MathJax may be canceled after processing the \begingroup but before the \endgroup. Again, you can use up memory.

This is what I meant when I said that the preview code would need to be modified to take that into account.

While it is technically possible to use the begingroup extension by hand, you would have to be careful about how you do it. On the plus side, it only affects you when you are editing (or someone else who is editing your work), so perhaps you would be willing to put up with the difficulties.

In any case, your example doesn't really show how it would work, since \begingroup and \endgroup don't protect you from definitions from outside your answer; they protect others from definitions in your answer. So to see it really work, you would need to use something like

$$\require{begingroup} \begingroup \renewcommand{\tan}{\operatorname{grey}} \tan\theta \endgroup \ne \tan\phi$$


to get

$$\require{begingroup} \begingroup \renewcommand{\tan}{\operatorname{grey}} \tan\theta \endgroup \ne \tan\phi$$

This works, but if you don't get the balancing of begin and end groups properly during the editing process, you can be left with a lot of open begin groups, that contain local definitions that don't go away (until you reload the page).

-
Is this workaround applicable "by hand"? (Testing: $\begingroup\sin\neq\cos\endgroup$) – Asaf Karagila May 5 '12 at 20:53
@AsafKaragila I added material to my original answer about that. – Davide Cervone May 6 '12 at 10:31
Yes, I saw. Thank you. Do note that the main problem which Nate pointed is that vandals can post a malicious code and "ruin" the answer. – Asaf Karagila May 6 '12 at 10:40
Yes, I understand that. That is why I said it would take changes to the SE code to do this properly. I thought you were asking about using \begingroup and \endroup yourself (to isolate your local macros so they don't interfere with others). Perhaps I misunderstood. I do not see a way to prevent others from making definitions without changes to SE code. – Davide Cervone May 6 '12 at 11:46
I was hoping that there would be a way to locally reset inside an answer. – Asaf Karagila May 6 '12 at 11:50
I suppose if the questioner added $\require{begingroup}\begingroup$ at the bottom of the question, you could use $\endgroup\begingroup$ at the top and bottom of your answer or isolate your response from the effects of others (and localize your changes to your answer as well). But this takes cooperation of the questioner, and it also has all the preview problems that I mentioned. – Davide Cervone May 6 '12 at 11:50
That is effectively what I am suggesting that the SE code does between each question/answer/comment, but you could do it by hand for your answer provided there was an initial \begingroup in the question. – Davide Cervone May 6 '12 at 11:54
Of course that would still only prevent accidental macro leaking, not malicious leaking. For one, the begingroup extension also provides \gdef, which works around \begingroup/endgroup. Moreover, even without \gdef, a malicious poster could simply use\endgroup\renewcommand{\sin}{\cos}\begingroup to make his definition intentionally leaking. So if the goal is to prevent malicious behaviour, it has to use a mechanism which isn't accessible to users. – celtschk Jul 13 '12 at 7:10
Your point is well taken, but I think it could be handled as follows: make a new macro \reset that does the action of \endgroup\begingroup (easily done), and remove the \begingroup, \endgroup, \gdef, and \global macros. Use $\reset$ between questions/answers/posts, and rather than call MathJax's typeset by itself, first queue the \begingroup function directly, then the typeset then the \endgroup function. While the user could still call \reset in her message, it would not provide a means of entering global definitions. – Davide Cervone Jul 13 '12 at 10:38
@DavideCervone: If you make \reset completely reset the MathJax engine (i.e. remove even macros defined globally), there's no need to remove the macros from the begingroup extension. But you're right, \reset being available to users would not be harmful. – celtschk Jul 14 '12 at 10:25
@Davide: I added a fix for this issue into SOUP, but it's kind of crude: I'm basically just injecting the equivalent of $\endgroup$ $\begingroup$ at the beginning of each post and comment. It's working, but if you'd have any suggestions on how to do it more cleanly / elegantly, please do tell. The current code I have is here (look for mathJaxSetup). – Ilmari Karonen Jan 15 '14 at 21:15
@IlmariKaronen, what you have looks good except for two things: (1) you don't need to have two separate expressions, you could just do $\endroup\begingroup$, and (2), it is possible for a user to redefine \endgroup or \begingroup within their post. Preventing that would require overriding part of MathJax's code for defining macros (but it could be done). Also, make sure you first post only starts with $\begingroup$ with no leading \endgroup, and your last one should only have $\endgroup$. – Davide Cervone Jan 16 '14 at 16:05
@DavideCervone: The reason I'm using two separate expressions is precisely so that if \endgroup fails (because the stack is already empty), the following \begingroup will still run. While I could omit the first \endgroup and the last \begingroup on the page as you suggest, having new posts or other content loaded via AJAX could still cause subsequent typeset passes to start with an unbalanced \endgroup, so I have to tolerate that possibility. What I'd really like to do is implement your / celtschk's \reset idea above, but I don't know enough about MathJax internals to see how. – Ilmari Karonen Jan 16 '14 at 19:50
@DavideCervone: OK, I did figure out how to do it by monkey-patching parts of the begingroup extension. It's a bit complicated, and likely to break if the extension ever gets rewritten, but otherwise it works very nicely. – Ilmari Karonen Jan 16 '14 at 22:50
@IlmariKaronen, actually, I quite like it over all. Would you might if I incorporate something similar into the begingroup extension directly? You use an approach I hadn't thought of, and I think it works nicely (as you point out). BTW, there are a couple of other things that could be added to SOUP that I might suggest, but this is not the right pace for that. Where is best to discuss such things? – Davide Cervone Jan 17 '14 at 14:38

This answer will serve as a demonstration:

$$\sin \pi = 0$$

What I typed was true (edit or view source), but what you see is false.

-
When $\sin$ is $\sin$ and $\cos$ is $\sin$! Pythagoras rolls over in his unmarked grave. – Asaf Karagila May 4 '12 at 22:38

$\require{begingroup} \begingroup$As discussed in the comments to Davide Cervone's answer, I have added a client-side fix to this bug to version 1.2. of the Stack Overflow Unofficial Patch.

The fix works by injecting a special hidden TeX command (currently named \resetstack) at the beggining of each post, comment, snippet (as shown e.g. on the front page) or question/answer link (as in the sidebar), which resets the TeX InputJax macro definitions to their default values.

The implementation is currently a bit complicated, but hopefully it can be simplified later, if some of the needed code is incorporated directly into MathJax as Davide suggests in the comments.

Some important notes about the fix:

Since SOUP is a client-side user script, installing it will fix the bug for you, but not for others. In particular, any definitions made in your posts will still leak to other posts when viewed by users who don't have SOUP installed (which, alas, means most of them).

I therefore strongly recommend that, if you use \def, \(re)newcommand or other such features in your posts, you should always prefix them with:

$\require{begingroup} \begingroup$


and end them with:

$\endgroup$


to keep your definitions from leaking into other posts. (Note that using SOUP should eliminate any memory leak issues due to unclosed \begingroup tags while composing a post, since SOUP will reset the definition stack whenever the preview pane is re-typeset.)

You should also avoid redefining symbols in question titles, or anywhere near the top of your posts where the definitions would be likely to show up on the front page or in search results. (Alas, there's currently no 100% reliable way to prevent that from happening, except by not redefining TeX commands at all.)


Also note that, even with SOUP, definitions imported from extensions via \require will still leak into other posts. This is pretty much impossible to avoid without breaking some extensions badly, and should basically be considered as being by design.$\endgroup$

Edit: Turns out that my original implementation of this fix suffered from a race condition that made it work on Firefox only occasionally. This should be fixed in v1.2.1 that I just released; anyone using it is strongly advised to upgrade.

(Also, the upcoming v1.4 release of SOUP will have more MathJax scoping fixes, including one for \labels, again based on a suggestion by Davide Cervone. Those still need some more testing before release, though.)

-
Is it possible that SOUP could implement some sort of autosave feature to prevent loss of work due to frequent Chrome + MathJax crashes? The problem is so severe that I don't even dare to use MathJax with Chrome any more (except for trivial answers), having already lost countless hours of work due to such crashes. – Bill Dubuque Jan 18 '14 at 15:56
@Bill: The SE editor is already supposed to autosave posts, although only every 45 seconds. Of course, the real problem here is MathJax crashing Chrome, which presumably counts as a bug in both MathJax and Chrome. FWIW, I suspect things may have improved somewhat -- I use both Firefox and Chrome, and do recall experiencing poor rendering and slowdowns during editing (if not outright crashes) on the latter in the past, but not so much recently (except on the Android version of Chrome, which does get bogged down by lots of math). – Ilmari Karonen Jan 18 '14 at 16:04
Alas, the SE "autosave" feature is a kludge that works only rarely to recover from Chrome crashes. Any heavy use of MathJax + Chrome causes frequent Chrome crashses, making MathJax essentially unusable on Chrome. It's been this way for many years now. If it cannot be fixed, it would be really, really great to have some workaround, if that is not too much trouble to implement. This is by far the worst software problem I've encountered in a few decades of heavy software use. It's a shame that it has gone on this long. You can see many complaints about it in old meta posts. – Bill Dubuque Jan 18 '14 at 16:47
I agree. I can't really fix it without knowing why it happens, though, and I don't think anyone's really figured that out yet. (If someone has, please do tell me.) – Ilmari Karonen Jan 18 '14 at 16:49
I highly doubt it will ever happen. David claims it is a bug in Chrome tckled by MathJax. So the only hope is a workaround. Surely it must be very easy to implement a halfway decent autosave feature in SOUP, right? This would be the best thing since sliced bread. It would save many Chrome users countless hours of lost work. – Bill Dubuque Jan 18 '14 at 17:05
It might be possible using LocalStorage, although if Chrome crashes badly enough, that might not be perfectly safe either. I've never actually used LocalStorage before, but I could take a look into it. I'd also have to find some way to keep it from fighting with the SE builtin autosave feature, though. – Ilmari Karonen Jan 18 '14 at 17:11
Thanks! Even something more primitive such as saving to the clipboard would be helpful. The goal is to guarantee that one will not lose much work even if the browser crashes (which is very far from true for the SE draft saving feature) – Bill Dubuque Jan 18 '14 at 17:36
Javascript doesn't have access to the clipboard (for security reasons), so that is not likely to be a solution. There are some Flash-based kludges, but in general, browsers prevent javascript frmo modifying the clipboard. – Davide Cervone Jan 18 '14 at 22:42