48

The LaTeX kernel uses these two all over the place. For example, apparently the correct way of defining something like \ifeq{\macro 1}{\macro 2}{true}{false} is (note Martin's response: each case should begin with \expandafter)

\def\ifeq#1#2{%
 \ifx#1#2\relax
  \@firstoftwo
 \else
  \@secondoftwo
 \fi
}

rather than

\def\ifeq#1#2#3#4{%
 \ifx#1#2\relax
  #3%
 \else
  #4%
 \fi
}

However, they are equivalent as far as I can see:

\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}

There is even a \@firstofone! It does this:

\long\def\@firstofone#1{#1}

Clearly there is no functional difference in using these macros than simply declaring one or two more arguments. I can see two possible minor differences off the top of my head:

  1. \@firstoftwo is a control sequence and, as such, gobbles subsequent spaces. This means we don't have to put a % after it if it ends a line. Of course, we have to put % in lots of other places, and TeX doesn't actually store the % in the macro's expansion text, so this is truly minor.

  2. Macros defined with \@firstoftwo take two arguments fewer than those defined normally. Thus, TeX doesn't have to store the information that my \ifeq macro takes those two arguments; it just refers to the storage already used by \@firstoftwo and \@secondoftwo. I guess this cuts down a little on memory usage.

    Neither of these explains the purpose of \@firstofone, since it could only possibly be useful when placed as the very last token of a macro, and even there it doesn't actually change the subsequent input, so it seems like it could just be eliminated. Is there some reason one would want to "set off" the next token like that? There is one more possibility:

  3. These are \long\def'd rather than just \def'd. Thus, they can take multiple-paragraph arguments even if the macro using them is not \long. I guess this allows you to make the last one or two arguments of a macro \long when the others are not, but really, why not just use \long when you really mean it?

Are there other advantages that I've missed? Do they have minor effects on speed or tricky interactions with expansion or execution that I'm missing? What is the real reason for this bit of obfuscation?

5 Answers 5

37

You are missing two very important \expandafters. The normally used, "correct" code is:

\def\ifeq#1#2{%
 \ifx#1#2\relax
   \expandafter\@firstoftwo
 \else
   \expandafter\@secondoftwo
 \fi
}

The difference to a macro which uses #3 and #4 is that the if-statement is fully processed before the first or second of the next two arguments is processed. This allows that code to e.g. look ahead using \@ifnextchar. Otherwise the \else or \fi would still be after the #3 or #4, respectively, which would break such macros. Such techniques to close the if-statement first are also important for recursive macro to not accumulate a lot of cascaded if-statements.

The macros are defined \long simply to allow for the most flexible use.


The \@firstofone macro seems to be a no-op, but actually removes the braces around the argument. It is often used in an if-statement where \@gobble is used in the other clause (both again using \expandafter).

\def\foo#1#2{%
 \ifx#1#2%
   \expandafter\@firstofone
 \else
   \expandafter\@gobble
 \fi
}

\foo{\bar}{\baz}{Argument code}
1
  • 1
    I came here to learn about the use of \@fristoftwo in ifs and find the part about the \fi/\else removal(?) interesting but can't quite understand how it works. Would you mind elaborating that a little bit further so that I can understand it? (p.s. please notify me per comment if you edit this)
    – ted
    Aug 3, 2013 at 8:46
19

The correct syntax for \ifeq should be

\def\ifeq#1#2{%
 \ifx#1#2\relax
  \expandafter\@firstoftwo
 \else
  \expandafter\@secondoftwo
 \fi
}

Martin has explained well the reasons for preferring this approach than the "four argument" one.

What about \@firstofone? Well it may be used for stripping a pair of braces around an argument, for example. Another use is to make something a noop; in the LaTeX kernel there's

\let\AtBeginDocument\@firstofone

which is executed as part of the \document macro; so if something added with \AtBeginDocument calls by itself \AtBeginDocument, the argument to this command will be executed (and not in braces). The example might be stupid, but in the real world it can happen:

\AtBeginDocument{\AtBeginDocument{do something}}

If the kernel said \let\AtBeginDocument\relax, the result would be to feed the tokens

{do something}

and assignments in the code would be lost at group end. With the correct definition, LaTeX would be presented with \@firstofone{do something} that's expanded into do something, without braces.

Of course nobody writes code like that; but a package might say

\AtBeginDocument{\macro}

and another package might have redefined \macro with a call of \AtBeginDocument.

Another example: we want a macro that does nothing to its argument when called in normal form, but prints it in italics if called in the *-form.

\newcommand{\macro}{\@ifstar{\textit}{\@firstofone}}

Then \macro{x} will print x, while \macro*{x} will print x. One might leave out \@firstofone, but this would not strip the braces around the (apparent) argument to \macro. In this cases it's customary to use \@iden, which is the same as \@firstofone.

There's another case where \@firstofone is very useful, see Bruno Le Floch's answer to "Will two-letter font style commands (\bf, \it, …) ever be resurrected in LaTeX?

2
  • I think you meant Bruno Le Floch's answer,I didn't answer the question you linked to ;-) Jun 21, 2011 at 21:45
  • @Gonzalo: My apologies to Bruno!
    – egreg
    Jun 21, 2011 at 21:54
12

Since some previous answers went over the use of \@firstofone, I will as well. One use is that catcodes of its argument are fixed when \@firstofone is expanded. Hence,

\begingroup
\makeatletter
\catcode`\*=\active
\@firstofone{\endgroup
  \newcommand{*}}{*}

defines the active character * to expand to the "other" character *. Here, \makeatletter is needed because \@firstofone contains an @, and we put it within the group: this way, all the catcodes are reverted when reading \endgroup once \@firstofone has been expanded.

2
  • But after your code is executed, * is no longer active, right? If I type \show * it tells me "the character *". So what does this accomplish?
    – Ryan Reich
    Jun 22, 2011 at 13:58
  • Sorry, that wasn't clear. It is used to give a definition to the active *, typically useful in a package for the sake of making it active later in the document (see an answer on markup which I was reminded of recently). Jun 22, 2011 at 21:39
7

There's a use for \@firstofone in the TikZ code. The macro \tikz@scan@one@point converts the variety of ways of specifying a TikZ coordinate in to something more standardised. That is, it takes things like (1,2) or (a.north) and converts them in to something of the form \pgfpoint{10pt}{20pt}. This is a general use macro so it tries not to presuppose what should be done with this point, thus it takes an argument and that argument is a command, and what is executed is \command{\pgfpoint{10pt}{20pt}}. This makes it very flexible. Now \pgfpoint{10pt}{20pt} sets two lengths: \pgf@x and \pgf@y. If, after the \tikz@scan@one@point you just want those two lengths then you don't want to execute a command on \pgfpoint{10pt}{20pt}, you just want to execute \pgfpoint{10pt}{20pt}. So you can tell \tikz@scan@one@point to use the command \@firstofone. Thus \tikz@scan@one@point\@firstofone returns the x and y values of the point in the lengths \pgf@x and \pgf@y.

4
  • 1
    That's a very specific example for a quite general question, isn't it? Jun 21, 2011 at 15:48
  • @Martin: he just knows that I like TikZ :)
    – Ryan Reich
    Jun 21, 2011 at 16:22
  • 8
    @Martin: Evidently not a mathematician! To answer a question, "Is X necessary?" it suffices to give one example where it is useful. Seriously, your answer covered the general case and I was merely trying to help out with a specific example (and one that I recently used). Jun 21, 2011 at 18:37
  • 1
    Remark: Basically this is the same answer as "what is the identity function useful for?" question in Haskell, this one is for TeX.
    – user202729
    Jan 20, 2023 at 11:08
1

Some other points, I think this is not mentioned in the other question.

(*) There are lots of spurious spaces in this answer, they're only for demonstration purposes; or assume they're in expl3's \ExplSyntaxOn environment.

How TeX conditional work, exactly?

If you don't read the (TeX)book carefully and just skim through the command description to see what they do, you might think that...

\ifx #1#2
    ⟨some code⟩
\else
    ⟨some other code⟩
\fi

... will do exactly the same thing as either ⟨some code⟩ or ⟨some other code⟩ depends on the first 2 tokens are equal.

But, if you think about it -- these conditionals are expandable. How could they be implemented?

A reasonable guess/"mental model" would be

  • \ifx grabs the next tokens until it sees a \fi
  • then it compares the first 2 tokens to see if they're equal
  • then it "returns" either ⟨some code⟩ or ⟨some other code⟩ to be executed.

So in the example above it would expand in 1 step to either ⟨some code⟩ or ⟨some other code⟩. Makes sense, right?

The main problem is, this model is wrong. The reality is...

  • when TeX sees the \ifx, it takes 2 next tokens and compare them.
  • If the compare is true, it "remembers" that "this is inside a true branch. When next \else is seen, gobble until next \fi; or when next \fi is seen, remove it".
  • If the compare is false, it gobbles until an \else or a fi, then (optionally, if \else is seen) remembers that "this is inside a false branch. When next \fi is seen, remove it".

As such, for example if the conditional is true, after 1 step of expansion the result is

    ⟨some code⟩
\else
    ⟨some other code⟩
\fi

and the expansion processor remembers it's in a true branch. See the unbalanced \else remaining in the code.

You can try it yourself, execute \iftrue\show\else\fi\a, it will show \else.

(also discussed in the TeXbook, first paragraph "Conditionals", chapter 20 page 213 / TeX by Topic, chapter 13.7 Evaluation of conditionals / TeX in a nutshell, page 16 (briefly).)

Why? This is unintuitive!

I guess there are a few reasons for this behavior:

  • First, because the tokens are not tokenized in advance, you can use catcode-changing commands (e.g. \verb) inside some branch. (mostly.)
  • You don't need to read the whole 2 branches into memory, they can be read later. That might have been the main reason a few decades ago.

What if the code doesn't look ahead for the next token?

(alternative title: TEX primitive conditional)

There's still a potential problem.

Assume that user-provided #3 or #4 has some TeX primitive conditional, they might be unbalanced:

\ifx #1#2
    \fi
\else
    ⟨some other code⟩
\fi

You can see the problem here. That does not happen when \@firstoftwo/\@secondoftwo approach is used.

Side note, you can't brace-protect this one, TeX conditionals ignore braces in such situations. (thus the famous "brace hack" \iffalse { \fi } and \expandafter { \iffalse } \fi)

Side note, the code can be optimized further.

If you do the following

\def     \change@secondoftwo@to@firstoftwo  \fi \@secondoftwo #1#2 {
                                            \fi               #1
                                        }
\ifx #1#2 \change@secondoftwo@to@firstoftwo \fi \@secondoftwo {#3} {#4}

you only need 3 tokens instead of the usual 5 in \expandafter \@firstoftwo \else \@secondoftwo \fi. (method briefly mentioned in https://tex.stackexchange.com/a/517265/250119.)

expl3 code does something similar with the macro \__prg_TF_true:w etc.

Side note, you need to insert the \fi back, because as mentioned above the expansion processor remembers that "we're in the true branch" and will print e.g. "\end occurred when \ifx was incomplete" error message in the end. (for some reason it's not really an error message, just a warning printed to the terminal.)

3
  • Yes, I did read your warning, "(*) There are lots of spurious spaces in this answer, ...", but depending on how the arguments are fed into the expansion, which isn't really clear, trying to unravel the rest of the answer makes my head hurt. If the first argument is a single character, the answer from \ifx #1 #2 will almost always be false, since #1 will be compared with a space; only if the first argument is specified to be input within braces is it possible to enter a single space. If unbraced, and aardvark is the first entry, that will be true. Either way, #2 will never be used. Jul 9, 2022 at 22:00
  • @barbarabeeton The "#1 is a single token" part comes from the OP, but otherwise I fix the harmful ones (or just assume it's \ExplSyntaxOn environment...).
    – user202729
    Jul 10, 2022 at 17:32
  • Better now, thanks. I'm not skilled enough in expl3 to know whether \ifx will work in the \ExplSyntaxOn environment. I was assuming not, but I really don't know. (Have to do some studying, I guess.) Jul 10, 2022 at 17:55

You must log in to answer this question.

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