> ## Content Index
> Fetch the complete content index at: https://blogs.remobjects.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Units of Measure
- URL: https://blogs.remobjects.com/2026/07/24/units-of-measure/
- Published: 2026-07-24T23:35:12.000Z
- Updated: 2026-07-24T23:35:12.000Z
- Author: marc hoffman
- Tags: #Import 2026-08-17 20:17

This week's Elements build adds a major new feature that I personally have been dreaming of adding to Oxygene for well over a decade; we just never got around to it. Well, now we did.

One of the great things about Object Pascal (and other true OOP languages) is that it is strongly typed. You cannot just assign a `String` to a `Button`, the compiler won't let you. This leads to safer code that is validated at *compile* time rather than at runtime. But there's one area where Object Pascal has let us down until now, and that is numbers. Numbers can mean a great many things. `100` can be a lot, or really little, depending on context.

Let's just take one common example: `fEvent.WaitFor(aTimeout: Integer);`. Ok, cool, but what unit is this integer in? Will it be too quick if I pass `1` because it's milliseconds, or will it wait forever if I pass `1000`, because it expects seconds? Who knows 🤷‍♀️. *Maybe* it's in the documentation. But the *compiler* certainly has no idea, and can't help you.

Until now.

Oxygene 13 adds two new fundamentals to the language: *dimensions* and *units*.

A *dimension* is the abstract concept of something that can be measured by a number. For example, **distance**. A *unit* is a concrete, well-defined way to measure a dimension. For example, **meters**. Or **furlongs**. Or **football fields**, if you're American.

```oxygene
type
  Distance = public dimension(Double);
  Meters = public unit(Distance) as m;
  Yards = public unit(Distance) as yd;

```

This code defines a new dimension that represents distances, as well as two concrete units.

```oxygene
var x: Meters := 5;
...
var y: Yards := x;
```

In the past, we'd have a problem here that we'd not find out about until someone runs our app and notices that the numbers are off by 0.9144\. Not ideal. But now that we have strongly-typed units, the *compiler knows* your code is about to mess up, and can do something about it.

But what? The simplest idea would be to warn (or error) to let you know about your mistake. But we can do better than that! What if instead Yards were defined as follows?

```oxygene
type
  Yards = public unit(Distance) as yd = 0.9144m;
 
```

Now the compiler can do more than just err. The compiler can actually make your code work as intended by *converting* from meters to yards, for you.

Let's go back and redefine our `WaitFor` method as such:

```oxygene
method WaitFor(aTimeout: Milliseconds);
```

The compiler now knows what exact unit the method expects, *and* can enable us to call it with the unit that *we* find convenient when calling it:

```oxygene
var DefaultTimeout: Seconds := 30;
...
fEvent.WaitFor(DefaultTimeout);
```

The call site is clearly stating its intention – not to wait for 30 *whatevers*, but for thirty *seconds*, specifically. The method clearly states that it works with milliseconds. This allows the compiler to do the rest, and convert your "30" into "30000".

## Full Unit Syntax

There are four parts to a unit definition:

```oxygene
type
  Distance = public dimension(Double);
  LightYears = public unit(Distance) as ly = 9 460 730 472 580 800m;
```

- First, the name.`Lightyears` defines a new strong numerical type that is at runtime backed/represented as a 64-bit floating-point double.
- Then, `Distance` establishes the unit as part of the `Distance` dimension. Units of the same dimension can be compatible with each other (as we've seen above for Meters/Yards and Seconds/Milliseconds. Even if a unit mismatches, the compiler knows whether the two values even represent the same *concept* or not.
- `ly` provides an (optional) shorthand form the unit that can be used in constant expressions: `DistanceTraveled := 2ly;`
- Finally, a conversion path can be provided between different units in the same dimension. Here, we tell the compiler that one light year is about 9 and a half quadrillion meters. That's a long way home.

Any two units for which the compiler can find a conversion path (whether direct or indirect) can simply be assigned to each other. Assigning, e.g., a mile to a centimeter, and the compiler might go from mile to yard, to meter, to centimeter, if the following units are defined:

```oxygene
type
  Centimeters = public unit(Distance) as cm = 0.01m;
  Meters = public unit(Distance) as m;
  ...
  Yards = public unit(Distance) as yd = 0.9144m;
  Miles = public unit(Distance) as mi = 1760yd;
```

You can even do `var Distance := 5km+5m+1mi`.

**Note**: If you like, you *can* define multiple units in the same dimension w/o a well-defined conversion factor. You will still get the benefits of unit type safety; you just won't get automatic conversion. For example:

```oxygene
type
  Refrigerator = public unit(Volume);
```

No one except TV newscasters really knows what "the size of 10 refrigerators" actually means, but at least now it won't accidentally be mistaken for a proper unit such as, say, cubic meters 🙃.

Another cool unit to have is

```oxygene
type
  Temperature = public dimension(Double);

  Kelvin = public unit(Temperature) as K;
  Celsius = public unit(Temperature) as °C = value + 273.15 K;
  Fahrenheit = public unit(Temperature) as °F = (value + 459.67) * 5 / 9 K;
  Rankine = public unit(Temperature) as °R = value * 5 / 9 K;

```

Now you can do:

```oxygene
var c := 35ºC;
writeLn(#"c {c}"); // 35 ºC
writeLn(#"c {c as Kelvin}"); // 308.15 K
```

Or, if you must:

```oxygene
  writeLn(#"c {c as Fahrenheit}"); // 95 °F

```

And yes, you can use º in a unit name, just fine.

## Dimension Relationships

Things become more interesting when more than one dimension is defined, and we teach the compiler the *relationship* between them:

```
  Time = public dimension(Double);
  Speed = public dimension(Distance/Time);
  Acceleration = public dimension(Speed/Time);
 
  ...
 
  Seconds = public unit(Time) as s;
  Minutes = public unit(Time) = 60s;
  Hours = public unit(Time) = 60 Minutes;
  ..
  MetersPerSecond = public unit(Speed) as mps = m/s;
  KilometersPerHour = public unit(Speed) as kmh = km/Hours;
  MilesPerHour = public unit(Speed) as mph = mi/Hours;

```

We can now do

```oxgene
var lDistance := 5km;
var lTime := 30s;
var lSpeed: KilometersPerHour := lDistance/lTime;
```

and despite `lTime` being provided in seconds, the result will be in km/h!

More importantly, even without the explicit type, the compiler would derive that `var lSpeed := lDistance/lTime` should be a `Speed` type (it would just pick a different default unit, probably).

This becomes more fun, the more complex the relationships get. For (maybe a bit of a contrived) example, here `x` will be strongly typed as `GravitationalConstantUnits`.

```oxygene
  var l := 2.0m;
  var mass := 500.0g;
  var time := 3.0Hours;

  var x := l*l*l/(mass*time**2);
```

simply because the compiler has been told that unit is defined as `m**3/(kg*s2)`:

```oxygene
type
  GravitationalConstantUnits = public 
 unit(GravitationalConstantDimension) = m**3/(kg*s2);
```

## Unit Conversions

As seen above, a unit can be defined in relation to a different unit of the same dimension (or even a different one, in some cases). This can take several shapes:

### With a simple conversion factor

Simply using a unit expression of a sibling unit, with a value, can define a conversion factor. The value will be understood to represent `1` of the new unit. One `km` is `1000m`. Once `cm` is one hundredth of a Meter.

```oxygene
  Meters = public unit(Distance) as m;

  Centimeters = public unit(Distance) as cm = 0.01m;
  Kilometers = public unit(Distance) as km = 1000m;

  Feet = public unit(Distance) as ft = 0.3048m;
```

### With a more complex expression:

For some units, conversion not as simple. You can define a more complex conversion expression using the `value` keyword to express how a value of the new unit is converted to a different sibling unit. For example, by adding `273.15 K` to the ºC value to go to Kelvin.

```oxygene
  Kelvin = public unit(Temperature) as K;
  Celsius = public unit(Temperature) as °C = value + 273.15 K;
  Fahrenheit = public unit(Temperature) as °F = (value + 459.67) * 5 / 9 K;

```

Once defined, these work both ways, e. g from ºC to ºF and back from ºF to ºC.

### Via Base Units

For units derived from other base units\*, you can also use the base unit in the expression, e.g.:

```oxygene
type
  Area = public dimension(Distance**2);
  SquareMeters = public unit(Area) as m² = m**2;

```

Here, the `SquareMeter` unit is not defined by relation to a different `Area` unit, but as the square (or really, multiplication of two) `Distance` units, Meters. Note how this matches the definition of the dimension, which is declared as `Distance**2`. (`**` is the power operator in Oxygene, e.g. Distance²)

### As Reciprocal Relationship

Finally, a unit (and its dimension) can be defined as the reciprocal (or *inverse*) of a different unit. For example, frequency is the number of <somethings> *per* unit of time:

```oxygene
type
  Frequency = public dimension(1/Time);

  Hertz = public unit(Frequency) as Hz = 1/s;
```

---

\* We consider a base unit the unit that all others are derived from. E.g. in the examples above, `Meters` is the base unit, while `Centimeters` or `Yards` are derived from it. In many cases, the choice of base unit is arbitrary; one could just as easily have picked `Millimeter` as the base.

The same goes for dimensions. We have `Distance` and `Time` defined as base dimensions, while `Speed` is defined as the quotient of `Distance` and `Time`. That is the intuitive way to do it, but as far as the compiler is concerned, we could have declared Speed as a base unit `Distance = dimension(Speed*Time)`. It'd be a lot more confusing, but just as valid.

As a final note here, the unit system is smart enough to understand the relationship between exponential expressions and multiplications. E.g. while area is defined as `Distance**2` (i.e. Distance²), it knows that just means "Distance \* Distance", i.e. any product of two Distances will qualify as an Area, and vice versa; the same goes for e.g. `**3`.

---

## Units in Elements RTL

Units come to you in Oxygene 13.0.0.3101 in two ways.

**First**, it is a language feature that you can use to define your own units as you need.

**Secondly**, and I think more interestingly for most users, Elements RTL comes with a huge list of predefined units in the `RemObjects.Elements.RTL.Units` namespace. Just reference the library (you should anyway), and add the new namespace to your `uses` clause, and you have immediate access to several dozen dimensions and units, including all the examples shown here, many more derived units in the same dimensions (eg `mm`, `cm`, `km`), as well as units for many common physics, chemistry and electro-technical domains such as Mass, Force and Pressure, Speed, Acceleration and Momentum, Power and Energy, Voltage, Amperage and Resistance, Radioactivity, and many more.

If you define your own units, we would strongly sugest to build on what's in `RemObjects.Elements.RTL.Units`. But you can, of course, also just define your own, independent unit space.

Finally, if you think we missed any obvious or (more likely, given the broad coverage) not-so-obvious units or dimensions for your favorite domain in our default list, please do not hesitate to let us know, and we will expand the list.

You can have a look at [Units.pas](https://github.com/remobjects/RTL2/blob/master/Source/RemObjects.Elements.RTL/Units.pas?ref=blogs.remobjects.com) to get inspired by what's already there and to consider how you can apply it to your projects, as well as to see examples for more complex and esoteric unit definitions, such as `KilogramSquareMetersPerSecond`.

## Get Build .3101 or later of Oxygene 13 now.

Units are new in build .3101\. Get it now, as a free trial download or as a free update for all active subscribers!

![](https://blogs.remobjects.com/content/images/2026/07/codebot-units-measuring-confusion-full-body-02.png)