I normally use the LaTeX \newcommand to define macros. However, when using delimited macros I use \def. Is there a way that I can get LaTeX to trigger an error if the command defined by \def is being re-defined by another package, i.e, if someone tries to re-define the command a LaTeX error message is triggered.

Do you want to check whether a command is already defined (which is what all the answers are about), or do you want to make it impossible for someone else to overwrite your definitions?
–
CaramdirMar 1 '11 at 4:06

Indeed, half of the answers are answering one of these questions and half the other.
–
Matthew LeingangMar 1 '11 at 13:39

5 Answers
5

No, \def is a TeX primitive and is destructive. And this is one reason LaTeX has \newcommand. If you and other package authors use \newcommand, then you will be warned against redefining each other's code. But even then, there is \renewcommand to get around that problem if you know what you're doing.

I'm no expert of LaTeX internals, but as far as I can understand, it does not keep track which commands are already defined. Your example would fail to compile even without the first \newcommand.
–
CaramdirMar 1 '11 at 4:09

@Caramdir Why you say the code will not compile? As shown it correctly triggers an error, when you attempt to redefine it for the third time.
–
Yiannis LazaridesMar 1 '11 at 4:16

2

@Caramdir true, but if you add it, it will also let you know if it was defined earlier (similar to your answer).
–
Yiannis LazaridesMar 1 '11 at 4:31

1

@Martin: All I wanted to point out, that the sentence “using \newcommand [...] you ensure that LaTeX knows that a command with such a name has been defined” is misleading.
–
CaramdirMar 1 '11 at 16:29

For what it's worth, I think that Yiannis' answer (using \newcommand before \def) is the best way to do it, or at least the simplest.

e-TeX provides two new primitives to check if a control sequence is defined.

\ifdefined\cs tests if \cs is a defined control sequence.

\ifcsname cs\endcsname tests if \cs is a defined control sequence.

The etoolbox package contains more LaTeX-friendly wrappers.

\ifdef{\cs}{true}{false} expands to true if \cs is defined, false otherwise.

\ifcsdef{cs}{true}{false} is similar but for control sequence names.

\ifundef{\cs}{true}{false} is similar to the negation of \ifdef except that control sequences that have been \let to \relax are considered undefined.

\ifcsundef{cs}{true}{false} is similar but for control sequence names.

etoolbox also contains other useful tests, for example if a control sequence is a macro.

Having \ifundef and \ifcsundef check if a command is \relax may seem odd at first. However, LaTeX's \@ifundefined compares \csname cs\endcsname to \relax. The reason for this is that when TeX constructs a control sequence via \csname ...\endcsname that it has not seen before, it gives it the value of \relax. This has the downside that there's no way to differentiate between the name of a control sequence that is undefined and one that has been \let to \relax. \ifcsundef was designed to be a drop-in replacement for the LaTeX kernel's \@ifundefined.

Edit:
I just read Caramdir's comment. There's no good way to prevent another package from redefining a command you define. One possible way around this is to use \AtBeginDocument{\def\cs{...}} to define a macro later than most other macros, but this is not foolproof. Another package can do the same thing and the user can redefine any macro at any time.

+1. There are further examples of why the e-TeX way of doing it is good at this TeX FAQ. In particular avoiding littering TeX's memory space with lots of unnecessary \relaxes could be a good thing
–
kahenMar 1 '11 at 10:45

@TH Your first two statements (about \ifdefined and \ifcsname) aren't precise. \ifdefined a returns true but a isn't a control sequence.
–
Ahmed MusaFeb 7 '12 at 20:39

@Ahmed: You're correct that \ifdefined actually tests if the following token is defined (although I'm not sure what its utility is other than testing for control sequences). What was imprecise about the \ifcsname statement? The documentation says, "True if the control sequence \csname...\endcsname would be defined; creates no new hash table entry."
–
TH.Feb 9 '12 at 22:34

It is technically impossible to protect a macro name (command sequence) from future redefinitions or trigger an error when it is redefined. TeX doesn't even protect its internal command and allows you to redefine them as well. This is by design.

You can however check at certain points (like at-begin-document) if your definition is still active and trigger an error otherwise:

Here is a generalization of Martin Scharrer's scheme. We introduce two commands \cmddef and \robustcmddef for defining simple and robust commands that can be tested anywhere for consistency/preservation. This is taken from ltxtools-base package.