I propose a new DocC directive,
/// The sample variance of the collection. /// - Returns: The sample variance: /// @Math("sample-variance.xml", description: "Sum, from i = 1 to n, of the squared norm of x_i minus mu. Everything divided by n minus 1.") /// where 𝑛 is the collection's `count` and ‖𝑥ᵢ - 𝜇‖ is the Euclidean distance from each element 𝑥ᵢ to the sample mean 𝜇. func sampleVariance …
Which would output something like this:
Documentation pages often need to include mathematical expressions. For example, Apple's documentation pages for Accelerate (which are made with DocC) are enriched by equations and matrices that help clarify the documentation's text.
Although adding mathematical expressions to DocC documentation is already possible, all current approaches are insufficient.
- Unicode math is usually enough for expressions containing a single row, such as ‖𝑥ᵢ - 𝜇‖². But expressions containing multiple rows tend to be unreadable or to not look good in Unicode math. For instance, the best we can do for the expression in the TL;DR above is ¹⁄₍ₙ₋₁₎ ∑ᵢ₌₁ⁿ ‖𝑥ᵢ - 𝜇‖². And, many times, multi-row expressions are impossible to represent in Unicode math. For example, there are no superscript Greek letters in Unicode. Matrices are also impossible.
- We can compile typeset math (.tex for LaTeX, or .xml for MathML) to an image (say, .png or .svg). This requires 2-3 files that must be kept in sync: the image in light mode, the image in dark mode, and optionally (but ideally) the source file. This is the approach that the Accelerate docs use (sans the dark mode support).
- We can use this trick, which is what I personally prefer, but it comes with disadvantages of its own (detailed in the linked post).
Therefore, first-class support for mathematical typesetting would be a welcome addition to DocC. There are many different ways of going about this, so I'm making this post for us to discuss potential solutions. I’ll include my personal preference, then some alternative approaches.
Keep it simple: write MathML, output MathML. DocC outputs a webpage; I think we should embrace this fact and stick to web standards when possible. MathML's syntax is more unwieldy than LaTeX's, but this solution:
- Adds no dependencies, e.g. on MathJax or KaTeX.
- Avoids the performance concerns of compiling LaTeX to SVG (or LaTeX to MathML, or MathML to SVG) at runtime. Concerning the first two cases (LaTeX to SVG and LaTeX to MathML), MathJax is infamous for the lag it can cause when there are many equations on-screen.
- Adapts to light/dark mode with no extra work, since MathML elements use the current font color. Try it out: inspect a DocC webpage, add a
<math>with some MathML, then toggle between light mode and dark mode.
- Is the easiest to implement and maintain. After checking that the source MathML is valid, DocC would just have to paste it unmodified into the webpage.
Also, any approach in which the output is MathML (regardless of whether the input is MathML or LaTeX) will have great accessibility, since users can navigate a
<math> equation with a screen reader. This is better than just having an alt text, which is the best we can do until DocC supports mathematical typesetting. (That said, MathJax's support for screen readers is also very good.)
As a future direction, we can consider also supporting LaTeX as a source language. If we do, I believe we should compile the .tex to MathML (not to SVG, PNG, etc.) for consistency and for best accessibility. Also, we should compile the source LaTeX to MathML while compiling the documentation (i.e. not at runtime via MathJax or KaTeX) for lighter documentation webpages and to avoid performance concerns.
Swift Markdown (used by DocC) recognizes some HTML tags since it uses GitHub-Flavored Markdown. But the HTML tags in the GHFM spec don't include any MathML tags, and even if they did, DocC ignores any HTML in the documentation comments. So we could change Swift Markdown to also recognize MathML, then change DocC to not ignore MathML tags as an exception to its "no HTML" rule.
This approach would be needlessly complicated and would require a Swift package that has nothing to do with DocC to break from its spec. It would also lead to bloated documentation comments:
/// The sample variance of the collection. /// - Returns: The sample variance: /// <math> /// <mstyle displaystyle="true"> /// <mfrac> /// <mn>1</mn> /// <mrow> /// <mi>n</mi> /// <mo>-</mo> /// <mn>1</mn> /// </mrow> /// </mfrac> /// <mspace width="5px"/> /// ... /// </math> /// where 𝑛 is the collection's `count` and ‖𝑥ᵢ - 𝜇‖ is the Euclidean distance from each element 𝑥ᵢ to the sample mean 𝜇. func sampleVariance …
Way too complicated, and would also lead to bloated documentation comments. We could alternatively write a Swift DSL similar to John Sundell's Plot that wraps MathML instead of HTML, which would make MathML less annyoing to write, then typeset documentation math on a separate
.swift file using the DSL. But DocC is intended to be language-agnostic, and this approach would still be more complex than necessary.
Mostly already covered. This could lead to insufficient accessibility, and we'd have to either:
- Make DocC dependent on an existing MathML-to-SVG compiler.
- Write our own.
This approach's motivation is the concern that MathML has insufficient cross-browser support. While true historically, MathML Core is now supported by all major browsers.
We have three options:
||Documentation writers can preview their MathML while writing it: open the
||If a file only contains MathML, it wouldn't be quite correct for it to be
||Most descriptive extension. Lets writers know exactly what is allowed in the file.||Not a real extension. Anyone who tries opening the file would be greeted with something like "There is no application set to open the document". No syntax highlighting.|
||No preview capabilities, now or ever.|
Given the trade-offs above, I believe
.xml is the best choice. The lack of file previews is not a big deal thanks to DocC's