Skip to content

Section 6 of 26

Units and quantities by example

Write the quantity you mean: 250ms, 440Hz, 3.2m, 21°C. The suffix carries a checked dimension. A duration, frequency and distance remain different even when their representations happen to have the same size.

Unit is a physical catalogue descriptor, distinct from a quantity of magnitude one and from Empty, the historical empty product value. Quantity uses the bounded exact decimal profile carrying its full Unit. Dimension-specific consumers such as Distance and Frequency use that same codec with checked dimensions. A domain needing an integer performs an explicit checked projection in its selected Unit, refusing fractional precision or overflow.

These examples describe current development source for first-class values #5390, built on completed SI work #5328. Published binaries can lag development. The complete conversion plots below use the installed product catalog; save one as example.conduit and check it:

conduit check example.conduit
conduit expand example.conduit

Checking proves authoring and admission; it does not execute the plot. The quantity conformance sources and product tests exercise the examples and their refusal cases.

A quantity has a dimension

plot beyond-reach (
    limit: Distance = 30cm
    >> distance: Distance
    beyond: Boolean >>
) = (. > limit)

This complete Plot compares distance with a typed distance threshold. Replacing the default 30cm with 440Hz refuses checking of the Distance parameter. Changing it to 0.3m preserves the physical threshold. Units give the comparison its meaning.

A distance becomes a musical pitch

The Pocket Theremin illustrates mapping one dimension into another explicitly. This domain example requires its reviewed catalog; it is not a standalone installed-CLI example. The pitch relationship is expressed with ordinary quantity arithmetic:

# The pitch law is ordinary Conduitese. Convert distance to a dimensionless
# number of centimetres, then lower pitch by 55 Hz per centimetre. Clamping is
# explicit; unit conversion and arithmetic never silently round.
plot theremin-pitch (
    >> distance: Distance
    frequency: Frequency >>
) = (distance <= 0cm ? 1760Hz : distance >= 30cm ? 110Hz : 1760Hz - (distance / 1cm) * 55Hz)

# The one canonical Theremin. Both controls describe portable meaning. Hosts
# own acquisition, cadence, and playback; this Plot owns the instrument law.
plot pocket-theremin (
    >> pitch-distance: Distance
    >> volume: Scalar
    >> cadence: value/tick@1...
    audio: audio/pcm-frames@1...| >>
) {
    pitch: theremin-pitch
    frequency: keep Frequency(440Hz) for this play
    tone: audio/continuous-tone
    gain: audio/apply-gain

    pitch-distance >> pitch.distance
    pitch.frequency >> frequency
    frequency >> tone.frequency
    cadence >> tone.cadence
    tone.audio >> gain.source-audio
    volume >> gain.amplitude
    gain.audio >> audio
}

The named expression input distance is evaluated for each arriving reading. It does not determine how long the instrument runs. keep holds pitch for the play, while every cadence tick samples it and renders another phase-continuous PCM block. Stationary input therefore sustains the tone; volume controls its amplitude. The controller supplies the cadence and the Host enforces output limits. Arithmetic retains units and refuses inexact carrier projections.

Moving away across the 30-centimetre range lowers pitch from 1760 Hz to 110 Hz. The expression declares that relationship explicitly; unit conversion alone cannot turn metres into hertz. Audio-device selection belongs to realization.

Convert explicitly and retain the result

plot convert-pitch (
    receipt: ExactQuantityConversionReceipt <= 8192B >>
) {
    converted: units/convert(source = 1kHz, to = Hz)
    converted.receipt >> receipt
}.

The result is exactly 1000 Hz. source: Quantity and to: Unit are ordinary checked startup values. Bare Hz, kHz and °C name Units; 1kHz and 21°C name Quantities. Neither needs notation imports or quotation marks. The receipt retains original spelling, resolved units and dimensions, prefix, conversion law, selected profile, and either the exact coordinate or a typed refusal.

Try these replacements in the same plot:

SourceTargetExact result
1µsns1000 ns
1cm²mm²100 mm²
0°CK273.15 K
30°C°F86 °F
1MBB1,000,000 B
1MiBB1,048,576 B
1mgg0.001 g
1kgg1000 g
1km/hm/sinexact refusal; no silent rounding

Powered units apply the prefix's power too: a centimetre squared is 10⁻⁴ square metres. The reviewed compound suffix m/s² is supported; this does not introduce arbitrary source algebra such as kg*m/s^2.

Compare compatible dimensions exactly

plot compare-distances (
    receipt: ExactQuantityComparisonReceipt <= 8192B >>
) {
    compared: units/compare(left = 1000mm, right = 0.001km)
    compared.receipt >> receipt
}.

The comparison is equal: both mean one metre. No rounded display coordinate is needed to establish equality. The receipt retains both operands and their exact reference transforms. The same Gear compares 1°F and 0°C exactly even though converting 1 °F to a finite decimal °C coordinate is inexact.

Turn a retained conversion receipt into a decision

plot convert-pitch-demo {
    operation: units/convert(source = 1kHz, to = Hz)
    exact: units/converted-equals(expected = 1000Hz)
    show: face/text("Message")
    operation.receipt >> exact.receipt
    exact.result >> (. ? "Exactly 1000 Hz" : "Conversion did not yield exactly 1000 Hz") >> show.text
}.

This full-name invocation validates the receipt and returns true for the exact conversion above. A different magnitude, incompatible expected dimension, or valid refusal returns false. Forged receipts fail admission. The Boolean is a chosen projection; retain the receipt when the exact outcome or refusal matters. Physical comparison uses units/compare, not representation-byte equality. For example, 21°C and 69.8°F compare as equal absolute points.

To abbreviate the same checked Gear in this plot, import with units/converted-equals as =? before its declaration and replace the configured invocation with exact: =?(expected = 1000Hz). The alias is scoped to its import and retains the full-name operation's Type checking and ports.

A temperature point differs from a temperature change

0°C as a temperature point equals 273.15 K. A change of 0 °C has no 273.15 K offset. Choose the ordinary Gear whose source Fore states which meaning you want. TemperatureDifference is distinct from absolute Quantity; forwarding an already checked point into a difference parameter refuses:

plot temperature-change (
    receipt: ExactTemperatureDifferenceConversionReceipt <= 8192B >>
) {
    converted: units/convert-temperature-difference(source = 9°F, to = K)
    converted.receipt >> receipt
}.

This change is exactly 5 K. For 1m°C to K, the difference is 0.001 K. Difference conversion scales the change without applying an absolute temperature offset.

plot compare-temperature-changes (
    receipt: ExactTemperatureDifferenceComparisonReceipt <= 8192B >>
) {
    compared: units/compare-temperature-differences(left = 9°F, right = 5K)
    compared.receipt >> receipt
}.

Its result is equal. These contracts prevent a temperature change from being silently treated as an absolute temperature point.

All 24 decimal SI prefixes

Each row can be used as source in units/convert, with to = m. The exact conversion profile preserves a finite coefficient and exponent; these examples do not promise that every integer realization can store it.

PrefixExampleMetres
quetta Q1Qm10³⁰
ronna R1Rm10²⁷
yotta Y1Ym10²⁴
zetta Z1Zm10²¹
exa E1Em10¹⁸
peta P1Pm10¹⁵
tera T1Tm10¹²
giga G1Gm10⁹
mega M1Mm10⁶
kilo k1km10³
hecto h1hm10²
deca da1dam10¹
deci d1dm10⁻¹
centi c1cm10⁻²
milli m1mm10⁻³
micro µ1µm10⁻⁶
nano n1nm10⁻⁹
pico p1pm10⁻¹²
femto f1fm10⁻¹⁵
atto a1am10⁻¹⁸
zepto z1zm10⁻²¹
yocto y1ym10⁻²⁴
ronto r1rm10⁻²⁷
quecto q1qm10⁻³⁰

The authored prefix policies includes seconds, hertz, volts, amperes, kelvin, grams, metres, square/cubic metres, litres, radians, bytes, newtons, joules, watts, pascals, metres per second, metres per second squared, and ampere-hours. Prefixes are case-sensitive: 1mW and 1MW differ by a factor of a billion. Mass prefixes attach to g; 1mkg refuses. Prefixes cannot be stacked or attached to arbitrary symbols.

Canonical micro is µ (U+00B5). ASCII u is an explicit source alias, so 1us can replace 1µs. Greek μ (U+03BC) refuses. Powers use declared spellings such as m², m³, and m/s². Source bytes and provenance survive; there is no implicit Unicode normalization. Binary KiB/MiB/GiB remain distinct from decimal kB/MB/GB.

Quantity families, dimensions, Unit reference laws, affine Point/Delta associations, and prefix policies are authored in Conduitese. The checked physical.conduit library is the builtin authority; a document can add unit smoot : Distance = { reference: m, scale: 1.7018 } without changing Rust. Prefixes are disabled unless the declaration explicitly opts into source-defined groups. Unit capsules occupy 768 bytes and retain their checked laws independently of later catalogue changes.

Angle uses turn as its canonical, reference, and default Unit. Degrees have an exact scale of 1/360turn, so 90° is exactly 0.25turn. Radians currently retain an independent named origin; radian/turn conversion returns typed Inexact until #5392 supplies the symbolic 2π relation. No decimal approximation stands in for that relation.

Reference anchors bind the family, source root symbol, and exact root law. Changing the root law creates a distinct anchor, preserving the meaning of old Unit/Quantity capsules and Plan/Play snapshots. A paired Point/Delta root shares one checked anchor.

Extreme scale needs an explicit representation

plot extreme-distance (
    receipt: ExactQuantityConversionReceipt <= 8192B >>
) {
    converted: units/convert(source = 1Qm, to = qm)
    converted.receipt >> receipt
}.

The exact coordinate has coefficient 1 and decimal exponent 60 in the target unit. The public Quantity Type carries an exact decimal coordinate and the full resolved Unit in one versioned 788-byte codec. There is no second narrow quantity family. Recognized extreme scales remain ordinary Quantities; an integer domain projection has its own finite precision and range. Recognizing a suffix does not make its value fit every consumer. A fractional or overflowing integer projection refuses admission.

An ordinary startup parameter selects the source Type Quantity:

plot exact-extent (
    extent: Quantity = 1Qm
) {
}

This Fore/default example checks the wider profile without performing an effect. Changing Quantity to Distance retains the same codec and requires the length dimension. A consumer requiring integer metres must explicitly project and refuse overflow for this extreme value. The exact-profile tests also cover direct literals and the canonical 788-byte carrier.

Refusal is an inspectable result

Replace the conversion arguments above with:

SourceTargetOutcome
1Hzmtyped incompatible-dimensions result
1°F°Ctyped inexact result
1Qm³qm³typed overflow result
21CKinvalid request; write 21°C
1mmkginvalid target suffix
1μssinvalid source alias

The first three are well-formed conversion requests whose receipts say refused; the last three are source diagnostics. A successful conduit check therefore does not imply that a conversion result is converted. The consumer must inspect the result. No case quietly rounds, guesses a unit, or turns an incompatible dimension into a scalar.

Acoustic quantities: current building blocks and planned integration

Native 440Hz and 250ms already work. The open acoustic contracts #5216 and Speech quantities #5262 ask for more than literal parsing. Their worked acceptance scenario is a 0.1-second, 200-Hz intent projected at 8, 16 and 48 kHz: 800, 1600 and 4800 samples describe the same source duration. The nominal cycle duration is 0.005 seconds; an executed checked reciprocal operation must establish that projection.

For repeated one-third-second durations, retain the exact fraction and cumulative remainder instead of rounding every append. Amplitude, power and referenced dB need distinct Types and explicit conversions. Overlapping pitch and energy trajectories retain their timebase, scope and provenance; intended targets remain distinct from measured observations and uncertainty.

Those are planned end-to-end acceptance examples, not claims that every projection or Speech bridge is complete. They build on the same quantity laws. Optional typed delimiter glyphs do not become a prerequisite for native units.

Continue with the complete feature examples.

The first-class value design records bounded codecs, name shadowing, source evidence and proof boundaries.

Compact full-turn units

For Angle, turn remains the reference unit. Use tr as the preferred compact spelling, or rev and rot as exact one-turn synonyms. pla is an uncommon historical full-angle spelling. 1tr, 1rev, 1rot, and 1pla are each exactly 1turn, 360°, or 400gon; 0.25tr is exactly 90°. Bare spellings such as tr denote Units, while suffixed values such as 2rev denote Angle Quantities. These units do not admit prefixes. An undeclared suffix is refused with CND-FRM-055; redeclaring a unit symbol is refused with CND-FRM-058.

Optional international full-turn vocabulary

architecture/core/definitions/optional/international-turns.conduit provides tour, toer, revolución, rivoluzione, revolução, Umdrehung, varv, and obrót. Each checked declaration references turn with scale 1. Bare names denote Units; suffixed quantities such as 1revolución equal one turn, and 0.25obrót equals a quarter turn exactly.

These names are optional. Include the declarations in authored Source, or check the declaration document with checked_physical_catalog_for_document and pass the returned immutable catalogue to the consumer's checker. The default catalogue does not acquire these names globally. This uses existing checked declarations and catalogue custody; it introduces no file-import syntax.

Spellings are case-sensitive and preserve their UTF-8 bytes. There is no Unicode normalization, accent removal, transliteration, or locale-based lookup: revolucion and decomposed revolución remain undeclared and receive CND-FRM-055. An import cannot rebind turn or an already imported alias (CND-FRM-058). The canonical reference and existing checked values remain fixed.

A checked catalogue import also rejects unsupported locale-import syntax (such as import locale "fr_FR") with its original parser code, message, and source span. It never treats a malformed import as an empty overlay, including when the destination catalogue already contains checked Units.