The difference is in the time at which the ‘right hand side’ is evaluated.
Thus \let\foo\bar
defines \foo
to have the value that \bar
had at the point of definition. On the other hand, \def\foo{\bar}
in effect defines \foo
to have the value that \bar
has at the point of use.
Consider:
\def\bar{hello}
\let\fooi\bar
\def\fooii{\bar}
\fooi +\fooii
\def\bar{goodbye}
\fooi +\fooii
This produces
hello+hello
hello+goodbye
This is a simple process.
However it's also a subtle one, so it might be worth highlighting a few key points:
When TeX encounters control sequences such as \fooi
, it evaluates them; if these are macros (that is, they have been defined by \def
, or \let
equal to something which was defined by \def
), then the result is that they will expand to other tokens, which TeX will then examine in turn, and so on, recursively, until what's left is either ‘primitive’ control sequences or letters (I'm simplifying a little bit).
\fooi
expands directly to the characters hello
(because \bar
initially did, and \fooi
was defined to have the same value).
\fooii
, in contrast, expands to \bar
, which is then immediately reexamined and reexpanded. In the first case, \bar
expands to hello
and in the second case to goodbye
. The definition of \fooii
hasn't changed, but \bar
has been redefined in between.
Getting a clear idea of the process of this recursive expansion is very helpful when learning how to develop and debug TeX macros.
A bit of background first. When Knuth wrote TeX, he realised that most macros would not need to absorb more than one paragraph as an argument. As a result, a good way to test for errors such as a missing }
is to forbid macros to accept paragraph tokens (either those generated by blank lines or explicit \par
tokens). So he created \def
for definitions which cannot take a paragraph token, and the \long
prefix to allow them to:
\def\examplea#1{% #1 cannot contain \par
}
\long\def\exampleb#1{% #1 can contain \par
}
When LaTeX was written, Lamport created \newcommand
as a wrapper around \def
with various bits of error checking. He found that paragraph tokens can pop up in odd places. So he decided that \newcommand
would be 'long'. When the LaTeX team took over for LaTeX2e, they decided that you would need to add the modifier *
to prevent this:
\newcommand{\examplea}[1]{% #1 can contain \par
}
\newcommand*{\exampleb}[1]{% #1 cannot contain \par
}
Most of the time, \newcommand*
is the best choice as you want the error-checking that it provides. That is why examples given by experienced LaTeX users normally use this form, rather than just \newcommand
.
The same behaviour is seen with \newenvironment
:
\newenvironment{examplea}[1]{% #1 can contain \par
}{}
\newenvironment*{exampleb}[1]{% #1 cannot contain \par
}{}
This works by defining \examplea
and \endexamplea
more-or-less using \newcommand
, and \exampleb
and \endexampleb
more-or-less using \newcommand*
. As a result, the 'end' macros have the same 'long' status as the 'begin' ones, even though they never take arguments. (Note that this does not affect what can go into the body of the environment, only the arguments at the start.) Environments are covered in more detail in What is the difference between \newenvironment and \newenvironment*?.
For LaTeX3, we've decided to take a somewhat hybrid approach. If you use xparse
for defining document commands, they are only 'long' if you ask for it:
\NewDocumentCommand\examplea{m}{% #1 cannot contain \par
}
\NewDocumentCommand\examplab{+m}{% #1 can contain \par
}
(We've decided on +
to represent a long argument). On the other hand, for internal use it is normally best to accept paragraph tokens, and to leave the filtering to the user interface level.
Best Answer
\def
is a TeX primitive,\newcommand
is a LaTeX overlay on top of\def
. The most obvious benefits of\newcommand
over\def
are:\newcommand
checks whether or not the command already exists\newcommand
allows you to define an optional argumentIn general, anything that
\newcommand
does can be done by\def
, but it usually involves a little trickery and unless you want something that\newcommand
can't do, there's no point in reinventing the wheel.In answer to your particular points:
\def
has to know exactly what its options are, and how they will be presented to it. However, a TeX command can be a bit clever and examine things other than its arguments. The way that optional commands are handled is to look at the next character in the stream and if it is[
then one version of the command is called, whereas if it isn't then another is called. So if you're prepared to do some hackery, then optional arguments are possible via\def
, but it isn't half so easy as\newcommand
.\def
doesn't check for a command already being defined, you can redefine stuff simply using\def
again. To get the checking, you need to use the\@ifundefined
command (note the ampersat (@
) sign!).There's probably lots more to be said on the differences, but that's enough from me.