为什么有些 LaTeX 宏使用 \newcommand 定义,而有些使用 \def 定义?

为什么有些 LaTeX 宏使用 \newcommand 定义,而有些使用 \def 定义?

我们已经看到这次精彩的讨论\def关于和之间的区别\newcommand。从答案来看,使用 \newcommand优于的优点\def 是显而易见的。

为什么有些 LaTeX 宏使用 来定义\def

让我们逐一考虑这些情况。


  • 最高级别(内核), latex.ltx

    \def\newcommand{\@star@or@long\new@command}
    

以上很明显。LaTeX 基于 TeX,并且\newcommand是 LaTeX 覆盖。 \newcommand需要先使用 TeX 原语进行定义。如果没有这个,我们就无法继续前进引导

但在此之后,仍然有那么多\defs。(恐怕我的例子是随机挑选的,因此不代表某个类别。)

\def\@ifnch
\def\makeatletter
\def\makeatother

  • 现在我们进入下一个级别,即文档类。

文章.cls,每种举一个例子。

    \newcommand\@ptsize{}

    \def\ps@headings

书籍目录,同样,每种类型随机取一个示例。

    \newcommand\@chapapp

    \def\@maketitle

回忆录.cls\def里面\newcommand(我并不一定声称上述情况不存在。)

\newcommand{\nametest}[2]{%
  \samenamefalse
  \begingroup
  \def\@memtempa{#1} \def\@memtempb{#2}
  \ifx \@memtempa\@memtempb
    \endgroup
    \samenametrue
  \else
    \endgroup
  \fi}

  • 我们再往前走一步,挑选包裹。fancyhdr.sty随机。我们发现\def\newcommand

    \newcommand{\fancyhead}
    
    \def\@fancyerrmsg
    

我的问题是,为什么 LaTeX 同时使用 \def\newcommand

它是否像开发人员当时想使用的一样简单?

(作为 TeX 使用者,我仍然使用\def,可能比 还多 \newcommand。没有什么特别的原因。我只是出于习惯这样做。)

或者有更深层次的技术原因?

答案1

使用的一个主要原因\def是,无论它是否已经存在,它本身都会定义某些东西。例如,使用 TeX,你可以定义

\def\mymacro{<stuff>}

并且不用担心\mymacro这次调用之后会存在什么。相比之下,使用纯 LaTeX,人们必须(大致)

\makeatletter
\@ifundefined{mymacro}
  {\newcommand{\mymacro}{<stuff>}}
  {\renewcommand{\mymacro}{<stuff>}}
\makeatother

虽然有些 LaTeX 结构(在latex.ltx)使用上述定义前检查,通常只是一个方便的选择\def\edef\gdef\xdef)。

此外,TeX\def允许指定非常强大的参数文本,并且无法使用纯 LaTeX 轻松复制(有关这方面的一些讨论,请参阅从 更改\def\newcommand*)。

答案2

核心 latex 格式和文章等类别的大部分样式可以追溯到最初的 latex 2.x 及更早版本。请注意,它曾经采用分钟加载 article.sty(当时是这样)删除注释的整个过程(如今正式称为 dtx/doc 系统)是因为加载未注释的文件明显比加载注释的文件要快。在这种情况下,定义一个带有错误检查的高级命令系统供用户使用,但使用较低级别的宏定义几乎所有的核心功能绝对有意义。

LaTeX2e 对其进行了一点改动,但改动不大。我们当时做的一件事是在所有用户可访问的长度(例如或列\setlength的宽度参数)中使用 latex 而不是原始长度设置,这样如果 加载了包,它们就会受到重新定义的影响。但大多数 def 仍保持为 def:-)minipagep\setlengthcalc

尽管如此,考虑到 latex2e 的功能,在内部代码中使用这两种形式仍然有意义。以最后一个例子为例

\newcommand{\fancyhead}

这是顶级命令,如果已经定义,您可能会产生错误,因为发生了一些不好的事情,周围还有一些其他冲突的代码。

\def\@fancyerrmsg

但是一旦您决定要加载包,您可能只定义需要定义的内容而不检查所有内容,这样更快(现在不太重要,但这个包比 latex2e 旧 :-) 但您也不想在每个内部定义上都生成错误,理想情况下,您希望出现一个错误表明包发生冲突,或者如果一切正常则没有错误。

答案3

遗憾的是,这真的是开发人员的感受。有时是因为它曾经是 TEX,有时是因为“开发人员就是这么用的”。LaTeX 经过了几次修订,并且呈指数级增长,远远超出了预期,因此如此规模的代码库中存在“一些”怪癖是很自然的。

LaTeX3 应该有一个更清晰的界面来定义命令,你可以在这里阅读相关内容:LaTeX3

相关内容