2

In the MWE below NewDocumentCommands \myComparison and \myNewComparison both use a control sequence \cookbook_Compare:nn which is fed two tokenlist parameters to be compared. These parameters are defined as optional O{} type parameters; while in \myComparison the default values are defined literally, in \myNewComparison they are defined through tokenlist variables. Calls 1., 2. and 3. of \myComparison work as expected, so do calls 4. and 5. of \myNewComparison. However, if \myNewComparison is called without parameters as in 6., \tl_if_eq:NNTF comes up with the wrong answer comparing what seem to me two tokenlist variables with identical content. Why?

\usepackage[check-declarations]{expl3}
\usepackage{xparse}
%   ----------------------------------------
\ExplSyntaxOn
%   VARIABLE DECLARATIONS:
\tl_new:N \l_rn_OpOne_tl
\tl_new:N \l_rn_OpTwo_tl
\tl_new:N \l_rn_OpOneDefault_tl
\tl_new:N \l_rn_OpTwoDefault_tl
\tl_set:Nn \l_rn_OpOneDefault_tl {abc} 
\tl_set:Nn \l_rn_OpTwoDefault_tl {abc} 
%   ----------------------------------------
\NewDocumentCommand\myComparison{O{abc}O{abc}}
 {
 \cookbook_Compare:nn {#1}{#2}
 }
\NewDocumentCommand\myNewComparison{O{\l_rn_OpOneDefault_tl}O    {\l_rn_OpTwoDefault_tl}}
 {
 \cookbook_Compare:nn {#1}{#2}
 }
\cs_new_protected:Npn \cookbook_Compare:nn #1 #2 
    {
        \tl_set:Nn \l_rn_OpOne_tl {#1}
        \tl_set:Nn \l_rn_OpTwo_tl {#2}
        Op~1:~\l_rn_OpOne_tl\\
        Op~2:~\l_rn_OpTwo_tl\\
        Op~1~=~ Op~2~  
        \tl_if_eq:NNTF \l_rn_OpOne_tl \l_rn_OpTwo_tl
            {TRUE\\}{FALSE\\}
    }
\ExplSyntaxOff
\begin{document}
1. \verb+\myComparison[zz][zz]+:\\
 \myComparison[zz][zz]
2. \verb+\myComparison[1z][zz]+:\\
 \myComparison[1z][zz]
3. \verb+\myComparison+:\\
\myComparison
4. \verb+\myNewComparison[zz][zz]+:\\
 \myNewComparison[zz][zz]
5. \verb+\myNewComparison[1z][zz]+:\\
 \myNewComparison[1z][zz]
6. \verb+\myNewComparison+:\\
\myNewComparison
\end{document}
0
3

The test for token list equivalence isn't 'do these expand eventually to the same thing' but 'do they have the same contents'. With your code, you effectively end up with

\tl_set:Nn \l_rn_OpOne_tl {\l_rn_OpOneDefault_tl}
\tl_set:Nn \l_rn_OpTwo_tl {\l_rn_OpTwoDefault_tl}

which are not equal: they contain different tl variables, which happen to have the same content.

If you want to compare the content here, and you also want to allow both literal and stored input, then you've got to force expansion all the way through to 'text', using \tl_set:Nx. The risk there is that with LaTeX2e input you might have fragile commands, so unless you are in a very restricted situation you should use \protected@edef instead. (expl3 doesn't provide any equivalent of the latter as the LaTeX2e robust mechanism isn't required for 'native' LaTeX3 material.)

1
  • would this become any easier if I let go the literal input and just go with stored input? Sep 20 '15 at 6:59
3

You have to use a different way of testing the optional arguments, so that you can compare the right tokens; otherwise you're comparing, for instance, \l_rn_OpOneDefault_tl with \l_rn_OpTwoDefault_tl (not the variables' contents).

\documentclass{article}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
%   ----------------------------------------
\ExplSyntaxOn
%   VARIABLE DECLARATIONS:
\tl_new:N \l_rn_OpOne_tl
\tl_new:N \l_rn_OpTwo_tl
\tl_new:N \l_rn_OpOneDefault_tl
\tl_new:N \l_rn_OpTwoDefault_tl
\tl_set:Nn \l_rn_OpOneDefault_tl {abc} 
\tl_set:Nn \l_rn_OpTwoDefault_tl {abc} 
%   ----------------------------------------
\NewDocumentCommand\myComparison{O{abc}O{abc}}
 {
 \cookbook_Compare:nn {#1}{#2}
 }
\NewDocumentCommand\myNewComparison{oo}
 {
  \IfNoValueTF{#1}
   { \cookbook_Compare:VV \l_rn_OpOneDefault_tl \l_rn_OpTwoDefault_tl }
   {
    \IfNoValueTF{#2}
     { \cookbook_Compare:nV { #1 } \l_rn_OpTwoDefault_tl }
     { \cookbook_Compare:nn { #1 } { #2 } }
   }
 }
\cs_new_protected:Npn \cookbook_Compare:nn #1 #2 
    {
        \tl_set:Nn \l_rn_OpOne_tl {#1}
        \tl_set:Nn \l_rn_OpTwo_tl {#2}
        Op~1:~\l_rn_OpOne_tl\\
        Op~2:~\l_rn_OpTwo_tl\\
        Op~1~=~ Op~2~  
        \tl_if_eq:NNTF \l_rn_OpOne_tl \l_rn_OpTwo_tl
            {TRUE\\}{FALSE\\}
    }
\cs_generate_variant:Nn \cookbook_Compare:nn { nV , VV }
\ExplSyntaxOff
\begin{document}
1. \verb+\myComparison[zz][zz]+:\\
 \myComparison[zz][zz]
2. \verb+\myComparison[1z][zz]+:\\
 \myComparison[1z][zz]
3. \verb+\myComparison+:\\
\myComparison
4. \verb+\myNewComparison[zz][zz]+:\\
 \myNewComparison[zz][zz]
5. \verb+\myNewComparison[1z][zz]+:\\
 \myNewComparison[1z][zz]
6. \verb+\myNewComparison+:\\
\myNewComparison
\end{document}

enter image description here

1
  • I recall having been corrected on this issue before and did experiment with V types, but obviously got it wrong. Thanks, this is the hint I was looking for. Sep 20 '15 at 8:36

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.