XeLaTeX + unicode-math enters infinite loop if \nin is defined?

I frequently use the abbreviation \nin with the definition

\newcommand{\nin}{\not\in}


However, when I started doing this using xelatex and unicode-math it causes xelatex to stall. In particular the following document seems to put xelatex into an infinite loop

\documentclass{amsart}
\usepackage{unicode-math}
\newcommand{\nin}{\not\in}
\begin{document}
$$a \nin b$$
\end{document}


Frankly I'm quite puzzled as my command is defined after all packages are loaded (still fails even if I define the command after begin document) and no existing command collides with it so what is going on?

Is there any way that I can make this macro work (ideally in a way that works in both xelatex+unicode-math and pdflatex)

Just to be clear it is the definition of \nin plus the use of \not\in that causes trouble as if I replace.

$$a \nin b$$


with

$$a \not\in b$$


it still stalls but if I instead replace it with

$$a \in b$$


it executes fine.

Pursuant to egreg's comment I can define \nin as \notin and everything compiles fine. I would, however, still like to know what is going on here so I won't run into the same problem again.

• \not\in has been wrong since day 1 and should be \notin. – egreg Mar 29 '17 at 6:17
• egreg's observation that I should use \notin lets me define \nin as \notin and everything compiles. However, I would still like to know why \not\in (which works fine without the \nin macro) causes a problem in this context – Peter Gerdes Mar 29 '17 at 6:23

This is how \not is defined in unicode-math:

\cs_new:Npn \__um_newnot:N #1
{
\tl_set:Nx \l_not_token_name_tl { \token_to_str:N #1 }
\exp_args:Nx \tl_if_empty:nF { \tl_tail:V \l_not_token_name_tl }
{
\tl_set:Nx \l_not_token_name_tl { \tl_tail:V \l_not_token_name_tl }
}
\cs_if_exist:cTF { n \l_not_token_name_tl }
{
\use:c { n \l_not_token_name_tl }
}
{
\cs_if_exist:cTF { not \l_not_token_name_tl }
{
\use:c { not \l_not_token_name_tl }
}
{
\__um_oldnot: #1
}
}
}


Here \__um_oldnot: is the legacy \not; at begin document, \not is set equal to \__um_newnot:N.

Essentially, when you do \not\foo, the macro checks whether \nfoo is defined (several negated symbols are named this way). Otherwise it checks for \notfoo and failing it uses the negation slash.

Do you see the problem? If \nin is defined as you do, it's executed, which restarts the cycle, because it does \not\in… Infinite loop.

Note that \not\in has been wrong since day 1 of TeX (and its standard fonts) and it should be \notin.

Solution

\newcommand{\nin}{\notin}


The underlying idea in unicode-math is to help users into getting the right symbols. Your case shows users neglect the recommendation to use \notin rather than \notin: can you spot the difference when using pdflatex and Computer Modern?

Similarly, it's frequent to find \not\mid instead of \nmid.

More importantly, if a negated symbol exists in the Unicode repertoire, it should be used independently from user’s input. So \not\mid ought to be translated internally into \nmid and, similarly, \not\in into \notin (that for unicode-math represents a single character, rather than a superposition of two glyphs like with the legacy fonts). If we look in unicode-math-table.tex, we find

\nexists
\notin
\nni
\nmid
\nparallel
\nsim


and several others. Possibly there should also be \nin, but the tradition is to call it \notin.

Note that if you define \nfoo to be \not\foo, you run into the same problem as with \in.

• So in general I would run into problems if I tried to define a command \nTleq to be \not\Tleq. But also if I define \nTleq to display in a nice fashion then (at least with unicode-math) I can count on \not\Tleq to automatically use this definition not simply put a slash through it? – Peter Gerdes Mar 29 '17 at 6:43
• @PeterGerdes If you define \nTleq to use \not\Tleq, you run in the same problem. – egreg Mar 29 '17 at 6:53