Consider the following simple code:

\def\@ifundefined#1#2#3{% \cs{UNDEF}{DEF}
    \def\reserved@a{#2}%
    \def\reserved@b{#3}%
    \ifdefined#1
        \let\reserved@c\reserved@b
    \else
        \let\reserved@c\reserved@a
    \fi
    \reserved@c}

The same result can be achieved with:

\toksdef\tokszero0
\toksdef\tokstwo2
\def\@@ifundefined#1#2#3{% \cs{UNDEF}{DEF}
    \tokszero{#2}%
    \tokstwo{#3}%
    \ifdefined#1
        \let\reserved@c\tokstwo
    \else
        \let\reserved@c\tokszero
    \fi
    \the\reserved@c}

Is there any significant difference? (Aside from \toksdef.) Which one is preferable?

(I can think of one difference. If either UNDEF or DEF contains #, then the macro register version would fail.)

  • In eTeX you can imitate toks registers with \protected\edef\reserved{\unexpanded{#1}} if I remember correctly. \toks is ”faster”, but probably the difference in your use doesn't really matter. In LaTeX3 the macro version is used for almost everything the user does. – Manuel Oct 15 at 6:25
  • 1
    You've marked this as tex-core but the use of \reserved@a suggests LaTeX ... – Joseph Wright Oct 15 at 6:28
  • 1
    It is usually better to avoid assignment at all (the latex definition of \@ifundefined doesn't use assignment) – David Carlisle Oct 15 at 9:19
up vote 6 down vote accepted

Not a very complete benchmark, but it should give the idea. Consider the following testundef.tex file

\catcode`@=11

\def\a@ifundefined#1#2#3{% \cs{UNDEF}{DEF}
  \def\reserved@a{#2}%
  \def\reserved@b{#3}%
  \ifdefined#1%
    \let\reserved@c\reserved@b
  \else
    \let\reserved@c\reserved@a
  \fi
  \reserved@c
}
\toksdef\tokszero0
\toksdef\tokstwo2
\def\b@ifundefined#1#2#3{% \cs{UNDEF}{DEF}
  \tokszero{#2}%
  \tokstwo{#3}%
  \ifdefined#1%
    \let\reserved@c\tokstwo
  \else
    \let\reserved@c\tokszero
  \fi
  \the\reserved@c
}
\def\@firstoftwo#1#2{#1}
\def\@secondoftwo#1#2{#2}
\def\c@ifundefined#1{% \cs{UNDEF}{DEF}
  \ifdefined#1%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\expandafter\let\expandafter\ifundefined\csname\test @ifundefined\endcsname

\count255=0
\loop\ifnum\count255<1000000
  \ifundefined\foo{\relax}{\relax}
  \ifundefined\relax{\relax}{\relax}
  \advance\count255 1
\repeat

\bye

I give three possible definitions of \@ifundefined and then test them by a command line switch. Here's the session transcript

> time pdftex "\def\test{a}\input testundef"
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) (preloaded format=pdftex)
 restricted \write18 enabled.
entering extended mode
(./testundef.tex )
No pages of output.
Transcript written on testundef.log.

real    0m1.871s
user    0m1.844s
sys 0m0.018s

> time pdftex "\def\test{b}\input testundef"
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) (preloaded format=pdftex)
 restricted \write18 enabled.
entering extended mode
(./testundef.tex )
No pages of output.
Transcript written on testundef.log.

real    0m2.308s
user    0m2.277s
sys 0m0.021s

> time pdftex "\def\test{c}\input testundef"
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) (preloaded format=pdftex)
 restricted \write18 enabled.
entering extended mode
(./testundef.tex )
No pages of output.
Transcript written on testundef.log.

real    0m1.518s
user    0m1.490s
sys 0m0.017s

It seems that the \toks method is the slowest; the final method, with pure expansion, is faster because there is no storing away and retrieving to do.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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