Request for ratio constructor from numbers; Why are ratios considered a different type to floats?

They seem pretty indistinguishable to me. Why not make percentiles a syntax sugar for floats? Rather than 50%, I hope I could write 0.5 or 1/2.

The ratio type is inherently linked to the layout design. See relative.

The float type is for a completely different usage.

You shouldn’t have any issue writing 0.5 or 1/2. Are you having trouble with something? See the float docs.

1 Like

You can do this, if you really want to:

#let r(f) = 100% * f
#r(0.5)

I do have issue writing 0.5 .

In which case, can you reproduce the issue and share the problematic code? Without more details, I’m afraid no one can help you!

The document goes like this:

This type is a combination of a length with a ratio.

Why not make it a combination of a length with a float? Is the % used as type annotation?

Sure. I was posting other info back then.

#scale(0.5, $sigma$)

There is more docs coming in the next version: How to draw a decorative frame (rect with concave corners) around text? - #6 by Andrew

Yeah I understood that. However it seems when a ratio needn’t be distinguished from floats in such use cases. Currently does Typst have operator overload? Is this design choice used to prevent + needing to be overloaded?

According to the Ratio Type documentation, ratios are:

a number, followed by a percent sign.

So yes, the % sign is used to indicate this data type.


Combining @Andrew’s function with your use case:

#let r(f) = 100% * f
#scale(r(0.5), $sigma$)

One thing that stands out to me is that a float could be between 0 and 1, but it can also be any other number. Also, if we consider 32 bit floats, adding 0.2 + 0.1 does not equal 0.3, whereas 20% + 10% does equal 30%:

#(20% + 10%)\ // equals 30%
#(0.2 + 0.1)  // equals 0.30000000000000004

Yeah. however when placing elements, such small errors can be ignored since they will be rounded to the nearest pixel, and in such scenarios it makes sense to write -100% or 125%.

1 Like

The same applies to ratios though, e.g. -200% is a valid ratio.

That’s true of the 64-bit floats in Typst too. But it’s also true of ratios: 20% + 10% prints as 30% but it’s not really 30%: #(10% + 20% == 30%) gives false.

2 Likes

As far as I can see, it’s true that floats and ratios are functionally redundant. But it’s nice to have distinct types for semantically different values. And having different types means that functions can interpret the values differently.

For example in the standard library, the Oklab color space has two axes (a and b) that normally take values between -0.4 and 0.4. It’s nice that you don’t have to remember that: in Typst you can do

#square(fill: oklab(30%, 100%, 50%))

and it will mean the same as

#square(fill: oklab(30%, 0.4, 0.2))

There’s another example in the CeTZ library: you can specify a coordinate as (A, x, B). If x is 0.5, it means “From A, move 0.5 (of a length unit) in direction of B”. But if x is 50% it means “50% of the path from A to B”:

#import "@preview/cetz:0.3.4"

#cetz.canvas(length: 2cm, {
  import cetz.draw: *
  let A = (0, 0)
  let B = (3, 0)
  line(A, B)
  content((A, 0.5, B))[1]    // 0.5 Ă— 2cm
  content((A, 50%, B))[2]
})

image

It also helps when reading code and looking at object fields: the percent gives some context that this floating point value plays the role of a ratio.

4 Likes

That’s a good point.

I think it would be clearer if such types are constructed by ratio(x) rather than %. Do people actually find this notation intuitive? In such scheme it is cumbersome to write 100% / 3.

For me at least yes it’s extremely intuitive :slight_smile:

1 Like

Seems weird to me that ratio doesn’t provide a constructor:

The r function here looks very weird to me.

The same reason there is no pt constructor. Just multiply a number by the unit.

#let ratio(a) = 100% * a
#ratio(5)

#let pt(a) = 1pt * a
#pt(5)

It’s explicit and I use it when needed.

I expect more from ratio: 100% isn’t a unit. It IS a number, just cast into a special type.

Especially wrt OKLab I find this misleading. OKLab is designed as a perceptual color space, with distances modeling perceptual contrast. Normalizing a/b seems wrong from a design perspective. Also, -0.4 and 0.4 may be the boundaries, but there is no lightness l for which any of oklab(l, {0,100}%, {0,100}%) is actually valid. IMO, the ratio obscures this fact which is a consequence of actual human vision.

Hi @AprilGrimoire, moderation question: this topic is currently under Questions; was that on purpose or would it fit better under General? The basic difference is that question topics are typically concluded when the “correct” answer has been uncovered, while general discussions show different points of view. This feels like it could be both and I don’t want to just move this without consulting you, OP.

1 Like