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.

I want to define a macro if it is not already defined. I can do this inline as the example below shows. But I would like to have a macro to do this functionality for me. My attempt to make this work is DefineMacroIfUndefined, but not sure how to adjust it to make it work.

I have commented out the call to DefineMacroIfUndefined as this does not compile otherwise.

\documentclass{article}

\newcommand{\CheckIfCommandDefined}{
    \ifdefined\MyNewCommand
        MyNewCommand is defined.\par%
    \else
        MyNewCommand is not defined.\par%
    \fi
}

% Define macro to the given value if not already defined
\newcommand{\DefineMacroIfUndefined}[2]{
% #1 is name of macro
% #2 is value to be assigned if this macros is not already defined.
\ifdefined\csname#1\endcsname
    % Do nothing since it is already defined
\else
    \newcommand{\csname#1\endcsname}{#2}
\fi
}

\begin{document}

% This works great.
\ifdefined\MyNewCommand
    % Do nothing since it is already defined
\else
    \newcommand{\MyNewCommand}{true}
\fi

\CheckIfCommandDefined
\let\MyNewCommand\undefined % Undefine \MyNewCommand

\CheckIfCommandDefined
% But want to be able to do the above thru a macro
%\DefineMacroIfUndefined{MyNewCommand}{true}
\CheckIfCommandDefined

\end{document}
share|improve this question

2 Answers 2

up vote 14 down vote accepted

You can simply use \providecommand instead of \newcommand. It has the same syntax but defines the macro only if it is not yet defined.


If you want to do it manual you need to use \expandafter before the \newcommand to make sure \csname ...\endcsname is expanded before it. In this case the { } should be simply dropped.

% Define macro to the given value if not already defined
\newcommand{\DefineMacroIfUndefined}[3][0]{%
% #1 is the optional argument
% #2 is name of macro
% #3 is value to be assigned if this macros is not already defined.
\ifcsname#2\endcsname
    % Do nothing since it is already defined
\else
    \expandafter\newcommand\csname#2\endcsname[#1]{#3}%
    %or: \expandafter\newcommand\expandafter{\csname#2\endcsname}[#1]{#3}%
\fi
}
share|improve this answer
    
This works nice. I assume the optional argument is the number of parameters for this macro. If so, how would I pass in what to do with the parameters? Use ##? –  Peter Grill Jun 2 '11 at 5:05
    
Sorry, I just saw your comment now. Single # should be fine here. –  Martin Scharrer Oct 23 '11 at 9:23

The following are a full set of macros I use. It has full error checking and writes every thing to the log file!!! If you try to overwrite an existing command it will stop with an error.

It gives you three command \TestedNameLet, \TestedNameDef and \TestedNameRobustDef

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatletter

% You will probably put this inside a package
\newcommand*\my@pkgname{mypackage}

\def\my@ifundefined#1{%-- Better than standard latex (eTex has better tests than this)
   \begingroup\expandafter\expandafter\expandafter\endgroup
   \expandafter\ifx\csname#1\endcsname\relax
       \expandafter\@firstoftwo
   \else
       \expandafter\@secondoftwo
   \fi}

\long\def\my@ifnamedefinable #1{%-- Test and write info to log
    \edef\reserved@a{#1}%
    \my@ifundefined\reserved@a
       {\edef\reserved@b{\expandafter\@carcube \reserved@a xxx\@nil}%
       \ifx \reserved@b\@qend \my@notdefinable\else
          \ifx \reserved@a\@qrelax \my@notdefinable\else
            \PackageInfo{\my@pkgname}{\@backslashchar\reserved@a\space created}%
          \fi
       \fi}%
    \my@notdefinable}

\gdef\my@notdefinable{%-- Error message
   \PackageError{\my@pkgname}{%
      Command \@backslashchar\reserved@a\space
      already defined.\MessageBreak
      Or name \@backslashchar\@qend... illegal.%
      }{%
      If \@backslashchar\reserved@a\space is not important\MessageBreak
      then \protect\let\@backslashchar\reserved@a%
      =\protect\relax,\MessageBreak
      else use a different \@backslashchar name.}}

%%% Base level commands %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand*{\my@namelet}[1]{\expandafter\let\csname #1\endcsname}
\newcommand*{\my@nameuse}[1]{\csname #1\endcsname}
\newcommand*{\my@namedef}[1]{\expandafter\def\csname #1\endcsname}
\newcommand*{\my@robustnamedef}[1]{%
   \expandafter\edef\csname #1\endcsname{%
      \noexpand\protect\my@nameuse{#1 }}%
   \my@namedef{#1 }}

%%% These are the commands to use %%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand*{\TestedNameLet}[1]{%
   \my@ifnamedefinable{#1}\my@namelet{#1}}

\newcommand*{\TestedNameDef}[1]{%
   \my@ifnamedefinable{#1}\my@namedef{#1}}

\newcommand*{\TestedNameRobustDef}[1]{%
   \my@ifnamedefinable{#1}\my@robustnamedef{#1}}

\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

An example of the usage is:

\newcommand\CreateRef[2]{%
    \TestedNameDef{#1Ref}##1{#2\ref{##1}}}

This can be used to create your own reference commands on the fly

\CreateRef{Fig}{Figure~}

Which will create a command \FigRef{lab} -> Figure~\ref{lab}

share|improve this answer
    
I am not yet as well versed with LaTeX as I need to be and am wondering if there is an advantage to using this over Martin's suggestion, which I can actually understand. –  Peter Grill Jun 2 '11 at 5:00
    
@Peter Grill: Conceptualy, Martin's version is related to \providecommand which means that if the command allready exists the original command is used and the one you provided is ignored. My version is related to \newcommand which means if the command already exists TeX stops and throws an error. You then have to choose a new command name. –  Danie Els Jun 2 '11 at 7:37
    
Thanks. As I get more proficient at LaTeX, I have a feeling I'll migrate over to your solution over time. –  Peter Grill Jun 2 '11 at 8:23

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.