When to use tl_to_str:V and when tl_to_str:N?aliasing vs variants — preferred practices?Difficulty saving formatting to a sequence to be called later in my codeA Couple of Tidbits about the LaTeX3 tl_case:??? FunctionLaTeX3: If next in input stream is command X or environment X, do Y else ZMisunderstanding from l3keys documentationWhy does the TeX scanner process tokens for register numbers and macro names differently?Equivalent for bgroup egroup in LaTeX3Is it possible to separate the declaration of a LaTeX3 variable of type control-sequence from the act of setting its value?Building regex from another one

What are the minimum element requirements for a star?

Why would prey creatures not hate predator creatures?

Why do we use the particular magnitude of a force to calculate work?

Grammar explanation for ~よし

Are there any dishes that can only be cooked with a microwave?

A new type of builder pattern

What was the motive for inventing Gröbner bases?

Is it a mistake to use a password that has previously been used (by anyone ever)?

Music theory class: the interval between (B flat and B sharp) and (E sharp and E flat)

Euclidean Distance Between Two Matrices

Generalize superdense encoding

How to tell my mentor to be careful when discussing my work in progress around people I do not trust?

How to explain to traditional people why they should upgrade their old Windows XP device?

N-Dimensional Cartesian Product

Is "montäglich" commonly used?

Unable to Style the checkboxes in Sitecore Forms

Is every conformal manifold equivalent to a flat one with cone singularities?

Steampunk book about a bounty hunter teen girl in London

Can a UK passport valid for two months travel to Germany post-brexit?

Bach Invention BMW 792 - Fingering Advice

Can the treble clef be used instead of the bass clef in piano music?

Prove that the equation has only one real root.

If prey gave predators the corpses of members which had naturally died, would predators be able to subsist without killing the prey?

Does toddler keep hands around private parts?



When to use tl_to_str:V and when tl_to_str:N?


aliasing vs variants — preferred practices?Difficulty saving formatting to a sequence to be called later in my codeA Couple of Tidbits about the LaTeX3 tl_case:??? FunctionLaTeX3: If next in input stream is command X or environment X, do Y else ZMisunderstanding from l3keys documentationWhy does the TeX scanner process tokens for register numbers and macro names differently?Equivalent for bgroup egroup in LaTeX3Is it possible to separate the declaration of a LaTeX3 variable of type control-sequence from the act of setting its value?Building regex from another one






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









9


















According to the interface3 documentation tl_to_str:N expects a “tl var”, which I believe might be e.g. g_temp_tl.



tl_to_str:V should, if I got it right, expect an argument representing a control sequence referring to a variable, i.e. a token list variable, which I thought is something like g_temp_tl.



So what is the usage difference?



Please give one example with tl_to_str:N where the V-variant would be wrong and another example with tl_to_str:V where the N-variant would be wrong.










share|improve this question



























  • Take a look at this example to understand the difference between N, n, and V: dpaste.com/3WRPSGA Basically V will perform one step of expansion whereas N takes the token unmodified.

    – Henri Menke
    Sep 7 at 23:22












  • @HenriMenke So what am I supposed to feed into each tl_to_str:*?

    – Robert Siemer
    Sep 7 at 23:57






  • 1





    On documentation: as others have I think said, texdoc expl3 gives the general intro, interface3 is really intended as a formal reference. (I've written some introductory stuff, but probably we really do need to get 'Programming expl3' sorted!)

    – Joseph Wright
    Sep 8 at 7:29

















9


















According to the interface3 documentation tl_to_str:N expects a “tl var”, which I believe might be e.g. g_temp_tl.



tl_to_str:V should, if I got it right, expect an argument representing a control sequence referring to a variable, i.e. a token list variable, which I thought is something like g_temp_tl.



So what is the usage difference?



Please give one example with tl_to_str:N where the V-variant would be wrong and another example with tl_to_str:V where the N-variant would be wrong.










share|improve this question



























  • Take a look at this example to understand the difference between N, n, and V: dpaste.com/3WRPSGA Basically V will perform one step of expansion whereas N takes the token unmodified.

    – Henri Menke
    Sep 7 at 23:22












  • @HenriMenke So what am I supposed to feed into each tl_to_str:*?

    – Robert Siemer
    Sep 7 at 23:57






  • 1





    On documentation: as others have I think said, texdoc expl3 gives the general intro, interface3 is really intended as a formal reference. (I've written some introductory stuff, but probably we really do need to get 'Programming expl3' sorted!)

    – Joseph Wright
    Sep 8 at 7:29













9













9









9








According to the interface3 documentation tl_to_str:N expects a “tl var”, which I believe might be e.g. g_temp_tl.



tl_to_str:V should, if I got it right, expect an argument representing a control sequence referring to a variable, i.e. a token list variable, which I thought is something like g_temp_tl.



So what is the usage difference?



Please give one example with tl_to_str:N where the V-variant would be wrong and another example with tl_to_str:V where the N-variant would be wrong.










share|improve this question
















According to the interface3 documentation tl_to_str:N expects a “tl var”, which I believe might be e.g. g_temp_tl.



tl_to_str:V should, if I got it right, expect an argument representing a control sequence referring to a variable, i.e. a token list variable, which I thought is something like g_temp_tl.



So what is the usage difference?



Please give one example with tl_to_str:N where the V-variant would be wrong and another example with tl_to_str:V where the N-variant would be wrong.







expl3 latex3 token-lists






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 15 at 0:17







Robert Siemer

















asked Sep 7 at 23:12









Robert SiemerRobert Siemer

7075 silver badges12 bronze badges




7075 silver badges12 bronze badges















  • Take a look at this example to understand the difference between N, n, and V: dpaste.com/3WRPSGA Basically V will perform one step of expansion whereas N takes the token unmodified.

    – Henri Menke
    Sep 7 at 23:22












  • @HenriMenke So what am I supposed to feed into each tl_to_str:*?

    – Robert Siemer
    Sep 7 at 23:57






  • 1





    On documentation: as others have I think said, texdoc expl3 gives the general intro, interface3 is really intended as a formal reference. (I've written some introductory stuff, but probably we really do need to get 'Programming expl3' sorted!)

    – Joseph Wright
    Sep 8 at 7:29

















  • Take a look at this example to understand the difference between N, n, and V: dpaste.com/3WRPSGA Basically V will perform one step of expansion whereas N takes the token unmodified.

    – Henri Menke
    Sep 7 at 23:22












  • @HenriMenke So what am I supposed to feed into each tl_to_str:*?

    – Robert Siemer
    Sep 7 at 23:57






  • 1





    On documentation: as others have I think said, texdoc expl3 gives the general intro, interface3 is really intended as a formal reference. (I've written some introductory stuff, but probably we really do need to get 'Programming expl3' sorted!)

    – Joseph Wright
    Sep 8 at 7:29
















Take a look at this example to understand the difference between N, n, and V: dpaste.com/3WRPSGA Basically V will perform one step of expansion whereas N takes the token unmodified.

– Henri Menke
Sep 7 at 23:22






Take a look at this example to understand the difference between N, n, and V: dpaste.com/3WRPSGA Basically V will perform one step of expansion whereas N takes the token unmodified.

– Henri Menke
Sep 7 at 23:22














@HenriMenke So what am I supposed to feed into each tl_to_str:*?

– Robert Siemer
Sep 7 at 23:57





@HenriMenke So what am I supposed to feed into each tl_to_str:*?

– Robert Siemer
Sep 7 at 23:57




1




1





On documentation: as others have I think said, texdoc expl3 gives the general intro, interface3 is really intended as a formal reference. (I've written some introductory stuff, but probably we really do need to get 'Programming expl3' sorted!)

– Joseph Wright
Sep 8 at 7:29





On documentation: as others have I think said, texdoc expl3 gives the general intro, interface3 is really intended as a formal reference. (I've written some introductory stuff, but probably we really do need to get 'Programming expl3' sorted!)

– Joseph Wright
Sep 8 at 7:29










2 Answers
2






active

oldest

votes


















10



















tl_to_str:V is a variant of tl_to_str:n, i.e. it retrieves the value of any variable you throw at it and passes it to tl_to_str:n. tl_to_str:N on the other hand expects a token list variable and converts its value to a string. Importantly, this is a separate function from tl_to_str:n, not a variant.



As long as you only pass token list variables to these functions, they behave identically, except for that tl_to_str:N is marginally faster than tl_to_str:V. If you pass different variable types to both functions, the result may differ, depending on the variable type. (It is never correct to pass anything but a token list variable to tl_to_str:N!)



documentclassarticle

usepackage[T1]fontenc
usepackageexpl3

begindocument

ExplSyntaxOn

tl_set:Nn l_tmpa_tl 42
int_set:Nn l_tmpa_int 42
fp_set:Nn l_tmpa_fp 42

tl_to_str:N l_tmpa_tl % 42
par
tl_to_str:V l_tmpa_tl % 42
par
tl_to_str:N l_tmpa_int % l_tmpa_int
par
tl_to_str:V l_tmpa_int % 42
par
tl_to_str:N l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;
par
tl_to_str:V l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;

ExplSyntaxOff

enddocument



Note that the value retrieved by exp_args:NV and passed to tl_to_str:n when you call tl_to_str:V is not necessarily in a human readable form (what you call a "string representation" in the comments). Let us instead call it a value representation. The defining property of this representation is that it is understood by the functions handling the respective variable type, i.e. you can input s__fp __fp_chk:w 1024200000000000000; into any fp function instead of 42 and it would behave the same. (You can think of this like exp_args:NV retrieving the binary representation of the variable value, though that is obviously just a metaphor.)



Formatting the value of a variable for human readers is an entirely different task. Note that, although it might look like tl_to_str:N (or :V does this for token lists, this is not really true (in the sense that you get all the information determining the exact value of the variable), since it does not show category codes.




Regarding your request for examples: tl_to_str:V l_tmpa_int is right, tl_to_str:N l_tmpa_int is wrong. tl_to_str:V is never wrong when you can use tl_to_str:N (namely on tl variables), but it is slower.



The real difference between the two functions in the latter case is a conceptual one: tl_to_str:N acts on the variable, tl_to_str:V acts on its content. In this case, the result is the same: [convert the content of [this token list variable]] is the same as [convert [the content of this token list variable]]. With other functions, there may be differences, e.g. the :N version often assigns a new value to the variable while the :V version leaves the result in the input stream. There may also be differences in expandability.






share|improve this answer




























  • ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

    – Robert Siemer
    Sep 8 at 0:14











  • Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

    – Robert Siemer
    Sep 8 at 0:19






  • 2





    @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

    – siracusa
    Sep 8 at 2:34






  • 1





    @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

    – schtandard
    Sep 8 at 6:30






  • 1





    @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

    – Joseph Wright
    Sep 8 at 6:53



















11



















I see that schtandard has written an excellent answer, but thought I might elaborate a bit on the difference between n-, N- and V-type arguments. I'll also include a little history and TeXnical detail which might help illustrate a few ideas.



The core argument types for expl3 are N (a single token without braces) and n (zero or more tokens in a brace pair). For token lists, we use these two types to separate out functions that act on a token list variable from those that act on a 'raw' token list



tl_map_function:NN l_tmpa_tl my_func:n
tl_map_function:nN abc my_func:n


Historically (up to around the time I joined the LaTeX team), we called token list variables 'token list pointers' (tlp), and the functions were separate: that made some ideas a bit clearer, but made others a lot more opaque and really was overall confusing.



Token list variables are ultimately TeX macros, so we can get their 'value' at a TeX primitive level using expandafter, or in expl3 terms we could use exp_args:No:



exp_args:No tl_map_function:nN l_tmpa_tl my_func:n


is thus equivalent to



tl_map_function:NN l_tmpa_tl my_func:n


The problem there is I'm relying on the implementation of l_tmpa_tl. We could have used TeX token registers (toks) for data storage, and they can only be converted to their content by the the primitive. Thus applying exp_args:No is problematic: ideally, using expl3 you don't need to know the implementation detail. (Provided the APIs remain unchanged, the team reserve the right to alter implementation.)



The V-type argument deals with this issue. It uses some clever code by Morten to 'look at' the variable and decide if it's a macro or a TeX register. It then does either expandafter or the as required, leaving just the 'value'. That means (as illustrated in the answer by schtandard) that we can use V-type expansion and apply it to tl, dim, etc. and not have to worry how they are implemented.



(Historically, expl3 had a separate module for toks, and these were used in parallel with tlp/tl: it was really important to have a simple way to get values. We altered tl data storage to avoid needing toks too, so this aspect doesn't show quite as strongly now.)



Almost all tl_<thing>:N 'use' functions could replaced by tl_<thing>:V, but there would be a performance hit. At the implementation level, the team are 'allowed' to take advantage of how things are defined in raw TeX terms. So for example tl_to_str:N currently does use the fact that the tl can yield a value on a single expansion:



> tl_to_str:N=long macro:
#1->__kernel_tl_to_str:w exp_after:wN #1.
l.3 showtl_to_str:N


which is in primitive terms exactly



detokenizeexpandafter#1


and thus as fast as this task can be achieved.






share|improve this answer





























    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "85"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );














    draft saved

    draft discarded
















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f507422%2fwhen-to-use-tl-to-strv-and-when-tl-to-strn%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown


























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    10



















    tl_to_str:V is a variant of tl_to_str:n, i.e. it retrieves the value of any variable you throw at it and passes it to tl_to_str:n. tl_to_str:N on the other hand expects a token list variable and converts its value to a string. Importantly, this is a separate function from tl_to_str:n, not a variant.



    As long as you only pass token list variables to these functions, they behave identically, except for that tl_to_str:N is marginally faster than tl_to_str:V. If you pass different variable types to both functions, the result may differ, depending on the variable type. (It is never correct to pass anything but a token list variable to tl_to_str:N!)



    documentclassarticle

    usepackage[T1]fontenc
    usepackageexpl3

    begindocument

    ExplSyntaxOn

    tl_set:Nn l_tmpa_tl 42
    int_set:Nn l_tmpa_int 42
    fp_set:Nn l_tmpa_fp 42

    tl_to_str:N l_tmpa_tl % 42
    par
    tl_to_str:V l_tmpa_tl % 42
    par
    tl_to_str:N l_tmpa_int % l_tmpa_int
    par
    tl_to_str:V l_tmpa_int % 42
    par
    tl_to_str:N l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;
    par
    tl_to_str:V l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;

    ExplSyntaxOff

    enddocument



    Note that the value retrieved by exp_args:NV and passed to tl_to_str:n when you call tl_to_str:V is not necessarily in a human readable form (what you call a "string representation" in the comments). Let us instead call it a value representation. The defining property of this representation is that it is understood by the functions handling the respective variable type, i.e. you can input s__fp __fp_chk:w 1024200000000000000; into any fp function instead of 42 and it would behave the same. (You can think of this like exp_args:NV retrieving the binary representation of the variable value, though that is obviously just a metaphor.)



    Formatting the value of a variable for human readers is an entirely different task. Note that, although it might look like tl_to_str:N (or :V does this for token lists, this is not really true (in the sense that you get all the information determining the exact value of the variable), since it does not show category codes.




    Regarding your request for examples: tl_to_str:V l_tmpa_int is right, tl_to_str:N l_tmpa_int is wrong. tl_to_str:V is never wrong when you can use tl_to_str:N (namely on tl variables), but it is slower.



    The real difference between the two functions in the latter case is a conceptual one: tl_to_str:N acts on the variable, tl_to_str:V acts on its content. In this case, the result is the same: [convert the content of [this token list variable]] is the same as [convert [the content of this token list variable]]. With other functions, there may be differences, e.g. the :N version often assigns a new value to the variable while the :V version leaves the result in the input stream. There may also be differences in expandability.






    share|improve this answer




























    • ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

      – Robert Siemer
      Sep 8 at 0:14











    • Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

      – Robert Siemer
      Sep 8 at 0:19






    • 2





      @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

      – siracusa
      Sep 8 at 2:34






    • 1





      @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

      – schtandard
      Sep 8 at 6:30






    • 1





      @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

      – Joseph Wright
      Sep 8 at 6:53
















    10



















    tl_to_str:V is a variant of tl_to_str:n, i.e. it retrieves the value of any variable you throw at it and passes it to tl_to_str:n. tl_to_str:N on the other hand expects a token list variable and converts its value to a string. Importantly, this is a separate function from tl_to_str:n, not a variant.



    As long as you only pass token list variables to these functions, they behave identically, except for that tl_to_str:N is marginally faster than tl_to_str:V. If you pass different variable types to both functions, the result may differ, depending on the variable type. (It is never correct to pass anything but a token list variable to tl_to_str:N!)



    documentclassarticle

    usepackage[T1]fontenc
    usepackageexpl3

    begindocument

    ExplSyntaxOn

    tl_set:Nn l_tmpa_tl 42
    int_set:Nn l_tmpa_int 42
    fp_set:Nn l_tmpa_fp 42

    tl_to_str:N l_tmpa_tl % 42
    par
    tl_to_str:V l_tmpa_tl % 42
    par
    tl_to_str:N l_tmpa_int % l_tmpa_int
    par
    tl_to_str:V l_tmpa_int % 42
    par
    tl_to_str:N l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;
    par
    tl_to_str:V l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;

    ExplSyntaxOff

    enddocument



    Note that the value retrieved by exp_args:NV and passed to tl_to_str:n when you call tl_to_str:V is not necessarily in a human readable form (what you call a "string representation" in the comments). Let us instead call it a value representation. The defining property of this representation is that it is understood by the functions handling the respective variable type, i.e. you can input s__fp __fp_chk:w 1024200000000000000; into any fp function instead of 42 and it would behave the same. (You can think of this like exp_args:NV retrieving the binary representation of the variable value, though that is obviously just a metaphor.)



    Formatting the value of a variable for human readers is an entirely different task. Note that, although it might look like tl_to_str:N (or :V does this for token lists, this is not really true (in the sense that you get all the information determining the exact value of the variable), since it does not show category codes.




    Regarding your request for examples: tl_to_str:V l_tmpa_int is right, tl_to_str:N l_tmpa_int is wrong. tl_to_str:V is never wrong when you can use tl_to_str:N (namely on tl variables), but it is slower.



    The real difference between the two functions in the latter case is a conceptual one: tl_to_str:N acts on the variable, tl_to_str:V acts on its content. In this case, the result is the same: [convert the content of [this token list variable]] is the same as [convert [the content of this token list variable]]. With other functions, there may be differences, e.g. the :N version often assigns a new value to the variable while the :V version leaves the result in the input stream. There may also be differences in expandability.






    share|improve this answer




























    • ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

      – Robert Siemer
      Sep 8 at 0:14











    • Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

      – Robert Siemer
      Sep 8 at 0:19






    • 2





      @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

      – siracusa
      Sep 8 at 2:34






    • 1





      @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

      – schtandard
      Sep 8 at 6:30






    • 1





      @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

      – Joseph Wright
      Sep 8 at 6:53














    10















    10











    10









    tl_to_str:V is a variant of tl_to_str:n, i.e. it retrieves the value of any variable you throw at it and passes it to tl_to_str:n. tl_to_str:N on the other hand expects a token list variable and converts its value to a string. Importantly, this is a separate function from tl_to_str:n, not a variant.



    As long as you only pass token list variables to these functions, they behave identically, except for that tl_to_str:N is marginally faster than tl_to_str:V. If you pass different variable types to both functions, the result may differ, depending on the variable type. (It is never correct to pass anything but a token list variable to tl_to_str:N!)



    documentclassarticle

    usepackage[T1]fontenc
    usepackageexpl3

    begindocument

    ExplSyntaxOn

    tl_set:Nn l_tmpa_tl 42
    int_set:Nn l_tmpa_int 42
    fp_set:Nn l_tmpa_fp 42

    tl_to_str:N l_tmpa_tl % 42
    par
    tl_to_str:V l_tmpa_tl % 42
    par
    tl_to_str:N l_tmpa_int % l_tmpa_int
    par
    tl_to_str:V l_tmpa_int % 42
    par
    tl_to_str:N l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;
    par
    tl_to_str:V l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;

    ExplSyntaxOff

    enddocument



    Note that the value retrieved by exp_args:NV and passed to tl_to_str:n when you call tl_to_str:V is not necessarily in a human readable form (what you call a "string representation" in the comments). Let us instead call it a value representation. The defining property of this representation is that it is understood by the functions handling the respective variable type, i.e. you can input s__fp __fp_chk:w 1024200000000000000; into any fp function instead of 42 and it would behave the same. (You can think of this like exp_args:NV retrieving the binary representation of the variable value, though that is obviously just a metaphor.)



    Formatting the value of a variable for human readers is an entirely different task. Note that, although it might look like tl_to_str:N (or :V does this for token lists, this is not really true (in the sense that you get all the information determining the exact value of the variable), since it does not show category codes.




    Regarding your request for examples: tl_to_str:V l_tmpa_int is right, tl_to_str:N l_tmpa_int is wrong. tl_to_str:V is never wrong when you can use tl_to_str:N (namely on tl variables), but it is slower.



    The real difference between the two functions in the latter case is a conceptual one: tl_to_str:N acts on the variable, tl_to_str:V acts on its content. In this case, the result is the same: [convert the content of [this token list variable]] is the same as [convert [the content of this token list variable]]. With other functions, there may be differences, e.g. the :N version often assigns a new value to the variable while the :V version leaves the result in the input stream. There may also be differences in expandability.






    share|improve this answer
















    tl_to_str:V is a variant of tl_to_str:n, i.e. it retrieves the value of any variable you throw at it and passes it to tl_to_str:n. tl_to_str:N on the other hand expects a token list variable and converts its value to a string. Importantly, this is a separate function from tl_to_str:n, not a variant.



    As long as you only pass token list variables to these functions, they behave identically, except for that tl_to_str:N is marginally faster than tl_to_str:V. If you pass different variable types to both functions, the result may differ, depending on the variable type. (It is never correct to pass anything but a token list variable to tl_to_str:N!)



    documentclassarticle

    usepackage[T1]fontenc
    usepackageexpl3

    begindocument

    ExplSyntaxOn

    tl_set:Nn l_tmpa_tl 42
    int_set:Nn l_tmpa_int 42
    fp_set:Nn l_tmpa_fp 42

    tl_to_str:N l_tmpa_tl % 42
    par
    tl_to_str:V l_tmpa_tl % 42
    par
    tl_to_str:N l_tmpa_int % l_tmpa_int
    par
    tl_to_str:V l_tmpa_int % 42
    par
    tl_to_str:N l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;
    par
    tl_to_str:V l_tmpa_fp % s__fp __fp_chk:w 1024200000000000000;

    ExplSyntaxOff

    enddocument



    Note that the value retrieved by exp_args:NV and passed to tl_to_str:n when you call tl_to_str:V is not necessarily in a human readable form (what you call a "string representation" in the comments). Let us instead call it a value representation. The defining property of this representation is that it is understood by the functions handling the respective variable type, i.e. you can input s__fp __fp_chk:w 1024200000000000000; into any fp function instead of 42 and it would behave the same. (You can think of this like exp_args:NV retrieving the binary representation of the variable value, though that is obviously just a metaphor.)



    Formatting the value of a variable for human readers is an entirely different task. Note that, although it might look like tl_to_str:N (or :V does this for token lists, this is not really true (in the sense that you get all the information determining the exact value of the variable), since it does not show category codes.




    Regarding your request for examples: tl_to_str:V l_tmpa_int is right, tl_to_str:N l_tmpa_int is wrong. tl_to_str:V is never wrong when you can use tl_to_str:N (namely on tl variables), but it is slower.



    The real difference between the two functions in the latter case is a conceptual one: tl_to_str:N acts on the variable, tl_to_str:V acts on its content. In this case, the result is the same: [convert the content of [this token list variable]] is the same as [convert [the content of this token list variable]]. With other functions, there may be differences, e.g. the :N version often assigns a new value to the variable while the :V version leaves the result in the input stream. There may also be differences in expandability.







    share|improve this answer















    share|improve this answer




    share|improve this answer








    edited Sep 11 at 7:03

























    answered Sep 8 at 0:05









    schtandardschtandard

    6,9231 gold badge16 silver badges34 bronze badges




    6,9231 gold badge16 silver badges34 bronze badges















    • ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

      – Robert Siemer
      Sep 8 at 0:14











    • Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

      – Robert Siemer
      Sep 8 at 0:19






    • 2





      @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

      – siracusa
      Sep 8 at 2:34






    • 1





      @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

      – schtandard
      Sep 8 at 6:30






    • 1





      @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

      – Joseph Wright
      Sep 8 at 6:53


















    • ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

      – Robert Siemer
      Sep 8 at 0:14











    • Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

      – Robert Siemer
      Sep 8 at 0:19






    • 2





      @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

      – siracusa
      Sep 8 at 2:34






    • 1





      @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

      – schtandard
      Sep 8 at 6:30






    • 1





      @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

      – Joseph Wright
      Sep 8 at 6:53

















    ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

    – Robert Siemer
    Sep 8 at 0:14





    ...I am supposed to throw some non-token list at tl_to_str:V? This is some kind of supported and intended use case? What use case would that be!?

    – Robert Siemer
    Sep 8 at 0:14













    Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

    – Robert Siemer
    Sep 8 at 0:19





    Your answer is really good at pointing out my confusion here: if tl_to_str:V is supposed to eat any variable, then I would expect it to turn them into proper string representations: works great for integers (where tl_to_str:N fails), but it is buggy for floating point 42. (If it is not buggy, than what is?)

    – Robert Siemer
    Sep 8 at 0:19




    2




    2





    @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

    – siracusa
    Sep 8 at 2:34





    @RobertSiemer The important difference is that :V variants unpack any kind of variable and pass the result as argument to the corresponding :n function. Token lists are a special case of this general variable unpacking, so they also work with :V. OTOH, an :N function works only with a single token and may have a different behavior than the corresponding :n function. Of course, for token lists the :N and :V functions will likely do the same thing. I guess the two functions are provided mainly for efficiency and consistency reasons.

    – siracusa
    Sep 8 at 2:34




    1




    1





    @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

    – schtandard
    Sep 8 at 6:30





    @RobertSiemer On your question about tl_new:N: I don't need to call it because I only used scratch variables that are defined by the kernel. (The int part would not work otherwise.) If I had used different variable names, I would have had to define them first using the ..._new:N functions.

    – schtandard
    Sep 8 at 6:30




    1




    1





    @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

    – Joseph Wright
    Sep 8 at 6:53






    @schtandard Yes, you are right: V-type can be used for any variable which has a single value (we perhaps should make fp 'print nicely', but it's a bit tricky). So tl, int, dim, skip, muskip, (fp) but not say prop or seq. Box registers are excluded as they don't have a meaningful 'value' here (at least without LuaTeX).

    – Joseph Wright
    Sep 8 at 6:53














    11



















    I see that schtandard has written an excellent answer, but thought I might elaborate a bit on the difference between n-, N- and V-type arguments. I'll also include a little history and TeXnical detail which might help illustrate a few ideas.



    The core argument types for expl3 are N (a single token without braces) and n (zero or more tokens in a brace pair). For token lists, we use these two types to separate out functions that act on a token list variable from those that act on a 'raw' token list



    tl_map_function:NN l_tmpa_tl my_func:n
    tl_map_function:nN abc my_func:n


    Historically (up to around the time I joined the LaTeX team), we called token list variables 'token list pointers' (tlp), and the functions were separate: that made some ideas a bit clearer, but made others a lot more opaque and really was overall confusing.



    Token list variables are ultimately TeX macros, so we can get their 'value' at a TeX primitive level using expandafter, or in expl3 terms we could use exp_args:No:



    exp_args:No tl_map_function:nN l_tmpa_tl my_func:n


    is thus equivalent to



    tl_map_function:NN l_tmpa_tl my_func:n


    The problem there is I'm relying on the implementation of l_tmpa_tl. We could have used TeX token registers (toks) for data storage, and they can only be converted to their content by the the primitive. Thus applying exp_args:No is problematic: ideally, using expl3 you don't need to know the implementation detail. (Provided the APIs remain unchanged, the team reserve the right to alter implementation.)



    The V-type argument deals with this issue. It uses some clever code by Morten to 'look at' the variable and decide if it's a macro or a TeX register. It then does either expandafter or the as required, leaving just the 'value'. That means (as illustrated in the answer by schtandard) that we can use V-type expansion and apply it to tl, dim, etc. and not have to worry how they are implemented.



    (Historically, expl3 had a separate module for toks, and these were used in parallel with tlp/tl: it was really important to have a simple way to get values. We altered tl data storage to avoid needing toks too, so this aspect doesn't show quite as strongly now.)



    Almost all tl_<thing>:N 'use' functions could replaced by tl_<thing>:V, but there would be a performance hit. At the implementation level, the team are 'allowed' to take advantage of how things are defined in raw TeX terms. So for example tl_to_str:N currently does use the fact that the tl can yield a value on a single expansion:



    > tl_to_str:N=long macro:
    #1->__kernel_tl_to_str:w exp_after:wN #1.
    l.3 showtl_to_str:N


    which is in primitive terms exactly



    detokenizeexpandafter#1


    and thus as fast as this task can be achieved.






    share|improve this answer
































      11



















      I see that schtandard has written an excellent answer, but thought I might elaborate a bit on the difference between n-, N- and V-type arguments. I'll also include a little history and TeXnical detail which might help illustrate a few ideas.



      The core argument types for expl3 are N (a single token without braces) and n (zero or more tokens in a brace pair). For token lists, we use these two types to separate out functions that act on a token list variable from those that act on a 'raw' token list



      tl_map_function:NN l_tmpa_tl my_func:n
      tl_map_function:nN abc my_func:n


      Historically (up to around the time I joined the LaTeX team), we called token list variables 'token list pointers' (tlp), and the functions were separate: that made some ideas a bit clearer, but made others a lot more opaque and really was overall confusing.



      Token list variables are ultimately TeX macros, so we can get their 'value' at a TeX primitive level using expandafter, or in expl3 terms we could use exp_args:No:



      exp_args:No tl_map_function:nN l_tmpa_tl my_func:n


      is thus equivalent to



      tl_map_function:NN l_tmpa_tl my_func:n


      The problem there is I'm relying on the implementation of l_tmpa_tl. We could have used TeX token registers (toks) for data storage, and they can only be converted to their content by the the primitive. Thus applying exp_args:No is problematic: ideally, using expl3 you don't need to know the implementation detail. (Provided the APIs remain unchanged, the team reserve the right to alter implementation.)



      The V-type argument deals with this issue. It uses some clever code by Morten to 'look at' the variable and decide if it's a macro or a TeX register. It then does either expandafter or the as required, leaving just the 'value'. That means (as illustrated in the answer by schtandard) that we can use V-type expansion and apply it to tl, dim, etc. and not have to worry how they are implemented.



      (Historically, expl3 had a separate module for toks, and these were used in parallel with tlp/tl: it was really important to have a simple way to get values. We altered tl data storage to avoid needing toks too, so this aspect doesn't show quite as strongly now.)



      Almost all tl_<thing>:N 'use' functions could replaced by tl_<thing>:V, but there would be a performance hit. At the implementation level, the team are 'allowed' to take advantage of how things are defined in raw TeX terms. So for example tl_to_str:N currently does use the fact that the tl can yield a value on a single expansion:



      > tl_to_str:N=long macro:
      #1->__kernel_tl_to_str:w exp_after:wN #1.
      l.3 showtl_to_str:N


      which is in primitive terms exactly



      detokenizeexpandafter#1


      and thus as fast as this task can be achieved.






      share|improve this answer






























        11















        11











        11









        I see that schtandard has written an excellent answer, but thought I might elaborate a bit on the difference between n-, N- and V-type arguments. I'll also include a little history and TeXnical detail which might help illustrate a few ideas.



        The core argument types for expl3 are N (a single token without braces) and n (zero or more tokens in a brace pair). For token lists, we use these two types to separate out functions that act on a token list variable from those that act on a 'raw' token list



        tl_map_function:NN l_tmpa_tl my_func:n
        tl_map_function:nN abc my_func:n


        Historically (up to around the time I joined the LaTeX team), we called token list variables 'token list pointers' (tlp), and the functions were separate: that made some ideas a bit clearer, but made others a lot more opaque and really was overall confusing.



        Token list variables are ultimately TeX macros, so we can get their 'value' at a TeX primitive level using expandafter, or in expl3 terms we could use exp_args:No:



        exp_args:No tl_map_function:nN l_tmpa_tl my_func:n


        is thus equivalent to



        tl_map_function:NN l_tmpa_tl my_func:n


        The problem there is I'm relying on the implementation of l_tmpa_tl. We could have used TeX token registers (toks) for data storage, and they can only be converted to their content by the the primitive. Thus applying exp_args:No is problematic: ideally, using expl3 you don't need to know the implementation detail. (Provided the APIs remain unchanged, the team reserve the right to alter implementation.)



        The V-type argument deals with this issue. It uses some clever code by Morten to 'look at' the variable and decide if it's a macro or a TeX register. It then does either expandafter or the as required, leaving just the 'value'. That means (as illustrated in the answer by schtandard) that we can use V-type expansion and apply it to tl, dim, etc. and not have to worry how they are implemented.



        (Historically, expl3 had a separate module for toks, and these were used in parallel with tlp/tl: it was really important to have a simple way to get values. We altered tl data storage to avoid needing toks too, so this aspect doesn't show quite as strongly now.)



        Almost all tl_<thing>:N 'use' functions could replaced by tl_<thing>:V, but there would be a performance hit. At the implementation level, the team are 'allowed' to take advantage of how things are defined in raw TeX terms. So for example tl_to_str:N currently does use the fact that the tl can yield a value on a single expansion:



        > tl_to_str:N=long macro:
        #1->__kernel_tl_to_str:w exp_after:wN #1.
        l.3 showtl_to_str:N


        which is in primitive terms exactly



        detokenizeexpandafter#1


        and thus as fast as this task can be achieved.






        share|improve this answer
















        I see that schtandard has written an excellent answer, but thought I might elaborate a bit on the difference between n-, N- and V-type arguments. I'll also include a little history and TeXnical detail which might help illustrate a few ideas.



        The core argument types for expl3 are N (a single token without braces) and n (zero or more tokens in a brace pair). For token lists, we use these two types to separate out functions that act on a token list variable from those that act on a 'raw' token list



        tl_map_function:NN l_tmpa_tl my_func:n
        tl_map_function:nN abc my_func:n


        Historically (up to around the time I joined the LaTeX team), we called token list variables 'token list pointers' (tlp), and the functions were separate: that made some ideas a bit clearer, but made others a lot more opaque and really was overall confusing.



        Token list variables are ultimately TeX macros, so we can get their 'value' at a TeX primitive level using expandafter, or in expl3 terms we could use exp_args:No:



        exp_args:No tl_map_function:nN l_tmpa_tl my_func:n


        is thus equivalent to



        tl_map_function:NN l_tmpa_tl my_func:n


        The problem there is I'm relying on the implementation of l_tmpa_tl. We could have used TeX token registers (toks) for data storage, and they can only be converted to their content by the the primitive. Thus applying exp_args:No is problematic: ideally, using expl3 you don't need to know the implementation detail. (Provided the APIs remain unchanged, the team reserve the right to alter implementation.)



        The V-type argument deals with this issue. It uses some clever code by Morten to 'look at' the variable and decide if it's a macro or a TeX register. It then does either expandafter or the as required, leaving just the 'value'. That means (as illustrated in the answer by schtandard) that we can use V-type expansion and apply it to tl, dim, etc. and not have to worry how they are implemented.



        (Historically, expl3 had a separate module for toks, and these were used in parallel with tlp/tl: it was really important to have a simple way to get values. We altered tl data storage to avoid needing toks too, so this aspect doesn't show quite as strongly now.)



        Almost all tl_<thing>:N 'use' functions could replaced by tl_<thing>:V, but there would be a performance hit. At the implementation level, the team are 'allowed' to take advantage of how things are defined in raw TeX terms. So for example tl_to_str:N currently does use the fact that the tl can yield a value on a single expansion:



        > tl_to_str:N=long macro:
        #1->__kernel_tl_to_str:w exp_after:wN #1.
        l.3 showtl_to_str:N


        which is in primitive terms exactly



        detokenizeexpandafter#1


        and thus as fast as this task can be achieved.







        share|improve this answer















        share|improve this answer




        share|improve this answer








        edited Sep 8 at 7:26

























        answered Sep 8 at 6:52









        Joseph WrightJoseph Wright

        215k24 gold badges582 silver badges912 bronze badges




        215k24 gold badges582 silver badges912 bronze badges































            draft saved

            draft discarded















































            Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f507422%2fwhen-to-use-tl-to-strv-and-when-tl-to-strn%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown









            Popular posts from this blog

            Tamil (spriik) Luke uk diar | Nawigatjuun

            Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

            Training a classifier when some of the features are unknownWhy does Gradient Boosting regression predict negative values when there are no negative y-values in my training set?How to improve an existing (trained) classifier?What is effect when I set up some self defined predisctor variables?Why Matlab neural network classification returns decimal values on prediction dataset?Fitting and transforming text data in training, testing, and validation setsHow to quantify the performance of the classifier (multi-class SVM) using the test data?How do I control for some patients providing multiple samples in my training data?Training and Test setTraining a convolutional neural network for image denoising in MatlabShouldn't an autoencoder with #(neurons in hidden layer) = #(neurons in input layer) be “perfect”?