Unwanted space around user-defined commands in math mode

I want to define a new command diff to denote the upright “d” that should be used in mathematical expressions like $f(x) dx$, $dx times.o dy$, etc.

I put let diff = math.upright(d), but I noticed that the visual output of (say) $diff x times.o diff y$ is different than those of $upright(d)x times.o upright(d)y$. The first version comes with some unwanted spacing around the “d”.

So, my questions are:

  1. How can I avoid that?
  2. What is the difference between:
  • let diff = upright(d);
  • let diff = math.upright(d);
  • let diff = $upright(d)$?

I have looked at this question but it left me more confused than before.

I know that the differential “d” is probably already defined in the physics package, but I’m trying to get a better grasp of the language.

1 Like

The first one doesn’t compile because upright is just a math function, it’s not a top level name in std.

The second one doesn’t compile because I think you mean either let diff = math.upright[d] or let diff = math.upright("d") where the first one takes [d] as typst markup and gives the text “d”; and the second one takes a string “d” and also should give the same result “d”.

To explain why the second one doesn’t give the same result as $upright(d)x$ we have to realize that d in typst markup and d inside a math equation don’t produce the same thing. In an equation it produces a symbol, that’s styled differently than text.

What you are looking for is actually built into typst under the name math.dif and we can mimic its definition like this:

#let diff = $thin upright(d)$

with only one difference - the built-in dif uses a weak space before the d, not a “strong” space.

So the short answer is that you should use a “d” that’s defined as a symbol or in math mode, and then it will behave correctly. Here’s a few equivalent ways of doing it…

#let diff = math.upright[\d]
#let diff = math.upright($d$)
#let diff = $upright(d)$
#let diff = math.upright(math.class("vary", "d"))  // Honestly, not sure about this one. It works... but why? :)

And to learn from the built-in definition, it’s good to have a weak space in front of it to have nice spacing when typesetting something like f(x) dx.

In summary, mimic the built-in dif exactly:

/// weakspc: take a h spacing and make it weak
#let weakspc(spc) = { h(spc.amount, weak: true) }
#let diff = $weakspc(thin)upright(d)$
#(math.dif == diff.body)  // returns true
3 Likes