16

What's the difference between \ignorespaces and \ignorespacesafterend and should I ever use the former rather than the later?

I've seen examples that place \ignorespacesafterend at the end of an environment definition while \ignorespaces goes at the end of the command opening the environment but I don't understand what that means in terms of different behavior or why a different command would be needed. Doesn't \newenvironment just create one macro for the start and another macro for the end of the environment? So why wouldn't the same command work in both places?

I'm looking to understand what they do differently and whether I could just use \ignorespacesafterend everywhere I could use \ignorespaces.

2
  • I should have been clearer…I know that is advised but I don't understand how that makes them different. I mean isn't the environment start and environment end both just translated into macros Mar 3, 2021 at 9:59
  • I've edited question to explain that I've seen that advice but I don't understand why that makes the two commands different or what that means in terms of their behavior. Thanks though! Mar 3, 2021 at 10:07

2 Answers 2

17

The purpose of \ignorespacesafterend is to gobble spaces after \end{...}, which you cannot achieve by using \ignorespaces in the end code of an environment.

Let us try this

\documentclass{article}

\newenvironment{foo}{%
   \unskip\space(\ignorespaces
  }{%
    \unskip)\space\ignorespaces
}

\begin{document}

Before
\begin{foo}
bla
\end{foo}
after

\end{document}

The idea of the whole \unskip/\ignorespace/\space is that the content of the environment is put in parentheses with one space before and one space after. However, the result of the code is

enter image description here

with two spaces after. Why is this happening? The code \end{foo} expands to (simplified)

\endfoo
\@checkend{foo}
% [ ... other stuff ... ]
\if@ignore\@ignorefalse\ignorespaces\fi

where \endfoo expands to the third argument of \newenvironment. With the current definition of \endfoo this results in

... \ignorespaces\@checkend{foo} ...

and \ignorespaces never sees any space, so it does nothing.

The LaTeX kernel provides the way out of this by introducing the line

\if@ignore\@ignorefalse\ignorespaces\fi

In fact, the definition of \ignorespacesafterend is very simply

\let\ignorespacesafterend\@ignoretrue

and it therefore executes the \ignorespaces in the \if@ignore resulting from the expansion of \end{foo}.

Thus, if you define

\newenvironment{foo}{%
   \unskip\space(\ignorespaces
  }{%
    \unskip)\space\ignorespacesafterend
}

you'll get the expected output

enter image description here

(Note that while it is customary to put \ignorespacesafterend as last in the end code of an environment, this is not really necessary.)

5
  • Thanks so much! But is it the \endgroup that prevents it from having an effect the newlines without a following%? Or do even macros that don't expand to include any non-spaces stop \ignorespaces? Mar 3, 2021 at 10:21
  • 1
    @PeterGerdes The \@doendpe is doing something different; I've removed in from the answer. \ignorespaces does nothing until it meets a token which is not a space. But the first token after \ignorespaces is \@checkend, which is no space, so nothing happens.
    – campa
    Mar 3, 2021 at 10:26
  • ok, I think I see now. Thanks! (and, of course, the \fi is gone by the time \ignorespaces executes) Mar 3, 2021 at 10:27
  • Sorry, one more question. Will \ignorespacesafterend work with xparse define environments as well? Mar 3, 2021 at 11:51
  • 2
    @PeterGerdes You mean with \NewDocumentEnvironment & Co.? I don't see any reason why it shouldn't work. xparse changes the ways the start and end code are defined but not the behaviour of \begin and \end.
    – campa
    Mar 3, 2021 at 11:55
3

The \ignorespaces is TeX primitive command which ignores all following space tokens after expansion and stops such ignoring when first no-expandable no-space token is scanned. It should be used at the end of macros if we suppose that a user uses such macro followed by unwanted space token(s) which create a space-glue in horizontal mode.

LaTeX puts its environments to the group. The LaTeX \newenwironment macro allows you to set the token string processed at the end of the environment but before end-group token. And the end-group token is unexpandable, So: if you use \ignorespaces here then it has no effect to the unwanted space tokens after end of the environment. I guess that \ignorespacesafterend is a macro implemented similar as \aftergroup\ignorespaces (but I didn't look at the LaTeX macros exactly).

4
  • Thanks for that clarification about it operating until it finds a unexpandable token that's not a space (is it really space or is it testing the cat code?). As for the \ignorespacesafterend @campa nicely explained above that latex just built into the end environment code an if statement that activates the trailing ignorespaces. Mar 3, 2021 at 23:50
  • @PeterGerdes TeXbook, Chapter 24: Summary of Vertical Mode says: ⟨optional spaces⟩→⟨empty⟩|⟨space token⟩⟨optional spaces⟩ [...] The quantity ⟨space token⟩, which was used in the syntax of ⟨optional spaces⟩ above, stands for an explicit or implicit space. In other words, it denotes either a character token of category 10, or a control sequence or active character whose current meaning has been made equal to such a token by \let or \futurelet. [...] \ignorespaces ⟨optional spaces⟩. TeX reads (and expands) tokens, doing nothing until reaching one that is not a ⟨space token⟩. Mar 6, 2021 at 18:43
  • @PeterGerdes Be aware that any character of category code 10 (space) will be tokenized as explicit character token with character-code 32 and catcode 10. (32 is the number of the code-point of the space-character in TeX's internal character encoding scheme which is ASCII with traditional TeX and is unicode with XeTeX/LuaTeX.) So-called "funny spaces", i.e., explicit character tokens with catcode 10 and character-code other than 32 can be created by applying \uppercase/\lowercase to explicit space tokens after assigning the desired \uccode-/\lccode-value to character 32. Mar 6, 2021 at 18:52
  • @PeterGerdes So it is as wipet (and you) said: \ignorespaces ignores all following ⟨space token⟩s; ⟨space token⟩ denoting whatsoever token of category code 10(space). (Explicit character token, implicit character token, explicit funny space, implicit funny space.) Mar 6, 2021 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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