Questions about `\cs_new:...` and friends and their TeX relatives regarding global, local, long, nopar, protected, expandable and naming

I see that Marcel has covered (1) and (2): I'll try to tackle the others.

As far as possible, 'variables' and 'functions' are treated the same in expl3. However, there are places that it turns out to be slightly more tricky. One place is that having \g_... in every function name would be painful: very few functions are repeatedly set, in contrast to variables. As such, the risk of save-stack build-up and the like is low.

All 'new' functions act globally in creating their argument; for variables, they also initialise in global scope. For functions, there is no 'initial' value, so \cs_new:Npn and similar set at global scope: the equivalent of \global\long\def. Where scope is indicated, this is always using g... and ... names, so there is no lset, it's just 'set'.

The creation of local functions/variables has come up before, usually in the context of variables. It was tried but did not seem to sit well with TeX's grouping model, so was not retained. This again goes with 'new' rather than 'gnew': variables are always declared and this is always global.

Whether the fact that 'new' is global and doesn't require 'gnew' I leave to others: I feel it's OK to have a clear set of 'always global' actions.

Everything is 'long' unless otherwise marked at the code level. Generally, Knuth's \long marker is useful in documents but problematic in code. The marker is as it is due to language development: things were originally closer to TeX namings (e.g. \def_new:Npn rather than \cs_new_nopar:Npn). As 'long' status is the default, it was easier to have the 'nopar' marker explicit.

The balance with protected status is more complex: whichever way one goes, there will be a large number of 'the other case'. At the same time, language development began well before e-TeX was required. Thus protected status was added well after initial ideas were developed. The team have discussed this (and the fact that function names do not indicate expansion behaviour), but at this stage a change here is simply too late.


  1. Is \cs_gset:Npn indeed like \long\global\def?

\cs_gset:Npn is defined as \tex_long:D \tex_gdef:D, so it is exactly the same as \long\gdef.

  1. Is \cs_set_protected:Npn like \protected\long\def?

\cs_set_protected:Npn is defined as \tex_protected:D \tex_long:D \tex_def:D, so yes it is exactly the same as \protected\long\def.

(See texdoc source3, Section 5.3 "Defining functions" for reference)


Every <module>_new<...> function globally defines a function or variable, setting it to something sensible. If you do

  • \cs_new:Npn #1 \siemer_foo:n { whatever #1 }, the function is globally defined and its action will be as defined.
  • \tl_new:N \l_siemer_foo_tl, the token list variable is globally defined and initialized to empty.
  • \int_new:N \g_siemer_foo_int, the integer variable is globally defined and initialized to 0.

What's the difference between \g_... and \l_... for variables? The former type should be always set globally, the latter locally. TeX will not raise errors if you do \int_set:Nn \g_siemer_foo_int { 42 }, but the Spanish Inquisition might start chasing on you it's conceptually wrong. Actually, an error would be raised if expl3 is loaded with the check-declarations option:

! LaTeX3 Error: Inconsistent local/global assignment

For immediate help type H <return>.
 ...                                              

l.8 \int_set:Nn \g_siemer_foo_int { 42 }

This kind of check is computationally heavy, so it should only be used when writing and testing the code, not when running LaTeX over a standard document.

A consequence is that there is no concept of “local variable”, in the sense of a variable only available locally. Since TeX has no notion of “namespace”, it's better to use descriptive variable names, so to be sure about their usage. It was a precise choice not to provide \<module>_gnew<...> as opposed to a \<module>_new<...> declaring the variable only locally.

However, one can have local functions, that are only available in the group they're defined in. This is the purpose of the \cs_set family of functions.

What's the difference between \cs_new and \cs_gset, then? A big one: the former family of functions check whether the to-be-defined function does not already exist; the latter simply overwrites the definition without warning.

So it's not true that \cs_new:Npn is \long\global\def: it is “check whether the function exists and if it does raise an error, otherwise perform \long\global\def. On the other hand, \cs_gset:Npn is \long\global\def.

Functions need not be \protected: several of them would cease to work if they were. To make a simple example, \int_eval:n must not be \protected, because its job is to deliver an integer in decimal notation in expansion contexts.