4

Background
In LaTeX3 I’m programming some macros to store and read contents from a variable like \tl_set:Nn does. An thus I’m generating variants using the N type, which causes a warning. The warning suggests to use V instead wich would be comprehensible for the reading macro \tobiw_use_thing but feels wrong for the writing macro \tobiw_save_thing. Since the manual says (highlighting by me):

The V and v specifiers are used to get the content of a variable […]

MWE

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \tobiw_save_thing:nn {
   \tl_set:Nn #1 { #2 }
}
\cs_generate_variant:Nn \tobiw_save_thing:nn { Nn }

\cs_new:Nn \tobiw_use_thing:n {
   \tl_use:N #1
}
\cs_generate_variant:Nn \tobiw_use_thing:n { N }

\NewDocumentCommand{\saveanduse}{ m }{
   \tobiw_save_thing:Nn \l_tmpa_tl { #1 }
   \fbox { \tobiw_use_thing:N \l_tmpa_tl }
}

\ExplSyntaxOff

\begin{document}
   Test
   \saveanduse{Tokens}
\end{document}

Question
So what is the best approach to create macros like this? What argument types should be used here?

  • 1
    It should be \cs_new_protected:Nn \tobiw_save_things:Nn to begin with. No variant needed. – egreg Mar 31 '18 at 7:59
  • Why aren't you directly generating functions like \tobiw_save_thing:Nn? You would not get any warning. – TeXnician Mar 31 '18 at 7:59
  • Btw: Conversion n to N is not well-formed, it should be n to V, but on the other hand there are the equivalents c and N if you want to be able to consume a group as csname. – TeXnician Mar 31 '18 at 8:00
6

You must not use variants here.

Variants are needed when a basic function, with signature consisting only of N or n specifiers (or in inclusive sense, to be clear), needs some kind of expansion of arguments before it takes action:

  • V is a variant for n, where the variant function will receive a single token (which should be the name of a suitable variable) and the basic function will receive as its n argument the value.

  • f and x are variants for n, where the contents of the braces will be f- or x-expanded.

  • o is a variant for n, where the contents of the braces will be “one time expanded”, in the sense that the first token in the list will be expanded once.

  • c is a variant for N, where the contents of the braces will be transformed in a single token to be fed as the N argument.

You are defining two basic functions and both expect a single token as their first (or unique) argument: this asks for an argument of type N.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\cs_new_protected:Nn \tobiw_save_thing:Nn
 {
   \tl_set:Nn #1 { #2 }
 }

\cs_new:Nn \tobiw_use_thing:N
 {
   \tl_use:N #1
 }

\NewDocumentCommand{\saveanduse}{ m }
 {
   \tobiw_save_thing:Nn \l_tmpa_tl { #1 }
   \fbox { \tobiw_use_thing:N \l_tmpa_tl }
 }

\ExplSyntaxOff

\begin{document}
   Test
   \saveanduse{Tokens}
\end{document}

Note that the first function should be defined with _protected, because it sets some variable.

The function defining facilities \cs_new_... or \cs_set_... have basic signatures :Nn or :Npn. The signature of the defined function should only consist of strings of N or n (inclusive sense); w is only allowed in the :Npn case.

As an example, you have \tobiw_use_thing:N, but you possibly want

\cs_new:Nn \tobiw_use_thing:n
 {
  Do something with #1
 }
\cs_generate_variant:Nn \tobiw_use_thing:n { V }

allowing calls such as

\tobiw_use_thing:n {whatever}

or

\tobiw_use_thing:V \l_tmpa_tl

But, at the end, it depends on what your functions are supposed to do.

  • Thanks! … sometimes its quite easy … didn’t saw this solution. In this case would you recommend to use \tobiw_use_thing:N or \tobiw_use_thing:V? – Tobi Mar 31 '18 at 12:08
  • @Tobi It depends on what you want the function to do. I'll add something. – egreg Mar 31 '18 at 12:31
  • I see. So N when I’m sure that there is always a single token and n+V when there are multiple tokes directly given as argument or as a variable content, right? – Tobi Mar 31 '18 at 12:36
  • @Tobi Yes, that's the idea. – egreg Mar 31 '18 at 12:37
4

You do not need any variant here, you could simply define functions with N type arguments. If your main concern is to allow also grouped input (as csname) generate a c variant afterwards.

Your functions uses the specifier n which stands for a group of tokens. You can convert those (as variant) to V type arguments, because that way the idea of getting a group of tokens stays intact. On the other hand you have the pair of c and N, where the former accepts a group of tokens (but forms one control word out of it) and the latter accepts one token, a control word.

When designing functions you should design with the purpose of the argument in mind. If you want a control sequence as argument use one of N or c. If you want some value use n, o, x, f, V or v.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \tobiw_save_thing:Nn {
   \tl_set:Nn #1 { #2 }
}
\cs_generate_variant:Nn \tobiw_save_thing:Nn { cn }

\cs_new:Nn \tobiw_use_thing:N {
   \tl_use:N #1
}
\cs_generate_variant:Nn \tobiw_use_thing:N { c }

\NewDocumentCommand{\saveanduse}{ m }{
   \tobiw_save_thing:Nn \l_tmpa_tl { #1 }
   \fbox { \tobiw_use_thing:N \l_tmpa_tl }
}

\ExplSyntaxOff

\begin{document}
   Test
   \saveanduse{Tokens}
\end{document}

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.