This is related to an earlier question of mine.

I'm posting my own interpretation of what's happening hoping that if I'm wrong, someone will chime in an explain why.

The issue with xparse's \IfNoValue does not hinge on passing an n type argument as @ScottH seems to be suggesting. The issue seems to be buried deeper inside the definition of \IfNoValue.

The nice thing about \IfNoValue is that it is designed in a manner to register whether an argument was empty or not without the end-user being able to accidentally pass something through the argument that'll be interpreted as an empty argument. Namely, \IfNoValue{-NoValue-} should register false. This comes about through some fancy temporary assignment of lower case values and the use of a weird (w) type argument.

The following example illustrates what's happening: (For the most part I'm following xparse's lead in how I'm defining commands so as to mirror the issues from my earlier question as best as possible.)

\cs_new:Npn \ae_experiment:w #1 DELIMITER { #1 }

\cs_new:Npn \ae_testing_weird:n #1 {
        { \ae_experiment:w #1 DELIMITER }
        { Andrew }
        { \emph{moi} }
        { \textbf{not}~me }
\cs_new:Npn \ae_testing_ntype:n #1 {
        { #1 }
        { Andrew }
        { \emph{moi} }
        { \textbf{not}~me }

\cs_new_eq:NN \testingWeird \ae_testing_weird:n
\cs_new_eq:NN \testingNtype \ae_testing_ntype:n

        \tl_set:Nn \l_ae_bypass_tl {#1}
        \exp_args:NV \testingWeird \l_ae_bypass_tl


Func. Call      & \verb=Andrew=         & vs. & \verb=\Andrew=         \\\hline
\verb=Weird=    & \testingWeird{Andrew} &     & \testingWeird{\Andrew} \\
\verb=Ntype=    & \testingNtype{Andrew} &     & \testingNtype{\Andrew} \\
\verb=bypassed= & \bypassWeird{Andrew}  &     & \bypassWeird{\Andrew}


I expected the second and third line of this table to have the same results. But it appears that \exp_args:NV only expanded \l_ae_bypass once to \Andrew and then no further. Why?



or even




does not fix things.

  • I will try to work out what you are up to in the other question and give a 'proper' answer there. Note at this stage that \exp_args:NV \testingWeird is strongly discouraged: you should not really need \exp_args: in code at all, as \cs_generate_variant:Nn should be used on appropriate code-level functions.
    – Joseph Wright
    May 18, 2013 at 7:16
  • I only resorted to \exp_args: because that's what I seem to need to get things to work in my previous example. I look forward to your answer to that question.
    – A.Ellett
    May 18, 2013 at 7:19

1 Answer 1


That's exactly what is supposed to happen: V-type expansion gives you the value stored inside a variable. The flow when you use


is that \l_ae_bypass has content \Andrew. So when you do

\exp_args:NV \testingWeird \l_ae_bypass

this is converted to

\testingWeird \l_ae_bypass { \Andrew }

and results in a false result in your test. If you want exhaustive expansion, then you'll have to have

\tl_set:Nx \l_ae_bypass {#1}

but in your case that will still fail as you've defined \Andrew as a document command (non-expandable) rather than as a variable (expandable).

(As noted by Marco Daniel, the expl3 convention is that code-level variable names must end with the type. So you should have \l_ae_bypass_tl here.)


You must log in to answer this question.

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