(Opinions needed) Likely upcoming changes to math mode precedence

First, thank you for considering my arguments this late in the release schedule. I appreciate your measured reply.

I still think that keeping functions composable is preferrable to the decrease in readability, and I still disagree that option B is more predictable.

On option B being less predictable, no one in this discussion so far has mentioned the behavior of function syntax on the left side of an attachment. In option B, why does abs(a)^b work, but not a^abs(b)?

Or why, when I remove the space before the parens in the next expression, does the function call act like one element? √abs (a)^b groups as √(abs) (a)^b, while √abs(a)^b groups as √((abs(a))^b). If option B were fully consistent, we should require parens around the call for it to work.

So I still disagree, but this is becoming more of an argument in taste than in truth. And at this point I don’t really expect to change your mind.

So if you want to go with option B, I can accept that.

3 Likes

Typst 0.14 was supposed to fix the long-standing issue that $f_i(x) renders the (x) in the subscript. The relevant change was made in Require parentheses in all function-like sub/superscripts by mkorje ¡ Pull Request #6442 ¡ typst/typst ¡ GitHub after lengthy considerations and discussion spread across Discord and here in this thread.

However, a new case that hasn’t previously been considered and whose behavior has regressed with #6442 has now come to light in discussions on Discord (specifically the parsing precedence in $ 1 / f_a(x) $).

There is a potential fix for this issue in Math mode implicit function call update and parser refactor by isuffix · Pull Request #7072 · typst/typst · GitHub. However, that PR only revealed deeper issues with the design and we’re not confident that it is the best we can do for Typst.

As we don’t want to put the burden on users to migrate their documents twice, we have thus decided to revert and postpone the change. That said, we are still committed to fixing the rendering of $f_i(x)$.

In particular, we are planning to prioritize a more holistical reconsideration of all edge cases and issues of the current math syntax, so that we can make one confident change rather than spread-out, disruptive fixes.

The revert is being made in Revert math precedence change by laurmaedje ¡ Pull Request #7084 ¡ typst/typst ¡ GitHub.

14 Likes

I believe that aiming for syntactic parity between code mode and math mode is the ideal approach.

By the way, introducing the ^ operator for exponentiation in code mode would further harmonize the two syntaxes. By adhering to these standard (mathematical and programming conventions), precedence rules would become intuitive and unambiguous.

For example, the parsing of $ 1 / f^a(x) $ in math mode should structurally mirror 1 / calc.pow(f, a(x)) in code.
And, the parsing of $ 1 / f^a (x) $ should mirror 1 / calc.pow(f, a) * x in code.

Achieving this symmetry would facilitate the creation of libraries that handle algebraic entities and operations (such as simplification and factorization) by allowing them to traverse the math AST more predictably. This is an important feature for users interested in ‘active documents’, using Typst not just for typesetting, but for maintaining a single source of truth where equations are both rendered and computed.

For instance, this could enable an API where math markup is evaluated directly, e.g. : evaluate($E = m c^2$, scope: (m: 0.001, c: 3e5)) which could also be rendered.

3 Likes