KotUniL = SI Units + Kotlin. Part Two: Advanced Features

Dr. Viktor Sirotin
7 min readJan 29, 2023
Arrangement of the principal measurements in physics based on the mathematical manipulation of length, time, and mass. Source: Wikipedia

This is the second article in a series of articles about the magic of dimensions and Kotlin on the example of the KotUniL library.

These are the articles of this series:

KotUniL = SI Units + Kotlin. Part One: Introduction to KotUniL

KotUniL = SI Units + Kotlin. Part Two: Advanced Features (this)

KotUniL = SI Units + Kotlin. Part Three: When only one unit test is enough

In the first article we considered how not to crash spacecrafts with this library :-).

In this article we will consider less obvious, but no less interesting features of the library.

Pretty print

We start with a nice printout of the results of our calculations. The SI standard (see https://en.wikipedia.org/wiki/International_System_of_Units) has strict guidelines for this, which the library tries to implement to the best of its ability:

val s = 4.m * 5.m
assertEquals("20 m2", s.show("%.0f"))
val x = 20.l
val format = "%.2f"
assertEquals("0,02 m3", x.show(format))
val h = x/s
assertEquals("0,001 m", h.show("%.3f"))
val y = 3.1415927.m
assertEquals("3,142 m", y.show("%.3f"))

Ways to set the basic SI units

As you know, the SI system defines exactly 7 physical units with which it is possible to measure and model all objects and processes of our world (see https://en.wikipedia.org/wiki/International_System_of_Units).

Here is this list:

SI base units. Source: Wikipedia

Let’s look at how you can set physical quantities in KotUniL using one second as an example (the equations below show different ways to set a physical quantity “the size” of one second):

s == 1*s
1*s == 1.0.s
Second(1.0) == 1.s

Derived SI units

The SI standard defines 22 derived units in addition to the seven basic units. They are listed in the table below.

SI derived units with special names and symbols. Source: Wikipedia

Don’t be surprised if you come across characters of the Ω type that are unusual for identifiers in this table and in the KotUniL library. This is possible because, according to the Kotlin specification, most common Unicode characters can be used in Kotlin identifiers (see paragraph “1.2.4 Identifiers” in the Kotlin specification). Derived units can be defined and used in the same way as base units. Variables from both groups can be used in formulas by multiplication or division.

Don’t be surprised to see the ^ symbol. Kotlin doesn’t have an operator for multiplication (taking the root), but it does have the function pow(a, b). KotUniL has been extended with an infix function with the same semantics. Unfortunately, you can’t set the correct priority for this function with this trick. Although it looks like a “real” operator, you have to enclose it in parentheses to maintain the correct priority of the operation.

To get a closer look at programming derivative units, let’s look at a real-life example.

Newlyweds Sasha and Natasha decided to go on a nature trip. They took a solar panel with them. When they arrived at the place Sasha immediately turned it on. The solar panel worked for two hours producing 12 volts at 7 amps. The generated electricity was stored in a portable battery. The storage efficiency was 85%. After that, Natasha decided to make tea. To make hot water for tea with a 500 watt kettle, the water has to be boiled for 8 minutes. The question is, is the accumulated electricity in the battery sufficient for this?

Let’s write a simple code using KotUniL:

val producedElectricity = 12.V * 7.A * 2.h
val savedElectricity = producedElectricity * 85.`%
val neededElectricity = 0.5.kW * 8.min
val dif = savedElectricity - neededElectricity
assertTrue(dif < 0.W*h) //comparison of KotUniL units
assertTrue(dif.value < 0) //comparison of dimensionless values

Note that we use the % symbol here for convenience. This is also a Kotlin extension in our library.
Regarding this and a number of other similar extensions, consider a quote from the specification: “Kotlin supports a way of specifying identifiers by enclosing any sequence of characters in a backsign (`) character, which allows any name to be used as an identifier.” (See paragraph 1.2.4 “Identifiers” in the Kotlin specification.)
Very important: The backtick (`) character (UTF-8 code U+0060) does not equal the apostrophe characters on your keyboard (UTF-8 code U+0027). If it’s not on your keyboard, copy it directly from this example.
Most derived units can be derived from base units or from other derived units in various ways.
Consider the example with SI-Unit Tesla:

assertEquals(T, kg * (s `^` -2) * (A `^` -1))
assertEquals(T, Wb/m2)

Own derived units

You can use KotUniL to determine your own derivative units.
Consider a not quite scientifically sound example. Let’s imagine that the rate of snow melting in the mountains is proportional to the duration and temperature above 0 °C and equals 10 microns per hour per degree. This would be our new derivative unit. If the current snow thickness is 10 cm, what fraction of it will melt in 5 hours at 20 °C?
The code below also demonstrates a nice side of Kotlin — the ability to use Unicode characters, such as Greek letters.

val ζ = 10.μm/(h*K) // ice melting rate
val τ = 10.cm
val t = 20.`°C`
val ξ = 5.h*(t - 0.`°C`)
val σ = ζ*ξ //level of melted snow
val α = σ/τ //relation of melted snow to the initial one
assertEquals(1.0, α.`as %`, ε) // Representation of the ratio in percent

Note how the result of the calculation can be represented as a percentage: α.`as %` is the ratio represented as a percentage.

ε is some small value for the tolerance when comparing double numbers. This is also one of the variables defined in KotUniL.

SI prefixes

The SI system defines prefixes that we have been accustomed to using since childhood, often without thinking about it. We measure room sizes in “pure” meters, smartphone sizes in millimeters, and distances between cities in kilometers.

Depending on the subject domain, it is often convenient to work with unit prefixes rather than pure ones. Each prefix has its own name and abbreviation as a symbol.

KotUniL implements all prefixes provided by SI standard. Here is their complete table.

SI prefixes. Source: Wikipedia

In the example below, we verify that one kilometer equals one billion micrometers.

val d = km - (10 `^` 9) * μm
assertTrue(abs(d.value) < ε)

Non-standard units

The SI standard recognizes as acceptable a number of units that have historically gained a place in human practice, such as minutes, hours and days for time, square and cubic meters, etc.

The table below gives an idea of these units:

Examples of coherent derived units in terms of base units. Source: Wikipedia

Example:

A city park has an area of 2.35 hectares. When it rained, 1 mm of water fell from the sky.

If it had not rained, the park would have needed to be watered with water from car cisterns. One car tanker can hold 4 tons of water. How many cisterns would be needed to achieve the same effect as if it were raining? Reminder: the density of water is 1 kg/l

val s = 2.35ha
val ω = s*1.mm // Total volume of water falling from the sky
val ρ = kg/l // Water density
val τ = ω * ρ // Total weight of rainwater
val n = τ/4.t
assertEquals(5.875, n.value, ε)

Let’s add currencies

To widen the library’s scope, thirty of the world’s most popular currencies have been adjoined with physical units as independent units:

Again, this is the last example:

A homeowner decided to tile one of his rooms.

He bought 16.5 square meters of tiles at a price of 52 € per square meter. How much did he pay for the tiles?

val prise = 52.`€/m2
val s = 16.5*m2
val cost = s*prise

Well, here we have got acquainted with the advanced features of KotUniL library.

Let me remind you that the way of connecting it to your project is described in the previous article of this series.

In the next, final article in the series, I will try to talk about some of the “magical” features of the SI system and their impact on the design of the library.

Illustration: A system of basic measurements in physics based on the mathematical manipulation of length, time and mass. Source: Wikipedia

--

--

Dr. Viktor Sirotin

I love programming, UML, model-driven software engineering, DSL, philosophy, mathematics, modern history and really good music. My homepage: www.sirotin.eu