在包或类文件中使用 \makeatletter 和 \makeatother 真的很糟糕吗?

在包或类文件中使用 \makeatletter 和 \makeatother 真的很糟糕吗?

在我对这个问题的回答中\makeatletter 和 \makeatother 起什么作用?我显然写道:

这些命令不应在文件本身内使用.sty.cls因为它们可能与加载包和类文件时发生的 catcode 更改相冲突。

事实上,这一行是 Will Robertson 添加的。所以我很好奇:有人能举一个具体的例子来说明在包或类的开头和结尾使用\makeatletterand会如何影响另一个包吗?\makeatother

我并不是在谈论如果遗漏其中一个会发生什么,正如这里所讨论的:

懈怠其他纪律到底有多糟糕?

答案1

首先,在或文件\makeatletter中是不必要的,因为默认的 catcode 机制包含它;这大概是为了鼓励包编写者使用-laden 名称来隐藏他们的宏。出于这个原因,我认为使用.sty.cls@命令在包文件中是无害的。

然而,使用一对命令在一起是有害的,因为与文档不同,你不是想要返回到@ = other包内的设置。这些是文档命令,标准顺序\makeatletter \makeatother假定这\makeatother实际上是撤消先前的更改,而在包中,这是进行更改的命令。

编辑:以下是一个更明智的答案。根据source2e.pdf,使用以下方案来加载包和类:

  1. 首先,收集选项等。
  2. 然后是当前文件的名称(即mypackage.sty),以及 catcode@,都保存在堆栈中。
  3. 然后\makeatletter运行,如果合适,则加载请求的文件。
  4. 随后,弹出堆栈并恢复预包加载状态。

换句话说,以下无知代码毫无效果

\documentclass{article}
\usepackage{bad}
\begin{document}
\end{document}

坏.sty:

\makeatletter
\makeatother
\RequirePackage{unsuspecting}

然而,很有可能一个包确实不是使用\RequirePackage,但只是\input。在这种情况下,catcode 是不是受保护,事实上,可能会出现错误,您可以通过以下方式自行检查bad.sty,例如:

\makeatletter
\makeatother
\input{pgfkeys.sty}

如果这看起来是人为的,请看一下pgfkeys.sty它本身:它\inputpgfkeys.code.tex,而该文件又\inputpgfkeysfiltered.code.tex。据推测,作者觉得自己在自己的软件包中是安全的,但没有想到其他人也可能绕过软件包加载保护机制!

答案2

在 LaTeX2.09 中,这个问题更加严重,因为 LaTeX 刚刚执行\makeatletter 一次在处理所有.sty文件之前(LaTeX2.09 没有给出.cls/.sty区分)。因此,这是一个常见问题,几乎是一个常见问题,即发布的软件包\makeatother在文件末尾执行,它们独立工作,但会破坏任何后续的“样式文件”(又名软件包)。

因此,2e 所做的第一件事就是在加载每个包时重置 catcode @,维护一个堆栈,以便在包结束时将 catcode 恢复到之前的状态。因此通过设计很难找到\makeatother包末尾的流氓程序造成危害的例子。

话虽如此,但最好不要跌倒,而不是依赖安全网。

答案3

只要您意识到不要在自己的包中做坏事(例如 Ryan Reich 的例子),您似乎在 LaTeX 提供的范围内是安全的。

但危险仍然潜伏在角落。

如果我说

\usepackage{afterpackage}

\AfterPackage{foo}{\input{bar}}

\usepackage{foo}

和里面foo.sty

\makeatother

和里面bar.tex

\protected@edef\baz{quux}

然后我收到一个错误,因为@不是一个字母(如果没有就不会发生这种情况\makeatother)。

(这个答案的重点当然是(毫无戒心的)使用者\AfterPackage不一定与软件包作者相同)

相关内容