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.
\leting the previous definition to\relax, or using the equivalent of\providecommand{\X}{\mbox{X}}for example, but it struck me as odd that there is not something better... Am I missing something? – mforbes Jul 17 '12 at 20:13\mboxwon't automatically give you the correct spacing around the operator (\DeclareMathOperatordoes this properly). – Ian Thompson Jul 17 '12 at 20:20\ProvideMathOperator. Let's say you want to define a "fi" operator. If you say\ProvideMathOperator{\fi}{fi}and start using\fi, the resulting errors will be puzzling. I'm very cautious also with\providecommand. – egreg Jul 17 '12 at 20:43\providecommandbut that emits an error if the definition is not the same. I though I saw something like that before, but I can't recall where I saw it. – mforbes Jul 17 '12 at 21:36xparse,\DeclareBlah... defines without checking. Thus, theamsmath\DeclareMathOperatorbehaves as if it were called\NewMathOperator. – mforbes Jul 17 '12 at 21:40