# Is there a right way to do combined conditionals in LaTeX3?

I have some LaTeX3 code and I want to add a new feature. This will involve choosing between various actions at a particular point. There are two choices to be made, and these choices are independent. The times when I read in the choice and the time when the choice is acted upon are distinct, so I need to store the choice for a bit before reading it back. As there is one choice for each term in a list, I need to store the choices in a similar list. I can think of a variety of ways of doing this and am wondering if there is a current proper way (couldn't find it in texdoc interface3) or, if not, a particular way that is better than the others.

Here are some ideas:

1. This is how I would do it in a language like lua: store an integer or string in the range 0-3 and test the bits. This is, though, a bit messy with integers (if i%2 == 0 then is simple enough but the second bit is more like if (i/2)%2 < 1 then) and easier with strings if s:sub(1,1) == 0 then).
2. Define two new booleans and store the requisite "setting" macros. So in a token list, I store the tokens \bool_set_true:N \l_bool_a \bool_set_false:N \l_bool_b and then execute it before doing \bool_if:NTF to figure out the actions to take.

Here's what I might do in a LaTeX2 scenario in a one-shot version:

\documentclass{article}

\newif\ifchoicea
\newif\ifchoiceb

\def\saveifs{%
\edef\restoreifs{\expandafter\noexpand\csname choicea\ifchoicea
true\else false\fi\endcsname\expandafter\noexpand\csname
choiceb\ifchoiceb true\else false\fi\endcsname}
}

\def\stateofifs{%
Choice A is \ifchoicea true\else false\fi,
choice B is \ifchoiceb true\else false\fi.
}
\begin{document}

\stateofifs

\choiceatrue
\saveifs

\stateofifs

\emph{You wait.
Time passes}

\choicebtrue
\choiceafalse

\stateofifs

\restoreifs

\stateofifs
\end{document}


This produces:

Choice A is false, choice B is false.
Choice A is true, choice B is false.
You wait. Time passes
Choice A is false, choice B is true.
Choice A is true, choice B is false.


In my real use case, I'll store the "states" in an array. So in pseudo-code it might be something like:

while (getting_data) do
process_data
convert_choice_to_storable_form
push(choice_array,storeable_form)
end

do
something_complicated
end

while (rendering_data) do
pop(choice_array,storeable_form)
convert_storable_form_to_choices
foreach choice do
if choice then
do_something_stupid
else
do_something_clever
fi
end
end

-
Questions: In the real use case, what's the setting interface? Is the key here performance or clarity? Do you need a save/restore stack, or is it a simple one-level save? –  Joseph Wright Sep 28 '12 at 7:02
One level save. The top-level interface is via keys (it's for the hobby package): the user will use a pgf key of the form blank=true (or some alias to that). I now have it that that constructs an l3key (also blank=true, the second layer is needed to allow for aliases). All of these keys are read before the processing starts so they need to be stored in an array. After the heavy work is done, they need to be read back to determine the choices to be made. There's no nesting involved: the processing is a closed box and can't be interrupted. –  Loop Space Sep 28 '12 at 8:50
Why can't you just save the key list in a token list and \keys_set:nV when needed? For aliases, that's what .meta:n is intended for. –  Joseph Wright Sep 28 '12 at 8:56
Maybe I can. But I need to read and act on some keys before the machine starts and some keys afterwards. So I read them all at the start and store those that I don't need until later. Storing them as a key list is one way, but as I've already read them it seems inefficient. All the information can be encoded in a 2-bit number and at this point there is no need for higher abstraction. –  Loop Space Sep 28 '12 at 9:12

## 1 Answer

I would maintain two property lists; one is updated when a condition is set, the second one is loaded with the state of the first when \saveifs is issued. Then the "static" one can be used to restore the conditionals to the fixed state.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% Document commands
\NewDocumentCommand{\setchoice}{ m m }
{
(Setting~#1~to~#2)\par
\andrew_setchoice:nn { #1 } { #2 }
}
\NewDocumentCommand{\saveifs}{ }
{
(Saving ifs)\par
\andrew_saveifs:
}
\NewDocumentCommand{\restoreifs}{ }
{
(Restoring ifs)\par
\andrew_restoreifs:
}
\NewDocumentCommand{\stateofifs}{} % no internal version, it's just for showing the situation
{
State of ifs:\par
\prop_if_empty:NT \l__andrew_conditionals_prop { *Still~no~conditionals* }
\prop_map_inline:Nn \l__andrew_conditionals_prop
{
Choice~##1~is~##2\par
}
}

% Variables
\prop_new:N \l__andrew_conditionals_prop
\prop_new:N \l__andrew_saved_conditionals_prop

% Functions

\cs_new_protected:Npn \andrew_setconditional:nn #1 #2
{
\use:c { bool_set_#2:c } { l__andrew_cond_ #1 _bool }
\prop_put:Nnn \l__andrew_conditionals_prop { #1 } { #2 }
}
\cs_new_protected:Npn \andrew_setchoice:nn #1 #2
{
\cs_if_free:cT { l__andrew_cond_ #1 _bool }
{
\bool_new:c { l__andrew_cond_ #1 _bool }
}
\andrew_setconditional:nn { #1 } { #2 }
}
\cs_new_protected:Npn \andrew_saveifs:
{
\prop_set_eq:NN \l__andrew_saved_conditionals_prop \l__andrew_conditionals_prop
}
\cs_new_protected:Npn \andrew_restoreifs:
{
\prop_map_inline:Nn \l__andrew_saved_conditionals_prop
{
\andrew_setconditional:nn { ##1 } { ##2 }
}
}
\ExplSyntaxOff

\begin{document}

\stateofifs

\setchoice{a}{true}
\saveifs

\stateofifs

\setchoice{b}{true}
\setchoice{a}{false}

\stateofifs
\saveifs

\setchoice{a}{true}

\restoreifs

\stateofifs
\end{document}


The conditionals are dynamically created. So \setchoice{foo}{true} will create \l__andrew_cond_foo_bool if needed, but it's not necessary to know that name. It will also update the property list \l__andrew_conditionals_prop.

The command \saveifs will set \l__andrew_saved_conditionals_prop equal to the current \l__andrew_conditionals_prop. For restoring the values it's sufficient to do a mapping from this property list.

-
I'm trying to put my finger on what I don't like about this solution, and it's probably my fault for complicating the issue. In the above, it feels as though the booleans aren't really used. My use-case is all internal to L3 so I can just check the value stored in the prop, and instead of true and false I could store 1 and 0, then as I know the number of conditionals I could simply store them as a token list as, say, 10 for "a is true, b is false". –  Loop Space Sep 26 '12 at 18:29
@AndrewStacey It all depends on what you really want to do. If the conditionals are all known, it's a different thing and a numerical comparison might be better. But maintaining the conditionals may be more efficient if the decision has to be made depending on one of them. If they are only two, then the branches are four; if they are ten, then an \int_case:nnn with 1024 branches is not that maintainable. –  egreg Sep 26 '12 at 19:20
That last bit is what I meant about the conditionals being independent. So I don't have to consider 1024 cases. I have to consider 10 lots of 2 cases. Choice A influences action A but has no effect on action B which is determined by Choice B. –  Loop Space Sep 26 '12 at 21:46