为什么没有 \ProvideCommandCopy?

为什么没有 \ProvideCommandCopy?

当我们查看xparse软件包文档时,有四个相关命令

\NewDocumentCommand
\RenewDocumentCommand
\ProvideDocumentCommand
\DeclareDocumentCommand

同样,环境命令有四个。当我了解到时,\NewCommandCopy我预计会有类似的四个命令可用。但查看 LaTeX 源代码时,我只发现

\NewCommandCopy
\RenewCommandCopy
\DeclareCommandCopy

已定义。

是否存在\ProvideCommandCopy未定义的技术原因?

编辑:示例用例

在回答中菲利佩·奥莱尼克据称,此类命令没有用例。

假设我们想为文档提供一个黑白开关,并且我们想使用\IfBooleanTFfrom,xparse因为我们熟悉它。我们知道它导出值\BooleanFalse\BooleanTrue因此我们可以这样写

\NewCommandCopy\blackandwhite\BooleanFalse

\IfBooleanTF{\blackandwhite}{...}{...}

假设我们想在编译文档时传递它,例如pdflatex '\NewCommandCopy\blackandwhite\BooleanTrue\input{document.tex}'。这显然会导致错误,因为\blackandwhite已经定义了。如果有,\ProvideCommandCopy我们可以用它来定义 switch 的默认值\blackandwhite,以防用户不提供它。目前我们被迫始终明确定义它。

显然还有其他方法可以使黑白开关按预期工作,但我认为这是的有效用例ProvideCommandCopy

答案1

没有,\ProvideCommandCopy因为它没用(甚至可能有害),所以决定不实施它。实施中有一条注释(texdoc source2e,部分)中有一条注释复制健壮的命令ltdefns.dtx):

\ProvideCommandCopy 未定义,因为它不太有用。\provide... 命令表示“如果没有其他定义,则定义它”,但复制命令(通常)意味着被复制的命令已定义,因此 \ProvideCommandCopy 没有多大意义。但更重要的是,复制命令的最常见用例是稍后重新定义它,同时保留旧定义,例如:\ProvideComandCopy \A \B \renewcommand \B {... \A... } 然后,如果 \A 已定义,则跳过第一行,在这种情况下 \B 将无法按预期工作。

答案2

我认为大多数人只是使用典型的命令来编写文档。我认为只有一小部分用户群在 TeX/LaTeX 中编写程序并定义相当复杂的东西。

\ProvideCommandCopy我认为不在LaTeX 2ε 内核中提供的原因在于:\ProvideCommandCopy这可能是一个陷阱。此外,这\ProvideCommandCopy很少需要。因此,在大多数情况下,在内核中拥有它意味着内核中有一些未使用的东西,因此在大多数情况下只是压舱物。可能\ProvideCommandCopy需要的场景处于高级水平,用户应该能够自己定义它。;-)

我写道:“我思考理由是......”。所以这只是猜测。我既不是 LaTeX 开发团队的成员,也没有太多的见解,所以我不能代表该团队发言并证明团队的决定是正确的。

我正在推测这个原因,因为我以前问过类似的问题时也听到过这种说法。

但对我来说这并不重要,因为对于我经常需要并因此经常定义的东西,我有自己的宏包和提取例程,在代码共享的情况下,它们只提取我自己真正需要的定义。因此,只需单击一下鼠标,即可创建一个仅包含特定场景中需要的我自己定义的新模板文件。;-)


\ProvideCommandCopy如果我觉得我需要一个命令,我会简单地自己定义它,而不是与那些因为某种原因不想看到我需要的东西的人争论。

下面的例子中就是这样做的。


\DeclareCommandCopy定义在任何情况下都要定义的命令,这并不排除在过程中重新定义它。如果重新定义发生,则这是默默完成的,即,出现错误信息或类似信息。

\RenewCommandCopy定义在任何情况下都要定义的命令,这并不排除在过程中重新定义它。如果尚未定义,一个错误信息已预先出现。

\NewCommandCopy如果尚未定义,则定义要定义的命令。如果已经定义,一个出现错误消息并且未重新定义命令。

\ProvideCommandCopy如果尚未定义,则定义要定义的命令。如果已经定义,出现错误消息并且未重新定义命令。

\RenewCommandCopy/\DeclareCommandCopy\NewCommandCopy/的区别\ProvideCommandCopy在于,前者如果命令已经定义则进一步重新定义,而后者如果命令已经定义则不再重新定义。

\NewCommandCopy/\RenewCommandCopy\ProvideCommandCopy/之间的区别\DeclareCommandCopy在于,如果要定义的命令尚未定义,则会进一步引发错误消息,而后者不会引发错误消息。

所有(!!!) 这些\...CommandCopy命令都不检查要复制的命令是否已定义。

对于所有这些\...CommandCopy命令,(重新)定义仅限于\...CommandCopy执行相应命令的本地范围。

使用所有这些\...CommandCopy命令,检查要定义的命令是否已定义仅限于\...CommandCopy执行相应命令的本地范围。

\makeatletter
\providecommand*\ProvideCommandCopy{%
  \declare@commandcopy{\@firstofone}{\@firstoftwo{}}%
}%
\makeatother

\newcommand\CommandToCopy{Copy}
\newcommand\CommandBToCopy{CopyB}
\newcommand\CommandCToCopy{CopyC}
\newcommand\CommandDToCopy{CopyD}

\begingroup

\NewCommandCopy\Copy\CommandToCopy
\message{You should get "\long macro:->Copy" and you get "\meaning\Copy"}

\RenewCommandCopy\Copy\CommandBToCopy
\message{You should get "\long macro:->CopyB" and you get "\meaning\Copy"}

\DeclareCommandCopy\Copy\CommandCToCopy
\message{You should get "\long macro:->CopyC" and you get "\meaning\Copy"}

% \Copy in the current scope is already defined equal to \ComandCToCopy, thus
% \ProvideCommandCopy does not redefine \Copy:

\ProvideCommandCopy\Copy\CommandDToCopy
\message{You should get "\long macro:->CopyC" and you get "\meaning\Copy"}

\endgroup

% Now \Copy is undefined
% \Copy is not defined in the current scope, thus \ProvideCommandCopy within
% the current scope makes \Copy equal to \CommandDToCopy:

\ProvideCommandCopy\Copy\CommandDToCopy
\message{You should get "\long macro:->CopyD" and you get "\meaning\Copy"}

\stop

控制台输出:

latex-dev test.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=latex-dev)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2021-05-01> pre-release-1 (develop 2021-2-27 branch)
L3 programming layer <2021-02-18>
You should get "\long macro:->Copy" and you get "\long macro:->Copy"
You should get "\long macro:->CopyB" and you get "\long macro:->CopyB"
You should get "\long macro:->CopyC" and you get "\long macro:->CopyC"
You should get "\long macro:->CopyC" and you get "\long macro:->CopyC"
You should get "\long macro:->CopyD" and you get "\long macro:->CopyD" )
No pages of output.
Transcript written on test.log.

实际上,我看不出没有的合理理由\ProvideCommandCopy
(请注意,“拥有\ProvideCommandCopy”与“包含到内核”不同\ProvideCommandCopy。例如,可以通过在序言中或通过一些自制的宏包提供其定义来拥有命令/宏/函数。)

用例可能包括\ProvideCommandCopy在要定义的命令尚未定义的情况下将另一个命令的定义设为默认的场景。

以我的拙见,只要使用时足够小心,\ProvideCommandCopy它并不比其他命令更有害。\...CommandCopy

如果要复制命令以便稍后重新定义它,同时保留旧定义,无论它是否已定义,您都可以:在任何情况下都不要将其用于\ProvideCommandCopy存储旧定义

如果\ProvideCommandCopy没有定义,您根本无法将其用于此目的。

如果\ProvideCommandCopy已定义,则不要将其用于此目的,因为\ProvideCommandCopy这是这些命令中唯一允许以下场景的命令默默不存储旧定义。(\NewCommandCopy不存储时不会沉默,但如果存储伴随着覆盖已经存在的内容,则会收到错误消息。存储\RenewCommandCopy\DeclareCommandCopy存储都在任何情况下都会发生,而只有进一步暗示如果存储伴随着不覆盖而是重新定义要保存存储定义的宏,则会引发错误消息。)

\ProvideCopyCommand我认为由于要复制的命令通常已经定义,因此没有多大意义的论点不是很有说服力:要复制的命令不是要定义的命令。LaTeX 内核的\providecommand(因此可能也是一个(假设的)命令\ProvideCopyCommand)不会检查要复制的命令是否已定义,但会检查要定义的命令是否已定义。

大致基于《阿甘正传》:这就是我要说的全部内容。;-)

相关内容