38

This question springs from a comment of mine and the subsequent discussion in chat.

I don't know anything about TeX, but I can easily understand a command like:

\let\oldmacro\somemacro

whereas

\cs_set_eq:NN

is not so clear to me.

In particular, all those underscores within the command names thoroughly dizzy me. Why was _ chosen, instead of writing \csSetEq, for example?

Moreover, why is :NN needed? Why is it necessary to add syntax information to the command name?

Isn't having self-explanatory commands one of the strength of LaTeX?

  • 3
    Isn't having self-explanatory commands one of the strenght of LaTeX? What makes you think that expl3 commands are not self-explanatory? I mean, \carlatex_if_selfexplanatory:NNnnTF looks very self explanatory to me, compared to \carlatex@ifselfexplanatory. – Manuel Nov 7 '17 at 10:14
  • 15
    @Manuel They are both obscure to me :) – CarLaTeX Nov 7 '17 at 10:18
  • 5
    This is the first time I have heard anyone describe LaTeX macro names as self-explanatory. See my rant on the topic. – Aditya Nov 7 '17 at 16:37
  • 1
    The question in the title seems very different from the question(s) in the body. The body raises various quite significant issues about differences between naming conventions in LaTeX3 and LaTeX2e — subtle and complex things which really do affect usability of a language. But the specific difference mentioned in the title — the choice of underscores vs. camelcase for making multi-word phrases into command names — is a pretty trivial one, which doesn’t affect usability much at all so long as one convention or the other is followed reasonably consistently. – Peter LeFanu Lumsdaine Nov 8 '17 at 15:47
  • @PeterLeFanuLumsdaine I'm not talking about underscore vs. camelcase in my question. – CarLaTeX Nov 8 '17 at 16:30
35

Underscores

\csSetEq wouldn't work: for such basic, internal commands you need names that a normal user can't accidental overwrite. That's why internal LaTeX2e commands have @ and context uses ! and also underscores: \c_anch_sidebars_current \c!bottomoffset.

expl3 couldn't use @ as it could to easily clash with existing commands and packages and from the other possible non-letters (!,?, *,+,...) imho underscores are not a bad choice: When you get used to it you can read many commands like sentences. \cs_set_eq = commands set equal, \tl_if_exist, \regex_extract_once.

The :NN-syntax

One problem when reading (La)TeX code is that it is very difficult to see how many arguments a command has (if any). This makes it difficult to understand the processing of a command and to debug errors due to missing or wrong argument. A command like e.g. \@sect takes 6 arguments but you have to go back to the definition to see this. With the :NN-syntax you have a much better overview.

  • 2
    Is it also partly because (La)TeX doesn't give you very nice error messages when you leave out missing arguments, too (unlike programming languages like C/etc. where you have stronger separation of commands/procedure calls)? – JAB Nov 7 '17 at 17:35
36

The function you mention has a name consisting of three parts: cs, set and eq.

  • cs is the “module name”: the function deals with functions (for definitions and things alike); cs stands for “control sequence”, probably it's not the best name, but it's too late for changing it.

  • set is the main action type; in this module there are basically three action types: new, set and gset: the first one is for globally defining new functions, checking that the name is not already used; the second and third ones do a definition or redefinition with no check, the difference is that set acts locally (in the scope of the current group), whereas gset does the definition or redefinition globally.

  • eq is how the definition is performed and stands for “equal”.

Thus the name can be read as “locally define a function to be a copy of some already existing one.

Next comes the “signature“, in this case :NN, which means that the function \cs_set_eq:NN should be followed by two unbraced function names.

Not only it makes visual syntax checking straighforward, but it is internally used for defining variants. We can compare it with what is available with other tools, standard LaTeX and etoolbox:

\let\foo\baz
\letcs\foo{baz}
\cslet{foo}\baz
\csletcs{foo}{baz}

All four perform the same task; of course, the three commands provided by etoolbox are used when one or both names need to be constructed from arguments to other macros. With expl3 we have the c argument type to denote a control sequence whose name should be formed by the token in a braced argument (internally using, of course \csname...\endcsname):

\cs_set_eq:NN \carla_foo:n \carla_baz:n
\cs_set_eq:Nc \carla_foo:n {carla_baz:n}
\cs_set_eq:cN {carla_foo:n} \carla_baz:n
\cs_set_eq:cc {carla_foo:n} {carla_baz:n}

and there's no thinking involved when the team defines them: after defining the first one in terms of primitives (\tex_let:D, but this is irrelevant), all is needed is

\cs_generate_variant:Nn \cs_set_eq:NN { Nc, cN, cc }

that you can compare with the corresponding code in etoolbox.sty:

\newrobustcmd{\cslet}[2]{%
  \expandafter\let\csname#1\endcsname#2}

% {<cstoken>}{<csname>}

\newrobustcmd{\letcs}[2]{%
  \ifcsdef{#2}
    {\expandafter\let\expandafter#1\csname#2\endcsname}
    {\undef#1}}

% {<csname>}{<csname>}

\newrobustcmd*{\csletcs}[2]{%
  \ifcsdef{#2}
    {\expandafter\let
     \csname#1\expandafter\endcsname
     \csname#2\endcsname}
    {\csundef{#1}}}

Variants are a very nice feature of expl3 and they rely on functions having a correct signature. Look for \cs_generate_variant:Nn on the site in order to get an idea of its usefulness.

23

If you have

\let\oldmacro\somemacro

but your macro names are being passed (or generated) as names so you have {oldmacro} and {newmacro} then you can go

\expandafter\let\csname oldmacro\expandafter\endcsname\csname newmacro\endcsname

but this is not very clear and when embedded in some larger set of macros is easy to get wrong and introduce weird bugs.

L3 version you just want a the variant assignment that takes two names as braced groups instead of two tokens so:

\cs_set_eq:cc{oldmacro}{newmacro}

these variant forms are either provided or can be easily generated for any command that ends in :NN you can specify a cc variant or a :Nx variant (where the second argument is edef-expanded first) etc.

The choice of _ rather than camel casing is less structural it's a design choice, but camel casing works less well as you can not stop camel cased commands being used mid document, but _ is set up like @ in plain tex and latex2e, as only a letter in code sections.

  • Why don't go on using @ instead of _? – CarLaTeX Nov 7 '17 at 7:49
  • 12
    @CarLaTeX (a) Frank had already chosen _ before I started using this syntax in 1992. (b) it was intentionally different so humans notice it is different and (c) so you don't get accidental clashes with old code and (d) \cs_set_eq is in fact more readable as words than \cs@set@eq especially as 2e code sometimes uses @ as a word separator sometimes as a vowel replacement \css@t@q and sometimes tacked on the end \csseteq@@ – David Carlisle Nov 7 '17 at 7:52
  • 10
    @StevenB.Segletes camel_casing:D – David Carlisle Nov 7 '17 at 11:33
  • 2
    @DavidCarlisle: It is easy to forget that work on LaTeX 3 started more than 25 years ago! – Aditya Nov 7 '17 at 16:40
  • 1
    @Aditya They didn't have Will/Bruno/me for a while ... – Joseph Wright Nov 7 '17 at 17:08
10

You should not compare to user code like \let\command\original but to some internals. You seem worried as if you might need to use those commands on a daily basis. That is internal code. The same way we have internal code right now that you might be afraid of too.

This is the code that makes primes work as you expect: f'(x) and f'''(x) work because of this

\def\active@math@prime{^\bgroup\prim@s}
{\catcode`\'=\active \global\let'\active@math@prime}
\def\prim@s{%
  \prime\futurelet\@let@token\pr@m@s}
\def\pr@m@s{%
  \ifx'\@let@token
    \expandafter\pr@@@s
  \else
    \ifx^\@let@token
      \expandafter\expandafter\expandafter\pr@@@t
    \else
      \egroup
    \fi
  \fi}
\def\pr@@@s#1{\prim@s}
\def\pr@@@t#1#2{#2\egroup}

A similar expl3 version would be

\cs_new_protected:Nn \math_prime: { \math_superscript:w \math_prime_next: }
\cs_new_protected:Nn \math_prime_next:
 {
  \math_prime_symbol
  \peek_charcode_remove_ignore_spaces:NTF '
   { \math_prime_next: }
   {
    \token_if_eq_meaning:NNTF \l_peek_token \c_math_superscript_token
     { \math_prime_remove_superscript:Nn }
     { \math_superscript_end: }
   }
 }
\cs_new_protected:Nn \math_prime_remove_superscript:Nn { #2 \math_superscript_end: }
\char_set_active_eq:NN ' \math_prime:

With expl3 it seems much more self-explanatory (although you might need to learn a bit). In fact I think this kind of code makes internals much more accessible.

PS: I haven't checked if the code is right, and it doesn't compile, as it does make use of some commands that are not defined, but the idea is to show that it actually shows a bit more of what's happening than those \pr@@@t and \pr@@@s.

  • 1
    \math_prime_symbol misses a : :) – clemens Nov 7 '17 at 11:09
  • @clemens I thought of it similar to \c_math_superscript_token, then \.._symbol could be another “type”. But yes, I was just showing an example, it doesn't compile, and it's far from what has to be done with unicode fonts. And I used also commands that haven't yet been decided by the LaTeX3 team. – Manuel Nov 7 '17 at 11:10
  • 1
    In that case it is a variable and some scope descriptor is missing, e.g., \l_math_prime_symbol – clemens Nov 7 '17 at 17:02

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.