# LaTeX3 conditional with grouping fails to compile

I am trying to write a LaTeX3 conditional using \prg_new_conditional:Nnn from the expl3 package. Since the code in the conditional needs to make assignments to some variables, I would like to use grouping in order to do those assgnments locally. However, the following MWE fails to compile:

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\prg_new_conditional:Nnn \foo: { p }
{
\group_begin:
% Do some stuff.
\group_end:
\prg_return_true:
}
\bool_if:nTF { \foo_p: } { true } { false }
\ExplSyntaxOff
\end{document}


The following errors show up several times:

! Missing number, treated as zero.
\group_begin:
l.11 \bool_if:nTF { \foo_p: }
{ true } { false }
A number should have been here; I inserted 0'.
(If you can't figure out why I needed to see a number,
look up weird error' in the index to The TeXbook.)
! Missing \endcsname inserted.
\group_begin:
l.11 \bool_if:nTF { \foo_p: }
{ true } { false }
The control sequence marked <to be read again> should
not appear between \csname and \endcsname.


When I remove \group_begin: and \group_end:, then everything works as expected. So what is going on here? Why can't I use grouping within the definition of \foo_p:?

• Welcome to TeX.SX! A conditional allowing the predicate form must be fully expandable, but \group_begin: isn't. So, no grouping nor assignments. – egreg May 11 '15 at 7:56
• Such statements appear from time to time in the LaTeX3 interface manual, but I never really understood them. Could you elaborate on this a bit further? – ranguwud May 11 '15 at 8:03
• consider something simpler like a simple primitive count assignment. you can go \def\z{123}\count0=\z as \z expands to 123, but you can not go \def\z{{123}}\count0=\z as then \z expands to {123} which isn't a legal number. Same here the \group_begin: stops the argument being interpreted as true or false. – David Carlisle May 11 '15 at 8:23
• If the code is not expandable, the correct would be \prg_new_protected_conditional:Nnn… which explicitly bans the p branch. So, it's not possible. – Manuel May 11 '15 at 12:20

In order to work, a predicate such as \foo_p: that you'd like to use must expand to either \prg_return_true: or \prg_return_false:, leaving nothing else in the input stream after macro expansion.

In the code for the replacement text you are free to use any of the conditionals marked with a (filled) * in the interface3 manual and, in their true or false parts, only functions marked in the same way.

With your definition, \group_begin: will remain unless hidden in code that's always skipped, but in that case it would be useless. No assignment can be performed in the code for a conditional that's supposed to have a predicate form, because assignments are not performed during macro expansion.

So, for example, it's impossible to have a predicate form for a conditional that's supposed to decide whether some tokens will end up with typeset text, say by doing \hbox_set:Nn \l_tmpa_box {<tokens>} and then measuring the box.

Depending on what you want to do, there could be expandable ways.

• Thanks for your thorough answer, egreg! So could you say that a group by design is never "empty", even though its contents leave nothing in the input stream? What I am actually trying to achieve is to check whether a token list is composed of certain characters. My current approach is to assign an input parameter to a token list and performe some actions on this variable. All this would preferrably be done locally. Finally I can run a test on the token list variable to output \prg_return_true: or \prg_return_false:. Am I missing some obvious way how to turn this into expandable code? – ranguwud May 11 '15 at 11:59
• @ranguwud No code containing assignments can be made fully expandable. – egreg May 11 '15 at 12:14
• @egreg I know an edge case, but a piece of LuaTeX-only code could do the assignment at the Lua end and remain expandable. – Joseph Wright May 11 '15 at 14:16
• @ranguwud Series of expandble loops, outer one over the input data, inner one over the allowed chars? – Joseph Wright May 11 '15 at 14:17
• @JosephWright This sounds indeed like a promising approach, but how would I remember if I found a "forbidden" character without setting a bool or something similar? As far as I know, \tl_break: cannot be used to terminate two loops. At least not without using groups. :) – ranguwud May 11 '15 at 15:36