4

In the MWE below why does the \tl_if_eq:nnTF function perform as expected if an operand is specified directly as a parameter #.. but fail if that parameter is first loaded into a variable and that variable then used as the operand? E.g. \tl_if_eq:nnTF {#1}{xyz} produces a match if #1=abc, but, with \l_rn_auxOne_tl set to #1, fails to produce a match for \tl_if_eq:nnTF {\l_rn_auxOne_tl}{xyz}.

The rationale for loading parameters first into a tl variable is so they can be tested prior to using them to pre-empt compilation or worse still, runtime errors, where possible. An obvious use of such tests for example might be for valid integer or floating point number syntax.

\documentclass{article}
% RN. Tuesday 21 November 2017
% BRIEF DESCRIPTION:
%  parameter passing and testing
%=======================
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
%-----------------------
\ExplSyntaxOn
\NewDocumentCommand\myCommand{mO{xyz}}
  {
    \rn_someUtility:n {#2}  
  }  %  \myCommand

\tl_new:N \l_rn_auxOne_tl
\cs_new:Npn \rn_someUtility:n #1
  {
\group_begin:
  macro~param~1~direct~=~#1\\
  \tl_if_eq:nnTF {#1}{xyz}
    {match~for~xyz\\}
    {no~match~for~xyz\\}

  \tl_set:Nn \l_rn_auxOne_tl {#1}
  macro~param~1~via~tl~variable~=~#1\\
  \tl_if_eq:nnTF {\l_rn_auxOne_tl}{xyz}
    {match~for~xyz\\}
    {no~match~for~xyz\\}

  macro~param~1~direct~=~#1\\
  \tl_if_eq:nnTF {#1}{123}
    {match~for~123\\}
    {no~match~for~123\\}

  \tl_set:Nn \l_rn_auxOne_tl {#1}
  macro~param~1~via~tl~variable~=~#1\\
  \tl_if_eq:nnTF {\l_rn_auxOne_tl}{123}
    {match~for~123\\}
    {no~match~for~123\\}
\group_end:
  }  %  \rn_someUtility:nnn  
\ExplSyntaxOff
%-----------------------
\begin{document}
  \textbf{Example~1: }\verb+\myCommand{Hi}+\\ 
  \myCommand{Hi}
  \textbf{Example~2: }\verb+\myCommand{Hi}[123]+\\ 
  \myCommand{Hi}[123]
\end{document}
0

1 Answer 1

7

That what argument expansion is for; one of the main strengths of expl3 code, and the argument signature of the functions.

\tl_if_eq:nnTF { \l_rn_auxOne_tl } { xyz }

outputs false, because it's false, one says xyz and the other says \l_rn_auxone_tl.

What you want is to see what's inside \l_rn_auxone_tl, you need to expand it. And here comes the beauty of expl3, you can do that just by telling the function that the argument is of type V rather than n.

\cs_generate_variant:Nn \tl_if_eq:nnTF { V }

and then use

\tl_if_eq:VnTF \l_rn_auxone_tl { xyz }

In the case of conditionals I don't know what is the standard procedure, but if you need the other T, F, TF you might need

\cs_generate_variant:Nn \tl_if_eq:nnTF { V }
\cs_generate_variant:Nn \tl_if_eq:nnT  { V }
\cs_generate_variant:Nn \tl_if_eq:nnF  { V }

May be they could program a \cs_generate_variant:Nnn \tl_if_eq:nnTF { V } { T, F, TF }? Or syntax like { V ; T, F, TF }? Or may be that \cs_generate_variant:Nn \tl_if_eq:nn { V } was enough for conditionals?

3
  • I am embarrassed to admit that I now realize I had been told this before. Unfortunately I am the kind of guy who needs to hear things three or four times, in different settings, before they sink in. It is high time for me to make a proper study of v vs. x vs. n etc.etc. Nov 21, 2017 at 12:37
  • 1
    v is to V what c is to N. This answer, with the v argument would be \tl_if_eq:vnTF { l_rn_auxone_tl } { xyz } just so you can understand it easily. x means it gets expanded inside an \edef before the argument starts to see. It's not appropiate here, but just so you understand \def\a{\b} \def\b{xyz} wouldn't work with then \tl_if_eq:Vn \a { xyz } wouldn't be enough because you would be comparing \b to xyz, so if you fully expanded it (in this case two times, but it can be whatever) you would get a <true> as a result.
    – Manuel
    Nov 21, 2017 at 12:41
  • Plugged it into my code and it all works like clockwork. You've been very helpful. Nov 21, 2017 at 12:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .