How do I pass an expanded optional argument using expl3/xparse?
The short answer is that there is no mechanism to do that, because we try to promote separating user interface (through xparse, and the choice of having optional, mandatory, delimited arguments and whatnot) from the coding part.
In most situations I can think of, you could convert the code to
\DeclareDocumentCommand {\foo} { o m }
{
\IfValueTF {#1}
{ \mypkg_foo:nn {#1} {#2} }
{ \mypkg_foo:n {#2} }
}
Then your call would be \exp_args:NV \mypkg_foo:nn \l_my_temporary_tl {}
, using the internal version and skipping the parsing. Note that I'm using a V
argument type to avoid worrying about what kind of variable is used: it will insert \the
when necessary. It would also be possible to use o
, since token lists expand in one step. \tl_use:N
is a rather odd beast, which I've never seen a use for so far.
Perhaps it is not possible in your case. Then you can use either of
\use:x { \foo [ { \exp_not:V \l_my_temporary_tl } ] { } }
where \foo
is not expanded since xparse's commands are protected (unless explicitly made not to be), and \exp_not:V
makes sure that the token list does not expand too far. Or,
\exp_args:NNV \foo [ \l_my_temporary_tl ] { }
which is somewhat a kludge. Note that in both cases, I put braces around the optional argument within brackets: if \l_my_temporary_tl
has unbalanced brackets, the wrong optional argument would be grabbed otherwise.
Broadly, creating document commands (i.e. user syntax) should always be done as a wrapper around internal functions which take only mandatory arguments. Thus is we have two functions \foo
and \bar
, at the document level with some relationship, then internally they should be linked using code-level functions
\DeclareDocumentCommand \foo { O{} m }
{
\IfNoValueTF {#1}
{ \foo_int:n {#2} }
{ \foo_int:nn {#1} {#2} }
}
\DeclareDocumentCommand \bar { O{} m }
{
\tl_set:Nx \l_my_temporary_tl
{ \IfNoValueF {#1} { \exp_not:n {#1} : \exp_not:n {#2} }
\foo_int:Vn \l_my_temporary_tl {#2}
}
Here, I'm setting \l_my_temporary_tl
in an arbitrary fashion, simply so there is something there for the demo.
(More generally, I'd expect \bar
to call a separate function internally, which would then deal with the input.)