4

For example \exp_args:Nxo is available but not \exp_args:NxV. Can we safely use the former instead of the latter?

7
  • Usually you don't need \exp_args at all but generate corresponding variants of the functions you're working with. And then you can just generate V if you need V.
    – cgnieder
    Feb 27 at 10:02
  • 2
    No, they're different even if the result might be the same. According to the guidelines a V argument should not be braced (but the value will be), whereas an o argument should be braced. The fact that \exp_args:NxV is not predefined is of no concern, because you can do \exp_args_generate:n { xV } and then you can use \exp_args:NxV. On the other hand, generating function variants is the recommended route.
    – egreg
    Feb 27 at 10:24
  • Function \cs_generate_variant:Nn (+variant ...:cn) in texdoc interface3 explains the syntax. V (and v) variant functions are usually enough in most cases.
    – Cicada
    Feb 27 at 10:25
  • For lowercase (o,c), the braces tells Tex where the set of tokens stops; for uppercase (V,N), no braces are needed because only one token is expected (usually the name of the variable).
    – Cicada
    Feb 27 at 10:32
  • 2
    @Cicada stronger than "no braces are needed" it is "braces should not be used" (although using braces does not always give an error for fficiency reasons. But in general you could end up with \def{\oops}{...} and low level tex errors if you brace N or V arguments Feb 27 at 10:55

2 Answers 2

6

No, they're not the same, even if in some cases they do produce the same result.

\documentclass{article}

\ExplSyntaxOn

\tl_new:N \l_jl_test_tl
\int_new:N \l_jl_test_int

\tl_set:Nn \l_jl_test_tl { tokens }
\int_set:Nn \l_jl_test_int { 42 }

\exp_args_generate:n { xV }

\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn

\exp_args:NxV \use_ii:nn { whatever } \l_jl_test_tl

\par

\exp_args:NxV \use_ii:nn { whatever } \l_jl_test_int

\par

\exp_args:Nxo \use_ii:nn { whatever } { \l_jl_test_tl }

\par

\exp_args:Nxo \use_ii:nn { whatever } { \l_jl_test_int }

\ExplSyntaxOff

\end{document}

enter image description here

Do you see the problem?

You also see that if some \exp_args:N... combination is not available out of the box, you can generate it very simply.

Note that an o argument should be braced and, to the contrary, a V argument shouldn't. The fact that TeX might do the “right” thing anyway is irrelevant.

On the other hand, it is much preferable and actually recommended t avoid \exp_args:N... when it's more than a one shot case. If you feel the necessity of using \exp_args:NxV, then it's quite likely that you want to define the suitable function variant.

-1

The question is not whether o and V are equivalent, which obviously is not the case, the question is whether one can emulate V with o. The answer is yes as suggested by the documentation interface3.pdf (p 3), but there are subtleties. The V arguments specifier gets the content of the variable, but things depend on the variable.

We can categorize variables

  1. token list like variables : tl, str, seq, clist, prop, fp
  2. int like variables: int, dim, skip, muskip
  3. quark
  4. intarray, fparray, cctab

For category 1 and 3, \foo:V <variable> is replaced by \foo:o { <variable> } For category 2, \foo:V <variable> is replaced by \foo:o { \<type>_use:N <variable> } For category 4, the variables are not suitable for a V argument.

Demonstration for int, dim, skip, muskip

\MyTest:nn prints SUCCESS if the 2 arguments as token lists are equal, FAILURE otherwise.

% !TeX program = lualatex
\documentclass{article}
\begin{document}
\noindent
\ExplSyntaxOn
\cs_new:Nn \MyTest:nn {
  \tl_if_eq:nnTF { #1 } { #2 } { SUCCESS } { FAILURE } \\
}
\cs_generate_variant:Nn \MyTest:nn { Vo }

\int_set:Nn \l_tmpa_int { 1234 }
\MyTest:Vo \l_tmpa_int { \int_use:N \l_tmpa_int }

\dim_set:Nn \l_tmpa_dim { 1234pt }
\MyTest:Vo \l_tmpa_dim { \dim_use:N \l_tmpa_dim }

\skip_set:Nn \l_tmpa_skip { 1234pt plus 1cm minus 2mm }
\MyTest:Vo \l_tmpa_skip { \skip_use:N \l_tmpa_skip }

\muskip_set:Nn \l_tmpa_muskip { 1234mu }
\MyTest:Vo \l_tmpa_muskip { \muskip_use:N \l_tmpa_muskip }
\end{document}

Demonstration for tl, str, seq, clist, prop, fp and quarks

For \MyTest:Nn, #1 sets \My_var to #2 and calls \MyTest:Vo with appropriate arguments.

% !TeX program = lualatex
\documentclass{article}
\begin{document}
\noindent
\ExplSyntaxOn
\cs_new:Nn \MyTest:nn {
  \tl_if_eq:nnTF { #1 } { #2 } { SUCCESS } { FAILURE } \\
}
\cs_generate_variant:Nn \MyTest:nn { Vo }
\cs_new:Nn \MyTest:Nn {
  #1 \My_var { #2 }
  \MyTest:Vo \My_var { \My_var }
}
\MyTest:Nn \tl_set:Nn { \def\My#1{#1#1} }
\MyTest:Nn \str_set:Nn { \def\My#1{#1#1} }
\MyTest:Nn \seq_set_from_clist:Nn { \def, \My, #1, {#1#1} }
\MyTest:Nn \clist_set:Nn{ \def, \My, #1, {#1#1} }
\MyTest:Nn \prop_set_from_keyval:Nn {
  \def = \My,
  #1 = {#1#1},
}
\MyTest:Nn \fp_set:Nn { 3.14159 }
\quark_new:N \q_My
\MyTest:Vo \q_My { \q_My }
\end{document}

Less contrived example

This illustrate what is possible, but this should not be used in production code because it uses unsupported features.

Here we define \foo:n to build a property list from its argument assuming it is the raw content of a property list variable and print out the items. Then we generate 'o' and 'V' variants to finally test \foo:o and \foo:V.

% !TeX program = lualatex
\documentclass{article}
\begin{document}
\noindent
\ExplSyntaxOn
\cs_new:Nn \foo:n {
  \tl_set:Nn \l_tmpb_prop { #1 }
  \prop_map_inline:Nn \l_tmpb_prop {
    ##1$\to$##2\\
  }
}
\cs_generate_variant:Nn \foo:n { o, V }
\prop_set_from_keyval:Nn \l_tmpa_prop {
  KEY1=VALUE1,
  KEY2=VALUE2,
}
\foo:V \l_tmpa_prop
\prop_set_from_keyval:Nn \l_tmpa_prop {
  key1=value1,
  key2=value2,
}
\foo:o { \l_tmpa_prop }
\ExplSyntaxOff
\end{document}

Is it safe ?

For a short time usage, it is ok, but for deployment code it is definitely not. If LaTeX internals change, this may break in the future.

10
  • They're still not the same.
    – egreg
    Mar 2 at 16:06
  • 1
    \tl_set:Nn \l_tmpb_prop is absurd.
    – egreg
    Mar 2 at 16:41
  • 1
    No, o is not equivalent to V even if you use \tl_use:N. Try \ExplSyntaxOn \tl_set:Nn \l_tmpa_tl { ABCD } \tl_set:No \l_tmpb_tl { \tl_use:N \l_tmpa_tl } % should assign ABCD to tmpb \tl_set:Nn \l_tmpa_tl { DEFG } \typeout{\l_tmpb_tl} % should print ABCD, but doesn't... (and try \exp_args:No \tl_show:n { \tl_use:N \l_My_tl } to see why). Mar 2 at 16:57
  • Argh, \tl_use:N is not \the !!!!!!! Mar 2 at 19:02
  • 1
    @JérômeLAURENS You've discovered that seq, prop and str are macros.
    – egreg
    Mar 3 at 17:05

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.