17

I have a command defined using xparse syntax:

\DeclareDocumentCommand \foo { O{} m } {}

Inside some other command (say, \bar), I want to call this command. The calling command (\bar) has to construct the arguments to feed to \foo. So the call is something like:

\foo [\tl_use:N \l_my_temporary_tl] {}

I want to make sure that when \foo is called, it is the actual token list and not the command that gets passed.

If \foo took two mandatory arguments then it would appear that I could just do

\exp_args:No \foo {\tl_use:N \l_my_temporary_tl} {}

(I realise that the number of expansions here might be incorrect, but that's not the point.)

Is there a similar syntax for optional arguments?

If not, how would the following look:

\cs_new:Npn \exp_opt_args:No #1[#2] { \exp_after:wN #1 \exp_after:wN [#2] }

and similar ...

2
  • 3
    xparse is for document commands. Could you add a concrete example of where this is needed at a document level? (Usually, a function defined by xparse should simply pass the input to a well-defined code-level function with a fixed number of mandatory arguments.)
    – Joseph Wright
    Aug 25, 2011 at 8:51
  • @Joseph: I hadn't thought of that solution, though it makes perfect sense. My actual example is pretty close to what I describe: I have a command that I sometimes call in the document (hence a DocumentCommand) but sometimes I need to call it with a bit of preprocessing (hence the wrapper command). But making both wrappers to a single code-level function would work just fine, I guess. Aug 25, 2011 at 9:01

3 Answers 3

14

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.

1
  • Both yours and Joseph's have the solution that I'm now using (that of having the DocumentCommand a wrapper to an internal one) but yours gets the "accepted" for the additional explanation of the V argument type. Aug 25, 2011 at 9:15
12

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.)

0
0

None of the other answers worked for me for whatever reason (lots of missing $ inserted errors). I solved this via something like:

\DeclareDocumentCommand{\fig}{O{t} +m}{
    \edef\figPoss{[#1]}
    \expandaftercmds{\begin{figure}}{\figPoss}
        #2
    \end{figure}
}

The key being that edef is needed to expand brackets with the text argument (e.g. \figPoss is then [t]), and then to use etextools' \expandaftercmds to delay processing of the \begin{figure} until the option is in place.

You must log in to answer this question.

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