\providecommand equivalent of \DeclareMathOperator: \ProvideMathOperator?

I don't think such a command exists in amsmath, but you can create your own using \ifdefined.

\documentclass{article}
\usepackage{amsmath}
\newcommand\ProvideMathOperator[2]{\ifdefined#1\else\DeclareMathOperator{#1}{#2}\fi}
\DeclareMathOperator{\goat}{goat}
\ProvideMathOperator{\sheep}{sheep}
\ProvideMathOperator{\goat}{} %Has no effect because \goat is already defined.
\begin{document}
$\goat$ $\sheep$ 
\end{document}

I'd be very cautions in using \providecommand or variations thereof. This simple example may show why: if you say

\providecommand{\box}{something}

and then start using \box in your document, very puzzling error messages will be raised.

One might think to define a \ProvideMathOperator that also checks for the definition of the first argument, if already defined somehow, and warns if the control sequence we are trying to define is an operator (with the same definition) or not.

However this is quite hard: the supplied control sequence might have any definition, with mandatory or optional arguments, be robust or even be unexpandable.

One could deal with all these variations, in principle, but it's rather hard (I assure you it really is). The number of predefined math operators is not very big, after all, so the "use \DeclareMathOperator and try with another name if LaTeX complains" way seems to be the less complicated one.


Here's a rather simplistic procedure:

\documentclass{article}
\usepackage{amsmath,xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\ProvideMathOperator}{smm}
 {
  \cs_if_exist:NTF #2
   {
    \xopn_check:Nn #2 { #3 }
   }
   {
    \IfBooleanTF{#1}
      { \DeclareMathOperator*{#2}{#3} }
      { \DeclareMathOperator{#2}{#3} }
   }
 }
\cs_new_protected:Npn \xopn_check:Nn #1 #2
 {
  \cs_if_exist:cTF { \cs_to_str:N #1\c_space_tl }
   {
    \tl_set:Nx \l_xopn_name_tl { \token_get_replacement_spec:c { \cs_to_str:N #1 \c_space_tl } }
   }
   {
    \tl_set:Nx \l_xopn_name_tl { \token_get_replacement_spec:c { \cs_to_str:N #1 } }
   }
   \xopn_check_operator:Nn #1 { #2 }
 }
\cs_new_protected:Npn \xopn_check_operator:Nn #1 #2
 {
  \regex_match:nVTF { \A \\qopname\ \\(newmcodes@|relax)\ (o|m) \{ #2 \} \Z } \l_xopn_name_tl
    { \msg_warning:nnx { xopn } { samedefinition } { \token_to_str:N #1 } }
    { \msg_warning:nnxx { xopn } { differentdefinition } { \token_to_str:N #1 } { \l_xopn_name_tl } }
 }
\cs_generate_variant:Nn \regex_match:nnTF {nV}
\cs_generate_variant:Nn \token_get_replacement_spec:N {c}
\msg_new:nnn { xopn } { samedefinition }
 {
  The~operator~`#1'~already~exists~with~the~same~definition
 }
\msg_new:nnn { xopn } { differentdefinition }
 {
  The~command~`#1'~has~already~a~different~definition\\
  \\
  #2\\
  \\
  (If~the~above~reads~`\token_to_str:N \scan_stop:'~don't~
  redefine~`#1'~under~any~circumstances,~but~be~cautious~anyway)
 }
\ExplSyntaxOff

\ProvideMathOperator{\log}{log}
\ProvideMathOperator{\gcd}{gcd}
\DeclareMathOperator{\Tor}{Tor}
\ProvideMathOperator{\Tor}{Tor}

\ProvideMathOperator{\null}{null}
\ProvideMathOperator{\fi}{fi}

I just try and see whether the proposed control sequence exists or not; in the latter case \DeclareMathOperator is safe. In the former case, I look whether the "command with trailing space in the name" exists; then I compare the meaning of the command (using the one with the trailing space, if existent) to what amsmath would have defined it if it's an operator.

The output of the document is

*************************************************
* xopn warning: "samedefinition"
* 
* The operator `\log' already exists with the same definition
*************************************************
*************************************************
* xopn warning: "samedefinition"
* 
* The operator `\gcd' already exists with the same definition
*************************************************
*************************************************
* xopn warning: "samedefinition"
* 
* The operator `\Tor' already exists with the same definition
*************************************************
*************************************************
* xopn warning: "differentdefinition"
* 
* The command `\null' has already a different definition
* 
* \hbox {}
* 
* (If the above reads `\scan_stop:' don't redefine `\null' under any
* circumstances, but be cautious anyway)
*************************************************
*************************************************
* xopn warning: "differentdefinition"
* 
* The command `\fi' has already a different definition
* 
* \scan_stop: 
* 
* (If the above reads `\scan_stop:' don't redefine `\fi' under any
* circumstances, but be cautious anyway)
*************************************************

When the warning is issued, no definition is performed.

\ProvideMathOperator accepts the *-variant just like \DeclareMathOperator.

Tags:

Amsmath