Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

What is the \providecommand equivalent of \DeclareMathOperator?

I.e. as \providecommand is to \newcommand a method for defining new commands if and only if they have not already been defined?

Actually, as pointed out by @egreg in the comments, \providecommand can be dangerous since it might adversely affect the behaviour of packages that define it. What I would really like is something that combines the ability of \providecommand to quietly ensure a command exists with the functionality of \CheckCommand to make sure that the provided definition is consistent with previous definitions.

share|improve this question
    
Of course there are lots of ways of doing this, \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
1  
Using \mbox won't automatically give you the correct spacing around the operator (\DeclareMathOperator does this properly). –  Ian Thompson Jul 17 '12 at 20:20
2  
I wouldn't rely on such a \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
    
@egreg I agree: What I am actually looking for is a command like \providecommand but 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:36
    
Just a note: looking at the LaTeX3 interface in xparse, \DeclareBlah... defines without checking. Thus, the amsmath \DeclareMathOperator behaves as if it were called \NewMathOperator. –  mforbes Jul 17 '12 at 21:40
add comment

2 Answers

up vote 5 down vote accepted

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.

share|improve this answer
    
As I try to implement a simple solution, I am beginning to appreciate the "rather hard"ness of this problem! –  mforbes Jul 17 '12 at 23:00
    
@mforbes I've added a LaTeX3 solution. –  egreg Jul 18 '12 at 15:34
add comment

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}
share|improve this answer
    
As I understand it, the \provide-command would define OR redefine something, based on its existence/not. That is, not just do nothing if it already exists. –  Werner Jul 17 '12 at 20:24
    
...see the definition of \provide@command in latex.ltx. –  Werner Jul 17 '12 at 20:30
1  
@Werner --- I think you are mistaken. I just did a simple test and \providecommand did not overwrite an existing definition. –  Ian Thompson Jul 17 '12 at 20:35
1  
@Werner \providecommand doesn't redefine an already existent command. –  egreg Jul 17 '12 at 20:38
    
@egreg: True, and strange. –  Werner Jul 17 '12 at 20:49
show 7 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.