11

I discovered recently \@testopt in this question. I tried to understand the goal with the use of this macro, but in my research I discovered other macros like \@protected@testopt and even new packages like exp-testopt. Actually, I develop only with TeX and LaTeX2e, what do you think of this macro?

What is the most reliable method?

1
  • +1, plus, to be honest, I wonder how to use it to define macros with larger number of obligatory {} arguments (I mean is there any difference in usage?)
    – yo'
    Jun 13, 2012 at 7:20

3 Answers 3

11

There are at least a couple of reasons for the the existence of \@testopt.

If you look at the definition of \@testopt, you will see that it is

> \@testopt=\long macro:
#1#2->\kernel@ifnextchar [{#1}{#1[{#2}]}.

This uses \kernel@ifnextchar rather than \@ifnextchar: the later may get redefined by for example the AMS math material, whereas \kernel@ifnextchar is 'frozen' and should never be redefined. Thus \@testopt will always show the same behaviour, searching for [ and skipping spaces. In that sense, there is a reliability gain from using it rather than coding the test yourself.

The other factor here is token usage. \@testopt is one token, whereas doing the test manually requires four tokens (\kernel@ifnextchar, [ and the [...] pair). When LaTeX2e was released, that reduction in token usage was important: there are lots of places in the kernel where such alterations were made to keep the size down. Of course, today that is not at all significant.

12

There's no advantage in using directly \@testopt, in my opinion. The question you refer to has

\def\collecttikzpicture{\@testopt\@collecttikzpicture{}}
\def\@collecttikzpicture[#1]{%
  \global\setbox\tempbox=\hbox\bgroup\begin{tikzpicture}[#1]%
}

that is functionally equivalent to

\newcommand\collecttikzpicture[1][]{%
  \global\setbox\tempbox=\hbox\bgroup\begin{tikzpicture}[#1]%
}

and has the advantage of being robust, that is it eventually expands to itself when used in moving arguments, which is not the case for the former definition.

With the latter definition, the expansion of \collecttikzpicture will be

\@protected@testopt \collecttikzpicture \\collecttikzpicture {}

where the third token is a peculiar control sequence with a backslash in its name, which has the same office as \@collecttikzpicture in the previous definition. So you don't even have to worry about defining an auxiliary control sequence for the real action, because \newcommand will take care of that automatically. When \@protected@testopt is expanded, it uses \@testopt, so \kernel@ifnextchar (and not \@ifnextchar).


Defining a command having mandatory arguments with \@testopt is really easy:

\def\foo{\@testopt\@foo{DEFAULT}}
\def\@foo[#1]#2#3{Something with #1, #2, #3}

Let's see why following the expansion of \foo{X}{Y} and \foo[A]{X}{Y}. Here's the first one:

\foo{X}{Y}
\@testopt\@foo{DEFAULT}{X}{Y}
\kernel@ifnextchar [{\@foo}{\@foo[{DEFAULT}]}{X}{Y}
\@foo[{DEFAULT}]{X}{Y}
Something with DEFAULT, X, Y

Here's the second:

\foo[A]{X}{Y}
\@testopt\@foo{DEFAULT}[A]{X}{Y}
\kernel@ifnextchar [{\@foo}{\@foo[{DEFAULT}]}[A]{X}{Y}
\@foo[A]{X}{Y}
Something with A, X, Y

But, of course,

\newcommand{\foo}[3][1]{Something with #1, #2 and #3}

is easier and robust.

11

It's probably also relevant here that \@testopt came from LaTeX2.09 so originally all LaTeX commands using optional arguments were explicitly defined using it.

The syntactic extension to \newcommand and friends to allow the declaration of commands using optional arguments is a more recent (latex2e) addition. They use \@testopt internally, but as @Joseph says, using the higher level forms saves some tokens and adds robustness.

1
  • 3
    Where "more recent" means it's from 1994 instead of 1986. :-) Jun 13, 2012 at 15:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .