This question is two-fold. Unfortunately, one side is opinionated, i.e. something to close-vote, so I put that part at the end and hope no one notices... The other side (coming first) are serious interface3 questions, which I would like to see answered.

The interface3.pdf documentation promises that it will write in a TeXhacker note for each command which latex2 command or TeX primitive they come close to. But it does not contain \gdef or \global\def anywhere.

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

As I understand it, latex3 is also about turning the “TeX programming language” into a saner environment, i.e. an environment which makes it harder to produce bugs by accident. One way to do this is to favor explicit over implicit, especially on treacherous grounds. With that in mind:

  1. Is \cs_new:Npn [which exists] more likely a \cs_gnew:Npn [my invention], i.e. global?
  2. Is \cs_set:Npn [which exists] something like \cs_lset:Npn [my invention], i.e. local?
  3. A \cs_lnew:Npn [my invention] was deemed of no use, so it was dropped, right?
  4. Does it make sense that unqualified functions (no l, no g) sometimes mean local and sometimes global (set vs. new)? → confusing → bugs

  5. \long is implicit now as this is what most programmers would expect, especially with the latex3 syntax. Right?

  6. Non-long is called ..._nopar:... now. It is the unexpected, so it got an explicit label, contrary to what TeX originally had. Correct?
  7. Why is \protected not implicit on the same grounds? I.e. \cs_new_protected:Npn [which exists] should be called \cs_gnew:Npn [my invention] and \cs_gnew_unprotected:Npn [my invention] could be what is currently \cs_new:Npn [which exists].
  • @cfr I totally disagree. Under the premise that you embrace expl3, for document level macros \NewDocumentCommand is a good start. And for everything else \cs_... or some other higher level functions.—I see no reason to use \?def at all with expl3. – Robert Siemer Oct 15 '19 at 16:32
  • I didn't mean that. I meant that \def etc. were intended to be used for both when they were created, whereas l3 distinguishes macros used to create user-level commands from those used to create interenal functions. \NewDocumentCommand etc. was what I had in mind. In the \def world of TeX, there's no such distinction. So \cs_ etc. isn't equivalent to \def etc. because it is intended for only a proper subset of the purposes \def etc. are designed for. – cfr Oct 15 '19 at 21:53
  • @cfr To be honest, I’m still trying to figure out the philosophy behind all this.—Currently I’m feeling that \cs_* should be preferred over any \*def wherever \ExplSyntaxOn is in effect. Outside of that you can’t use them, so... – Robert Siemer Oct 15 '19 at 22:01

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.

  • Maybe \cs_gnew_unprotected:Npn is better. I’ll use that name in my question... – Robert Siemer Oct 15 '19 at 16:39
  • @RobertSiemer Like I say, if we were starting from a clean slate today, perhaps we'd look at this differently. It certainly has been one area we've talked about. But the 'broadly stable' business is important too: we are still making some changes, but take-up means we are more restricted than we were say when I joined the team. – Joseph Wright Oct 15 '19 at 16:40
  • @JosephWright While writing my question I was also thinking about the stable interface restrictions... Well... My suggested new names (or most other naming scheme picking up my critics and using new names) could be introduced with minimal breaking (if any), and the “old” names could be deprecated.—Even at this state it is probably better to do sooner than later. Nevertheless it’ll be work. And as I’m not the one doing it I take what I get. ;-) – Robert Siemer Oct 15 '19 at 16:49
  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.

  • I’m not sure which question you are trying to answer here. – Robert Siemer Oct 15 '19 at 18:50
  • @RobertSiemer I read answers to your questions 1, 2, 3 and 4. – egreg Oct 15 '19 at 21:08
  • I found a clear answer to 1., I did not find an answer to 2. Regarding 3. I think you are saying that indeed \cs_new is a \cs_gnew without endorsing the name. To 4. I’m not sure. – Robert Siemer Oct 15 '19 at 21:29
  • @RobertSiemer "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." – egreg Oct 15 '19 at 21:40

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.