19

I want LaTeX to throw an error message if I use a command more than once in a file.

This is allowed

\documentclass{article}

\newcommand{\mycommand}{Test}

\begin{document}

\mycommand

\end{document}

This is should throw an error message

\documentclass{article}

\newcommand{\mycommand}{Test}

\begin{document}

\mycommand

\mycommand

\end{document}
1

2 Answers 2

22

Let the command redefine itself:

\documentclass{article}

\newcommand\myCommandOnce{%
  Test%
  \renewcommand\myCommandOnce{\GenericError{}
    {Error: \string\myCommandOnce\space used twice!}
    {Command was setup to be usable only once}{}}%
}
\newcommand{\mycommand}{Test}

\begin{document}

\myCommandOnce
\myCommandOnce

\mycommand
\mycommand

\end{document}

If you intend to create many of those commands, you can use the following. I created a small/stupid wrapper around \newcommand which inserts the redefining part after the rest of the specified definition. My code might not be well looking and I guess that more experienced LaTeX users would create it differently.

The name of the wrapper macro is \newonetimecommand and it accepts the same arguments like \newcommand plus an ! as its first optional argument. If the exclamation mark is given, the command is globally usable only once.

EDIT: The below code is changed from the original version, because the optional processor didn't work. As a result, only macros with arguments were possible. Now I use O{\use:c{c_novalue_tl}} instead of o. The result is just something which is very unlikely to be inserted and checked with a \str_if_eq:nnTF.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\cs_set_protected:Nn \my_optional_processor:n
  {
    \str_if_eq:nnTF { #1 } { \use:c { c_novalue_tl } }
      { \def \ProcessedArgument {} }
      { \def \ProcessedArgument { [#1] } }
  }
\ExplSyntaxOff
\newcommand*\MyStarredProcessor[1]{%
  \IfBooleanTF{#1}
    {\def\ProcessedArgument{*}}
    {\def\ProcessedArgument{}}}
\ExplSyntaxOn
\NewDocumentCommand{\newonetimecommand}
  { t!
    >{\MyStarredProcessor}s
    m
    >{\my_optional_processor:n}O{ \use:c { c_novalue_tl } }
    >{\my_optional_processor:n}+O{ \use:c { c_novalue_tl } }
    +m }{%
  \newcommand#2#3#4#5{%
    #6%
    \IfBooleanTF{#1}{\gdef}{\def}#3{%
      \GenericError{}
        {Error:~\string#3~used~twice!}
        {Command~was~setup~to~be~usable~only~once}{}%
    }%
  }}
\ExplSyntaxOff

\newonetimecommand*\myCommandOnce[1][]{Test%
  \if\relax\detokenize{#1}\relax\else\ #1\fi}
\newonetimecommand!*\myCommandReallyOnce[1][]{Test%
  \if\relax\detokenize{#1}\relax\else\ #1\fi}
\newonetimecommand\foo{Test}
\newcommand{\mycommand}{Test}

\begin{document}

{\myCommandOnce}
\myCommandOnce

{\myCommandReallyOnce}
%\myCommandReallyOnce

\mycommand
\mycommand

\foo


\end{document}
2
  • 1
    Yes, I do intend to create many of those commands. Great edit! Commented Jan 17, 2018 at 19:58
  • 2
    @Sr.Schneider I made a very important edit to the code I provided in my edit. It is just one additional character (+) but is really important for the macro. If the + is not present, you can't specify macros which include a \par (or two consecutive newlines) in their definition.
    – Skillmon
    Commented Jan 17, 2018 at 22:28
15

You can use

\newcommand{\mycommand}{%
  \renewcommand{\mycommand}{\PackageError{mypkg}{two mycommands}{read the documentation}}%
  Test}

If you need the redefinition to be global, so that you may not have two \newcommand even in separate environments then

\newcommand{\mycommand}{%
   \gdef\mycommand{\PackageError{mypkg}{two mycommands}{read the documentation}}%
  Test}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .