Skip to content

Instantly share code, notes, and snippets.

@user202729
Last active January 9, 2022 12:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save user202729/ac86cfcb3e9e538c0d8426dd85b731e3 to your computer and use it in GitHub Desktop.
Save user202729/ac86cfcb3e9e538c0d8426dd85b731e3 to your computer and use it in GitHub Desktop.
TeX-notes.md

.some notes.

Why TeX, as a programming language, is so hard?

There are some issues with TeX. Not that it's a expansion language.

  • It has a few quirks in behavior that will take you hours of debugging if you don't know them in advance.

    Example

    It may be worth it to spend a few hours reading the TeXbook the first time, that may help you avoiding the issues.

  • It uses "global variables/states" extensively.

    This is actually not an issue (in "normal" cases it greatly shorten code), but for complex tasks the user need to understand much of the details how TeX works to make modifications.

  • Not everything is expandable.

    This doesn't make TeX hard, but it does make TeX tedious, in that

  • It's not possible to parse TeX source code without executing it.

    Combined with the fact that by default TeX grabs arguments unexpandably, this is a huge problem.

    (as mentioned below, it does not make tasks impossible, but it does make it difficult to write correct code that handles all corner cases.)

Surprisingly, that it is a macro expansion language is not really the issue.

I don't know Lisp, but I know some similar Lisp-like languages with the "code is data" concept. (of course, the comparison isn't really fair as the other languages aren't used to typeset text, and definitely not for typesetting text in a way that makes the source code concise)

Consider Mathematica:

  • Variables and functions are the same thing.

  • It can do expansion before or after assignment.

    Compare a = b (evaluate b, then inject the result into a) and a := b (define a to be b).

    In some respect, = is similar to TeX's edef and := is similar to TeX's def.

    The large difference is that the evaluation value of b in the first case is identical to that if it were evaluated independently; while in TeX it's evaluated in an expansion-only context.

    Actually, if you think about it, TeX has a good (and very simple) reason to make some things not expandable by default: normally you don't want to do the typesetting work when you assign/pass the result to something else.

    Consider \edef \a {\hbox { \b }}. In "typical" cases you want \b to be expanded and \hbox to not be expanded.

    Similarly \edef \a {the section is \the\c@section} (normally you want to define \a as the section is 1, not to typeset the text then define \a to be empty.

    TeX does provide a primitive \noexpand to temporarily prevent expansion, but there's nothing that "temporarily allow executable things to expand". (until LuaTeX has \immediateassignment, but things like hbox have to wait)

    Remember that Knuth never intend anyone to do "complex programming tasks" in TeX, only as a typesetting engine, so it was not designed for the former purpose.

  • Functions can either choose to evaluate the arguments or not.

    In TeX, all functions does not pre-evaluated the argument, but it's possible to define variants that x-expand the argument.

    Unfortunately compared to Mathematica, TeX cannot evaluate everything so it isn't really possible to nest things comfortably. (have to store intermediate result into variables)

  • Inject evaluated value into expression is "nontrivial".

    It even has a name "Trott-Strzebonski in-place evaluation technique": evaluation - Replacement inside held expression - Mathematica Stack Exchange

    Surprisingly, this feature is not directly supported by the kernel, it uses some quirk of the way the kernel evaluates code.

  • It has special syntaxes ("verbatim" – actually just string, etc.).

    This one Mathematica is much better than TeX that it parses the whole thing in advance, so there's no annoying catcode bug.

    On the other hand it's not possible for functions to define custom input format, but since it's possible to pass string to functions and Mathematica core syntax is already very expressive this isn't a particularly important issue.

  • It has Block to "temporarily backup" value of variables.

    This is similar to TeX's grouping mechanism, but it can "selectively" backup and restore.

    Note that Mathematica is also macro-expand-only (it does not have real functions!), but it doesn't matter because

    • Usually you don't have to be concerned with "one-step expansion"
    • There's no distinction between expansion and execution.
  • It has Module to create a closure-like environment.

    This is like TeX's manual prefixing of commands, but the TeX way is more tedious.

  • Nonlocal error messages

    This one I don't know, I hardly encounter errors in Mathematica if I recalled correctly.

    Although the truly "hard to understand" error messages in TeX are the ones concerning the syntax of TeX, so with a cleaner syntax it would not happen at all.

    Example:

    This one you will encounter something like "Missing { inserted", and you need to understand how ^ works (in the processing engine) to understand what it does.

  • While it's possible to implement a stack for saving and restoring values like TeX's \begingroup ... \endgroup (which is roughly similar to Block[...] in Mathematica), it's not a built-in functionality, so there would be no ambiguity like "what should \begingroup do".

Why is TeX source code hard to read?

  • The fact that some things are not expandable makes source code longer.

    For the same reason why assembly is harder to read than C (you have to store all temporary values into registers, and recall the same register later), that if you want to use temporary values in TeX that requires non-expandable computations,

  • It's very space-sensitive, thus programmers tend to squeeze code together.

    (fixed in expl3 programming environment)

    This actually isn't that bad, but the fact that both the backslash and the control sequence name is highlighted with the same color on my text editor makes it extra bad.

    Compare:

     if x is equal to 0:
     	print the value of x
    
     \if\x\is\equ@l\to\zer@:
     	\print\the\v@lue\of\x
    
     ifzxziszequalztoz0:
     	printzthezvaluezofzx
    

    The backslash is "halfway" dense between normal character and the @, so it doesn't really stand out. In comparison, the blank space is very light.

  • It has no local scope, so there's a lot of module-prefix clutter on the screen.

    Actually, in dtx files, the unique prefix is represented by something like @@ which is translated to the correct prefix while "compiled" (or so I think?) so maybe it isn't that bad.

Why is it so hard to do task X in LaTeX?

By design, LaTeX is designed so that tasks it supports is easy, and tasks it does not support is hard.

Although LaTeX is not a single thing, it's a collection of packages written by several people.

Example:

It does that by providing packages, so "in theory" you only need to learn the interface to use the packages; but in reality, the way TeX works make writing correct package code difficult.

Example Square brackets in listings caption - TeX - LaTeX Stack Exchange

To understand how to "fix the issue" it may be necessary to understand how TeX works in low level and/or read the source code of the packages, which is not always easy.

Reference:

Other interesting read

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment