3

The conditional structure of the macro of the MWE allow print two text strings as "true" and "false" alternatively. So you can print something like "false true false true false true" calling six times the same macro without any option.

But if the printed strings made a environment (that is: \begin{...} and \end{...}) this works only the first time, as in the MWE. With a second \tin .... \tin then pdflatex said that \begin{document} is ended by \end{...}.

\documentclass{article}
\newif\iftiny
\def\tin{\iftiny
\tinyfalse \end{tiny}
\else
\tinytrue \begin{tiny} 
\fi}
\begin{document}
 normal size 
\tin tiny size \tin normal size
% uncomment the next line to see the problem 
% \tin tiny size \tin normal size   
\end{document}
  • What happen with the second \begin{tiny} when the macro is called four times?
  • Why is wrong this code?
  • How fix this problem?
  • Beware that \begin starts a group and \end closes it, so assignments such as \tinyfalse made inside them disappear. – egreg Jul 4 '13 at 22:04
  • @egreg. That is. Then moving \tinyfalse before of \begin and \tinytrue after \begin solved the problem! Please, make an answer to accept it. – Fran Jul 4 '13 at 22:25
  • A condition like iftiny can be defined without \newif. Something like \let\iftiny\iffalse and your definition of \tinytrue can be \def\tinytrue{\global\let\iftiny\iftrue} – Marco Daniel Jul 5 '13 at 9:58
5

Every \begin command issues \begingroup, which corresponds to a command \endgroup issued by \end.

Assignments such as \tinyfalse or \tinytrue are local to the group in which they appear. You can do \global\tinytrue and \global\tinyfalse if you want that the assignment transcends the group it's performed in.

Let's see what happens with your code.

\tin tiny size \tin normal size

becomes

\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi tiny size \tin normal size

Since a conditional is initially false, the true branch is skipped and

\tinytrue\begin{tiny}\fi tiny size \tin normal size

remains. The assignment is performed, the tiny environment is started with its \begingroup and tiny size is printed (\fi disappears because of its working). Now remember we are in a group; when \tin is found it's expanded and we're confronted with

\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi normal size

Now \iftiny follows the true branch and the resulting token list is

\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi normal size

The assignment is performed, then \end{tiny} is executed with its \endgroup that undoes the assignment made by \tinyfalse and so \iftiny remains true. The \else...\fi part disappears and normal size is printed.

If now you execute again the input

\tin tiny size \tin normal size

you're starting with \iftiny returning true! So

\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi tiny size \tin normal size

follows the true branch, giving

\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi tiny size \tin normal size

and there's an \end{tiny} that doesn't belong there.

  • In this case the offending command is only \tinyfalse, therefore \global\tinyfalse or move it after \end{tiny} was enough. Grazie mile. – Fran Jul 4 '13 at 22:48
  • @Fran I've added an analysis of what happens – egreg Jul 4 '13 at 22:50
3

Besides the explanation of egreg here another approach defining your conditional:

\documentclass{article}
\let\iftiny\iffalse
\def\tinytrue{\global\let\iftiny\iftrue}
\def\tinyfalse{\global\let\iftiny\iffalse}
\def\tin{\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi}
\begin{document}
 normal size 
\tin tiny size \tin normal size
 uncomment the next line to see the problem 
 \tin tiny size \tin normal size   
\end{document}

The op wrote that this solution isn't such intuitive. So I think a small explanation about \newif is necessary.

The command \newif is defined in the LaTeX-kernel in the following

\def\newif#1{%
  \count@\escapechar \escapechar\m@ne
    \let#1\iffalse
    \@if#1\iftrue
    \@if#1\iffalse
  \escapechar\count@}

This really clever definition does three things. First it defines a new command which is equal to \iffalse by \let#1\iffalse. This is equal to the example above.

The next two lines are calling the macro \@if with the following definition:

\def\@if#1#2{%
  \expandafter\def\csname\expandafter\@gobbletwo\string#1%
                    \expandafter\@gobbletwo\string#2\endcsname
                       {\let#1#2}}

In short it gobbles the first two tokens of the input string one and two e.g. from \iftiny you get tiny and from \iffalse you get false. In the next step you get the definition: \def\tinyfalse{\let\iftiny\iffalse}. The solution above does nearly the same but it add a \global assignment.

  • +1 Is less intuitive (for me) how it works, but it works. :-) – Fran Jul 5 '13 at 11:06
  • @Fran: I added a small explanation. I hope it's now more intuitive ;-) – Marco Daniel Jul 5 '13 at 12:09
  • Intuitive could be a nipple for a baby, a \color{red} command for me, the Matrix code for Neo, or a sequence of TeX primitives for you, but I am not still at that level. Please do not misunderstand this comment as some disagreement because the answer is not for dummies. I really appreciate your explanation.:-) – Fran Jul 5 '13 at 18:46
  • @Fran: I understand your comment ;-) – Marco Daniel Jul 5 '13 at 18:48

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.