As I think the concept of "variant" in expl3
is one of the most fundamental concepts for LaTeX3 I like to expand a bit on the answer already given by Joseph.
Naming convention
The naming convention for commands in LaTeX3 (expl3
) structures the command name into
\
module_
description:
arg-specifiers
- module identifies the (main) type of data the function manipulates or use (for example,
int
(integers), prop
(property lists), etc., or it might be the name of a package or some specific concept
- description says what is being done, e.g.,
put_left
, get
, clear
, count
, etc. If it makes sense the same descriptions are reused, but for special tasks there can, of course, be some that are used only once.
- arg-specifiers finally describe what arguments the function has and how they should be treated (more on this below).
Base functions
The base arg-specifiers are:
N
denoting that the argument consists of a single token (no braces needed, sometimes not even allowed)
n
denoting a "normal" argument with braces
p
denoting a parameter spec like #1#2
in definitions
T
is like n
but tells the programmer that this is the "true" path in a conditional
F
is like n
but signals the "false" path in a conditional
Commands with arg-specifiers consisting just of those letters are called base functions.
Variant functions
There are many more arg-specifiers available, for example
c
interpret the argument as a string and generate a command name from it
V
the argument is a variable, use its value
v
the argument is a string, generate a variable name from it and then use the value of that variable
o
expand the argument once like in \expandafter{...}
x
expand the argument as if it would have been inside the replacement text of \edef
f
expand the argument fully until you hit a non-expandable token then stop expanding
Any command that uses one or more of these arg-specifiers is called a variant of the corresponding base function. The important aspect here is that all these additional arg-specifiers modify the argument in one way or another and only then pass it to the underlying base function. For example:
\foo_bar:cVno {cmd} \VAR {text} \CMD
would
- generate from the string
cmd
the command name \cmd
- look up the value of the variable
\VAR
- leave
text
alone
- expand
\CMD
once and surround the result with braces
and only then it would call the corresponding base function as follows:
\foo_bar:Nnnn \cmd {<value-of-\VAR>} {text} {<one-level-expansion-of-\CMD>}
Now ideally we want any possible variant of a base function automatically available for a programmer. Unfortunately, this can only be reliably done if alle variants have all been predefined (as TeX doesn't offer you to trap the "undefined csname" error and do something on the fly).
Given the number of arg-specifier and the possible permutations predefining all variants, of which 90% would never be needed, is not realistic. We therefore adopted the following strategy:
- conceptually all variants are available and everybody can assume this is the case
- in reality the kernel only defines a small subset that is often needed
- any variant not defined by the kernel needs to be defined by the programmer using
\cs_generate_variant:Nn
\cs_generate_variant:Nn
has been designed in such a way that it doesn't matter if it is called several times: if the variant already exists it will do nothing. So if two programmers define the same variant in their packages it doesn't hurt, the first one executed will define the variant the second one will simply be ignored (with very little overhead).
- If some variants are used fairly often they may eventually get defined already in the kernel. Because of the last point it doesn't hurt if some packages still define the variant, i.e., there is no need for programmers to modify their packages in that case.
So in summary: Whenever you need a variant that is not predefined, define it at the beginning of your code. This is even sensible if you need the variant only once, because the code using the variant will be much more readable than any manual preprocessing of the argument and the speed difference is close to zero.
The \exp_args:N...
functions
Technicically speaking a variant defined via \cs_generate_variant:Nn
has a very simple definition: \foo_bar:cVno
above would simply expand to
\exp_args:NcVno \foo_bar:Nnnnn
So instead of defining the variant and then using it like this:
\cs_generate_variant:Nn \foo_bar:Nnnnn {cVno}
...
\foo_bar:cVno {cmd} \VAR {text} \CMD
one could, of course, directly use its replacement text, i.e.,
\exp_args:NcVno \foo_bar:Nnnn {cmd} \VAR {text} \CMD
If you do that, then you optimise for speed (you avoid one expansion - hurrah) at the cost of less readable code and except in very very special circumstances this is not useful. In the kernel there are a few commands that have been very carefully optimised for speed, but unless you expect your command to be called many thousand times in a document there is no way to even measure the speed gain. Concerning the question of clarity, even if a variant is used only once in the code it will make the code clearer as all the arg-specifiers have universal meanings I can immediately see what happens with the arguments regardless of what the base function does (which hopefully is clear from its module and description part as far as possible).
So on the whole the advice is: do not use the \exp_args:...
in your code unless there is a very good reason. On "good" reason could, of course, be that you quickly want to test something and then throwing in some \exp_args...
is quicker than defining variants and use them. But this is a little like the argument that one doesn't need to document this piece of code because it is only temporary there (... for the next 10 years).
For the same reason avoid \exp_after:wN
! If you use it, you normally do something wrong in the sense of thinking in plain TeX/LaTeX2e expansion based programming style. (So why has the kernel code so much \exp_after:wN
??? well, there we provide the low-level machinery, and somewhere certain things need to happen :-) but this is not the model on which LaTeX3 programming is build upon.)
Other arg-specifiers
There are a number of other arg-specifiers that I didn't mention above. They are a bit strange and do not support variant generation in the above sense.
D
means don't use this command. It is only for the kernel (if at all). This doesn't really tell if and how many args this command has.
w
means this commands has a weird argument structure which is normally not further detailed. For example \exp_after:wN
(known in plain TeX as \expandafter
) is a little strange as it expands the second token (N
) but the first can be a single opening or closing brace.
Aliases viz variants
In contrast to a variant (that manipulates the arguments before passing the result to the base function) is an alias of a command not providing any new functionality. It is simply a "copy" of a command under a new name. The reason why this can be useful is simply abstraction in the code (hiding implementation details) and as a side effect also readability.
For example, the data type seq
(sequences) is internally implemented as simple token lists (tl
) with some internal structure. Therefore to "clear" a sequence, i.e., \seq_clear:N
is doing exactly the same as clearing a token list \tl_clear:N
, i.e., the latter would (at the moment) clear the sequence as well. But providing a separate name here is nevertheless much better:
- it makes the code more readable (you see that you are clearing a sequence)
- the programmer doesn't need to remember which commands a specific to sequences and which not
- there is a proper abstraction for the sequence type: if the implementation would get changed, code would not be affected. For example property lists changed the implementation from
toks
registers to tl
s.
So in summary an alias is something you would only want to use if you have a reason to provide existing fuctionality under a different name.
\cs_generate_variant:Nn \seq_set_split:Nnn { NVV }
. I'd say that it's the good method.\cs_generate_variant:Nn
?\cs_generate_variant:Nn
is the recommended method for doing such variations. You might do\exp_args:NV \seq_set_split:NnV \l__delimiter_tl \l__content_string_tl
, which is exactly what the built variant would do.\exp_args:...
commands. But @egreg is right: variants are a much cleaner way (and they simply use\exp_args:...
internally (I think))\exp_args:NNV \seq_set_split:NnV
which is equivalent to\seq_set_split:NVV
(once defined), but not advisable.