aughtone-types
3.1.0indexedFacilitates shared data types across projects, addressing duplication issues. Includes types for Location, Locale, Currency, and potentially Duration shortcuts for types like Distance.
Facilitates shared data types across projects, addressing duplication issues. Includes types for Location, Locale, Currency, and potentially Duration shortcuts for types like Distance.
A Kotlin Multiplatform library of strongly-typed, shareable data types — money and currency, locales, coordinates and telemetry, GeoJSON geometry, RFC-compliant identifiers, and arbitrary-precision math. It exists because KMP projects kept redefining the same types incompatibly; these are the shared ones, with no platform-specific API leaking through.
Targets: Android, JVM, iOS, JS, Wasm and Linux.
Published to Maven Central as io.github.aughtone:types.
// build.gradle.kts
implementation("io.github.aughtone:types:4.1.0")
Or through a version catalog:
# gradle/libs.versions.toml
[versions]
aughtone-types = "4.1.0"
[libraries]
aughtone-types = { module = "io.github.aughtone:types", version.ref = "aughtone-types" }
// build.gradle.kts
implementation(libs.aughtone.types)
Locale.current or localeFor("fr-CH").Money(12.50, Currency.Usd) or Money(BigDecimal("1.23456"), Currency.Eur).100.meters or 5.kilometers.UnitOfMeasure.Litre.symbol ("L"), MetricPrefix.Kilo.Url("https://pkg.dev"), Urn("urn:uuid:...").GeoUri(45.5, -122.6) (RFC 5870).BigInteger("999999999999999999999999") or BigDecimal("123.456").BigDecimal("1.255").setScale(2, RoundingMode.HALF_EVEN) -> 1.26.GeoPoint(45.5, -122.6, 100.0).toGeoJson() (RFC 7946).Locale.displayName from the bundled resource data is always English. To show a locale's name in the end user's own language:
localeFor("bn")?.localizedDisplayName() // "bengali" for a French user, "ベンガル語" for a Japanese user
Rather than bundling a full translation matrix (~90 × 90 names) into every app, this delegates to the CLDR data each platform already ships — java.util.Locale (JVM/Android), NSLocale (Apple), Intl.DisplayNames (JS/Wasm). Bundled resource files aren't viable everywhere: browsers can't read files synchronously, and klibs can't deliver resources into an iOS app bundle.
This is the one place the library does not promise every platform the same answer, and the reason is measured rather than assumed. Of the locale names that the JVM, Apple and a browser can all produce, they disagree on 40.8% between Apple and the browser, and 9.6% between the JVM and Apple. Not near-misses: nl-BE is "Nederlands (België)" on two platforms and "Vlaams" on the third. That is CLDR version skew between operating systems and browsers, and delegation cannot remove it.
So the goal here is completeness — every locale gets a name in the reader's language — and not consistency, which would mean bundling the full translation matrix into every artifact. That costs roughly 107 KB gzipped on web and mobile to fix a problem those platforms do not have, since they already ship the data. Elsewhere in this library identical behaviour everywhere is the point; for display names the price was judged wrong, deliberately.
What that means for you:
See ADR-0005 for the decision and the measurements, ADR-0003 for the original delegation rationale, and issue #20 for gap-filling work.
To ensure mathematical precision and behavior consistency, this library employs rigorous Differential Parity Testing against standard baseline libraries:
java.math.BigInteger and java.math.BigDecimal).BigInteger and BigDecimal are benchmarked against the JDK types. Figures are relative to java.math, so 1.0x is parity and below 1.0x is faster than the JDK.
Small values are the exception, and deliberately so: the JDK keeps any BigDecimal under 19 digits in a long, so it answers toDouble on one by reading a field. There is no equivalent fast path here, and short-value operations run from several times to two orders of magnitude slower as a result. Two other costs are worth knowing: modPow is around 5x, lacking Montgomery reduction, and comparing two BigDecimal values of different scale is quick only when their magnitudes differ enough to settle it without aligning them — equal scales, the common case, beat the JDK.
Run them yourself with ./gradlew :benchmarks:benchmark. Ratios hold reasonably across machines; absolute throughput does not, so the benchmarks report both.
[!IMPORTANT]
v4.1.0 Breaking Changes: Outcome is aligned with kotlin.Result. dataOrNull, dataOrThrow and dataOrElse are renamed getOrNull, getOrThrow and getOrElse, with no deprecated aliases, and the callbacks handed to onFailure, fold, recover and getOrElse now receive the Throwable rather than the Outcome.Failure. Check the callbacks first: they still compile. A body reading it.message keeps building but now gets the nullable Throwable.message instead of the non-null Outcome.Failure.message, so an exception with no message renders the text null. Use it.message ?: it.toString(). isSuccess, isFailure, exceptionOrNull() and getOrDefault are new. Currency now compares by its ISO 4217 code alone, so a Set or map keyed by Currency may hold one entry where it held two, and Money amounts from different sources sort instead of throwing. Gigabyte is now GiB and Gigabit Gbit, keeping GB and Gb as alternatives, so rendering .symbol changes for those two. Also: localizedDisplayName returned English for every locale on the JS and Wasm targets in 3.4.0 and 4.0.0 and now returns real translations, so anything rendering locale names on web changes output.
v4.0.0 Breaking Changes: A breaking release. Outcome.Error and Locale.toLanguageTag() are removed; Money equality is now numeric so 5.1 equals 5.10; Distance and Speed throw instead of clamping to zero; GeoBoundingBox leaves the geometry hierarchy; GeoFeature.properties becomes JsonObject; invalid GeoJSON is now rejected; and UnitOfMeasure.findFirst refuses ambiguous symbols rather than guessing. Several change behaviour without a compile error — see the changelog before upgrading.
v3.4.0 Outcome.Error renamed: The failure case of Outcome is now Outcome.Failure, and the factory is Outcome.failure(...). The old names shipped as deprecated aliases in 3.4.0 and are removed in 4.0.0. Outcome$Error no longer exists as a class, so upgrading from 3.3.0 needs a clean and rebuild rather than a code change.
v3.3.0 Locale Display Names: Eleven locale displayName values are corrected — renamed countries (Czechia, North Macedonia, Türkiye), incomplete or abbreviated country names, and dated language exonyms (Farsi → Persian, Azeri → Azerbaijani). No API changed, but snapshot tests and cached UI strings holding the old names will need updating. See the changelog for the full table.
v3.2.0 Behavioral Fixes: Still worth reading if you are coming from 3.1.x — that release corrected long-standing bugs whose output or validation changes for existing code. UrlEncoder.encode is now true RFC 3986 percent-encoding — use encodeFormData for the previous application/x-www-form-urlencoded behavior. Url/Uri/Urn/GeoUri string output is now well-formed, and Urn/GeoUri construction now rejects invalid input. Critical arbitrary-precision fixes also land in BigInteger/BigDecimal division and BankersValue. See the changelog for the full list.
v3.0.0 Breaking Change: All GeoJSON geometry types (e.g., Point, Polygon) have been renamed with a Geo prefix (e.g., GeoPoint, GeoPolygon). Money now uses BigDecimal for its internal value to support sub-minor units, and Telemetry has moved to the quantitative package.
docs/knowledge/, work in Issues.| Category | Type | Standard / Compliance | Description |
|---|
| Financial | Money | Banker's Rounding | Arbitrary-precision monetary values with BigDecimal storage. |
Currency | ISO 4217 | Global currency definitions with scale factors. | |
| Localization | Locale | BCP 47 | Universal language, region, and script identifiers. |
| Quantitative | Coordinates | WGS84 | Geodetic latitude and longitude degrees. |
Distance | SI (Meters) | Linear distance with accuracy support. | |
Speed | SI (mps) | Rate of motion in meters per second. | |
Altitude | SI (Meters) | Vertical distance above/below reference. | |
Azimuth | Degrees | Compass bearing (0-360°). | |
Telemetry | Unified Domain | Comprehensive model with coordinates, azimuth, speed, and altitude. | |
| Geospatial | GeoJson | RFC 7946 | GeoPoint, GeoFeature, and GeoFeatureCollection models. Coordinates.toGeoPoint() reorders to GeoJSON's longitude-first position. |
| SI Units | UnitOfMeasure | SI / Imperial | Definitions for meters, liters, bytes, etc. |
MetricPrefix | SI Prefixes | Scaling factors from Quetta to Quecto. | |
| Identifiers | Url | RFC 3986 | Uniform Resource Locators (Web). |
Urn | RFC 8141 | Uniform Resource Names (Persistent IDs). | |
GeoUri | RFC 5870 | Geographic 'geo' URI scheme. | |
| Mathematics | BigInteger | Pure Kotlin | Arbitrary-precision integer math support. |
BigDecimal | Pure Kotlin | Arbitrary-precision decimal math with rounding support. | |
| Utilities | BitSet | Multiplatform | Space-efficient storage for bit-level flags. |
BankersValue | Half-to-Even | Precision math with bias-free rounding rules. | |
| Control Flow | Outcome | Sealed (KMP-safe) | Success-or-failure result Swift can read as data, unlike kotlin.Result. Reads like Result: getOrNull, getOrThrow, getOrElse, fold, map, recover. |
Telemetry(coords, speed = 2.5.mps, azimuth = 90.degrees)runOutcome { parse(input) } returns Outcome.Success or Outcome.Failure; when over the two, or use fold, map, recover, getOrNull, getOrElse.kotlin.Result it is a sealed class, so Swift and JavaScript callers can read the failure as data. It otherwise reads as Result does — same members, same callback arguments — so it stands in for one where Result cannot cross the language boundary. See ADR-0004.localizedDisplayName never returns null — the worst case is the English displayName. That fallback is silent, so use localizedDisplayNameOrNull when showing the wrong language matters more than showing nothing: it returns null where the platform has no data, instead of quietly handing back English.Intl.DisplayNames, available since roughly 2020; older environments fall back to English.| Values of 40 digits or more | vs java.math |
|---|
| Division, remainder, modulo | 0.5x – 0.8x |
| Bitwise operations | 0.5x – 0.8x |
Text conversion (toString, parsing) | 0.8x – 3.4x |
Scaling, rounding, BigDecimal division | 0.9x – 1.2x |
| Add, subtract, multiply, shifts | 1.2x – 2.9x |
Surfaced from shared tags and platforms — no rankings paid for.