1

[Please take this question for a moot point/an "academical" issue.]

The LaTeX-kernel-command \newcommand was invented decades before expl3, xparse and \NewDocumentCommand were available.

\newcommand brings along the concept of an optional argument whereby tokens forming an optional argument need to be nested between [ and ].

With macros defined in terms of \newcommand that process optional arguments, only the presence of an opening square-bracket [ is detected as an indicator for the presence of an optional argument. The presence of a matching ] is not detected.

In short you can say:

With this concept, indicator for the presence of an optional argument is the presence of an opening square-bracket [. The optional argument itself is delimited by ].

Delimiting optional arguments (by ]) can be a source of problems, e.g., (]-)delimiter-matching when it comes to nesting optional arguments within optional arguments without being aware of the need of nesting the entire content of an optional argument between curly braces.

My question is:

Why was it decided to have optional arguments not only preceeded by a specific character-token ([12) but also delimited by another specific character-token (]12)?

Why optional arguments as delimited arguments?

Why optional arguments as ]12-delimited arguments?

If delimiting was omitted, one could, instead of a preceding [, have chosen, e.g, a preceding ? for marking the presence of an optional argument.

Syntax of a macro \mymacro processing an optional argument would be:

\mymacro?{optional}{non-optional} respective \macro{non-optional}.

(There not being a delimiter implies there not being problems with missing delimiters or delimiter-matching in case of nesting things.)

5
  • 1
    Honestly, I don’t find \mymacro?{optional}{non-optional} to be a particularly intuitive syntax.
    – Gaussler
    Oct 7, 2021 at 14:10
  • What we really should do is make [ and ] globally active and define them to be what is currently [{ and }]. This would work fine with xparse if o is redefined to be d[] with [ and ] active.
    – Gaussler
    Oct 7, 2021 at 14:14
  • @Gaussler Why? active [ and active ] would still be treated/removed as parameter-text/argument-delimiters and therefore would never be carried out... Besides this: How to define a macro whose toplevel-expansion yields unbalanced curly braces? With macros you always need brace-hacks for removing/neutralizing braces and this way creating a set of unbalanced braces.Brace-hacks in turn imply several expansion-steps. Oct 7, 2021 at 14:22
  • I would do \def[{\oldleftbrack\bgroup} and \def]{\egroup\oldrightbrack}. Commands defined with xparse are perfectly able to respect balanced brackets, and meanwhile, stuff like \foo[key=\baz[other key=2,some third key=3]] now works without issues.
    – Gaussler
    Oct 7, 2021 at 14:27
  • @Gaussler I don't see why adding \bgroup in the definition of an active [ would really help parsing nested [] as you say, xparse doesn't need that and it wouldn't help hide the , in your nested key list (well depending on the implementation I suppose it might help a bit, but that isn't at all clear) Oct 7, 2021 at 16:52

1 Answer 1

5

As a historical note, the second optional argument to \newcommand was actually a later addition to LaTeX, first appearing in LaTeX2e. LaTeX 2.09's \newcommand did not have that facility. So optional arguments, in fact, predate that mechanism as well.

But the historical note is of more than just academic interest in this question: it actually goes a bit towards explaining the decision process here.

The kernel code for commands like \section, \caption and even \newcommand itself shows the original implementation of such features which involved multi-step processing of input spread across multiple macros (which is how we get \section calls \@startsection which calls \@sect or \@ssect depending on whether there's a *). Add in the fact that when LaTeX was first created, 16-bit addressing for TeX's main memory was the norm (meaning that there was really not that much space for macro definitions). “Big TeX” which changed that to 32-bit addressing was first introduced in the late 80s and I don't think it became normalized until the 90s at the earliest (I once tried to find the original Big TeX article in TUGboat but it's a difficult to Google subject).

So given all of that, and the challenges of programming in TeX's macro language, Lamport went for simplicity in implementation (thus [₁₂]₁₂ and not, say, [₁₃]₁₃ which also risked making non-optional-argument uses of brackets a challenge) as well as ergonomics for users (having the choice of delimiting arguments with [] or {} makes for an easily observed distinction between the two which is not quite the case by using a prefix flag like ? not to mention that while * is uncommon in text and mathematics so it's unlikely that \somecommand* would be intended to mean execute \somecommand and then typeset * but not unlikely that someone might want to write, e.g., How long have you been using \LaTeX?).

As the sophistication of TeX programming has grown in the last 35 years, it's not unlikely that someone who were attempting to recreate LaTeX from scratch today could in fact allow, say, \section[$\sqrt[3]{x}$]{Cube roots} to be correctly parsed, but doing so would almost certainly break backwards compatibility.¹


  1. Which makes a good case for the idea that the decision to extend LaTeX2e rather than release a potentially breaking LaTeX3 was not the best choice. Backwards compatibility can be a heavy burden to carry.
1
  • 1
    I'm not sure I agree with the last para or its footnote. \section is defined by a class not core latex and if a class defines it using \NewDocumentCommand and nested [] works that probably won't break too much, just as in earlier latex \sqrt was fragile so would have failed there but is robust in recent releases. Making an error situation be a non error is one of the safer changes that you could contemplate. Oct 7, 2021 at 16:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .