I Built a Type-Safe SI Unit Library in Swift — And the Compiler Catches Your Physics Mistakes — DeepSeek Blog | Neura Market
    Neura MarketNeura Market/DeepSeek
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityDeepSeekDeepSeek
    CoPilotCoPilotStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsBlogVideosGuidesCoursesCommunityTrendingGenerate
    DeepSeekBlogI Built a Type-Safe SI Unit Library in Swift — And the Compiler Catches Your Physics Mistakes
    Back to Blog
    I Built a Type-Safe SI Unit Library in Swift — And the Compiler Catches Your Physics Mistakes
    swift

    I Built a Type-Safe SI Unit Library in Swift — And the Compiler Catches Your Physics Mistakes

    Henrique Sasaki Yuya March 24, 2026
    0 views

    SystemeInternational uses phantom types, affine spaces, and zero-cost abstractions to make unit misuse a compile-time error. 306 tests, 8 bytes per quantity, and unit conversions at 3 ns/op in Release.

    --- title: "I Built a Type-Safe SI Unit Library in Swift — And the Compiler Catches Your Physics Mistakes" published: true description: "SystemeInternational uses phantom types, affine spaces, and zero-cost abstractions to make unit misuse a compile-time error. 306 tests, 8 bytes per quantity, and unit conversions at 3 ns/op in Release." tags: swift, programming, opensource, types --- You've seen this bug before: ```swift let speed = distance + time // Compiles. Runs. Produces nonsense. ``` Or worse — the Mars Climate Orbiter kind, where pound-seconds and newton-seconds silently mix, and a $327 million spacecraft burns up in the atmosphere. I built **[SystemeInternational](https://github.com/moriturus/SystemeInternational)** to make that class of bug extinct in Swift — at compile time, with zero runtime cost. ## What If the Type System Knew Physics? `SystemeInternational` encodes physical dimensions, units, and even the distinction between *absolute positions* and *intervals* into Swift's type parameters. Every quantity is: ```swift Quantity<Scalar, Unit, Space> ``` That's it. **8 bytes.** The `Unit` and `Space` are phantom types — they exist only at compile time and vanish completely in the binary. ```swift import UnitesSI let distance = try Quantity<Double, Kilometer, Linear>(36) let time = try Quantity<Double, Second, Linear>(3_600) let speed = try distance / time // ✅ Compiles — dimension is Length/Time let nonsense = try distance + time // ❌ Compile error — no overload ``` No runtime checks. No `if unit == .meter`. The compiler simply won't let you add meters to seconds. ## Five Things That Make This Different ### 1. Hertz ≠ Becquerel (Even Though They're Both 1/s) The SI system has unit pairs with identical dimensions but completely different physical meanings. Most unit libraries treat them as interchangeable. SystemeInternational doesn't: ```swift import UnitesSI let reciprocalRate = try Quantity<Double, CanonicalUnit<QuotientDimension<Dimensionless, TimeDimension>>, Linear>(50) let frequency = reciprocalRate.interpreted(as: Hertz.self) let activity = reciprocalRate.interpreted(as: Becquerel.self) print(frequency.value) // 50.0 print(activity.value) // 50.0 ``` `Hertz` and `Becquerel` are different public types even though they share the same exponent dimension. The same idea applies to angular frequency (`rad/s`) versus cyclic frequency (`Hz`), and to `Gray`/`Sievert` (absorbed dose vs. equivalent dose). The library respects BIPM's semantic distinctions. ### 2. You Can't Add Two Temperatures Adding 20°C + 25°C is physically meaningless — you can't add two absolute positions. But subtracting them to get a temperature *difference* is perfectly valid. SystemeInternational models this with **affine space algebra**: ```swift import UnitesSI let room = try CelsiusTemperatureValue(20) // Affine (absolute position) let boiling = try CelsiusTemperatureValue(100) // Affine let rise = try boiling - room // ✅ Linear (interval): 80°C let shifted = try room + rise // ✅ Affine: 100°C let oops = try room + boiling // ❌ Compile error ``` | Expression | Result | Meaning | |---|---|---| | Point − Point | Vector | Distance between positions | | Point + Vector | Point | Shift a position | | Point + Point | **compile error** | Adding positions is meaningless | And yes — it validates against absolute zero at runtime: ```swift try CelsiusTemperatureValue(-274) // throws QuantityError.belowAbsoluteZero ``` ### 3. Exact Integer Arithmetic Need precise timing in embedded systems? Use integer scalars: ```swift import UnitesSI let duration = try Quantity<Int, Millisecond, Linear>(exactly: 2_000) let seconds = try duration.convertedIfExactly(to: Second.self) print(seconds.exactValue) // Optional(2) let oneMeter = try Quantity<Int, Meter, Linear>(exactly: 1) try oneMeter.convertedIfExactly(to: Kilometer.self) // throws — 0.001 isn't an Int ``` No silent truncation. No floating-point drift. It throws when the math doesn't work out exactly. ### 4. Rational Scale Factors (Not Floating-Point) Unit scales are stored as **rational numbers with decimal exponents**, preserving precision that `Double` arithmetic would destroy: ```text // 1° = π/180 radians, stored as: UnitScale(numerator: 3_141_592_653_589_793, denominator: 180, decimalExponent: -15) // 1 eV = 1.602176634 × 10⁻¹⁹ J (exact by 2019 SI redefinition), stored as: UnitScale(numerator: 1_602_176_634, denominator: 1, decimalExponent: -28) ``` This means conversions like `Degree → Radian` or `ElectronVolt → Joule` carry the full precision of the defining constants. ### 5. Thin Abstractions the Optimizer Can See Through Hot-path accessors and arithmetic are annotated with `@inlinable`, so the compiler can inline across module boundaries and apply full optimizations in Release builds: | Benchmark | Debug | Release | Speedup | |---|---|---|---| | `convert_kilometer_to_meter` | 225 ns/op | **3 ns/op** | ~75× | | `semantic_lumen_operator` | 291 ns/op | **83 ns/op** | ~3.5× | | `semantic_lux_operator` | 435 ns/op | **155 ns/op** | ~2.8× | > Same-unit operations like `linear_add_same_unit` and `multiply_canonical_area` measured **0 ns/op** in Release — the optimizer eliminated them entirely via dead code elimination, confirming that the phantom-type abstractions add no barriers to standard compiler optimizations. Real-world code that *uses* the results will still pay the cost of a bare `Double` operation, but nothing more. The key takeaway: **the type-safety layer is transparent to the optimizer.** You get compile-time unit checking without runtime overhead beyond the underlying arithmetic. ## The Module Architecture SystemeInternational is split into focused, composable modules: ```plaintext UnitesSI ← Main facade (import this) ├── UnitesDeBaseDuSI ← Core: Quantity, dimensions, 7 base units ├── PrefixesDuSI ← All 20 SI prefixes (Quetta → Quecto) └── UnitesDeriveesDuSI← Named derived units + temperature scales UtiliseesNonSI ← 16 BIPM-accepted non-SI units UnitesSICompat ← Foundation.Measurement bridge UtiliseesNonSICompat ← Non-SI Foundation bridge ``` For most use cases, `import UnitesSI` gives you everything. The modular design means you only link what you use. ## Quick Tour ### Prefixed Units — All 20 SI Prefixes ```swift import UnitesSI let distance = try Quantity<Double, Kilometer, Linear>(5.2) let tiny = try Quantity<Double, Microgram, Linear>(0.3) let huge = try Quantity<Double, Gigahertz, Linear>(2.4) // Mass follows SI convention: Kilogram is base, but prefixes come from Gram let mg = try Quantity<Double, Milligram, Linear>(500) print(mg.converted(to: Kilogram.self).value) // 0.0005 ``` ### Derived Units with Semantic Operators ```swift import UnitesSI let intensity = try Quantity<Double, Candela, Linear>(1_200) let solidAngle = try Quantity<Double, Steradian, Linear>(1.5) let luminous = try intensity * solidAngle // → Lumen let area = try Quantity<Double, Meter, Linear>(3) * Quantity<Double, Meter, Linear>(2) // → m² let illuminance = try luminous / area // → Lux ``` ### Foundation.Measurement Interop ```swift import Foundation import UnitesSICompat // SystemeInternational → Foundation let road = try Quantity<Double, Kilometer, Linear>(12.3).foundationMeasurement() print(road.unit.symbol) // "km" // Foundation → SystemeInternational let temp = try Measurement(value: 25, unit: UnitTemperature.celsius) .absoluteTemperature(as: DegreeCelsius.self) print(temp.converted(to: Kelvin.self).value) // 298.15 ``` ### Non-SI Accepted Units ```swift import UtiliseesNonSI let water = try Quantity<Double, Milliliter, Linear>(500) let rightAngle = try Quantity<Double, Degree, Linear>(90) let gain = try Quantity<Double, Decibel, Linear>(20) print(water.converted(to: Liter.self).value) // 0.5 print(rightAngle.converted(to: Radian.self).value) // 1.5707963267948966 ``` ## Why "Systeme International"? The name comes from the French *Système International d'Unités* — the official name of the SI system, maintained by the [Bureau International des Poids et Mesures (BIPM)](https://www.bipm.org/en/measurement-units/si). The module names follow the same convention: *Unités de base du SI*, *Préfixes du SI*, *Utilisées non-SI*. ## Requirements & Installation - **Swift 6.2+** - **No dependencies** — pure Swift, no external packages ```swift // Package.swift dependencies: [ .package(url: "https://github.com/moriturus/SystemeInternational.git", from: "0.1.0"), ] ``` 306 tests. 100% coverage target. Apache 2.0 licensed. --- If you work with physical quantities in Swift — whether it's scientific computing, IoT sensor data, robotics, game physics, or just making sure your app doesn't confuse kilometers with miles — give **[SystemeInternational](https://github.com/moriturus/SystemeInternational)** a look. ⭐ **[Star the repo on GitHub](https://github.com/moriturus/SystemeInternational)** if you think the type system should catch your physics bugs. {% github moriturus/SystemeInternational %} --- **P.S.** To our friends still measuring things in feet, inches, pounds, ounces, fluid ounces (US), fluid ounces (UK), short tons, long tons, nautical miles, statute miles, furlongs, and—my personal favorite—*slugs*: the year is 2026. The rest of the world moved on. Even the UK went metric (mostly). Even NASA went metric (after *that* incident). This library does not, and will never, include `Foot`, `Slug`, or `Hogshead`. You know where to find `Foundation.Measurement` — it's right there, waiting, with all 14 of your competing gallon definitions. 🫡

    Tags

    swiftprogrammingopensourcetypes

    Comments

    More Blog

    View all
    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠ai

    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠

    Hi everyone! 👋 I’m Tara, a Senior Software Engineer and Consultant. Over the years, I've jumped...

    T
    tworrell
    Local AI Will Save Us All (The Math Says So, Trust Me)ai

    Local AI Will Save Us All (The Math Says So, Trust Me)

    Every few weeks a take goes viral in tech circles making the case for ditching cloud AI and running...

    S
    Sebastian Schürmann
    Lost in the AI Hype, I Started Smallai

    Lost in the AI Hype, I Started Small

    And it helped me get back into tech without drowning TL;DR at the end Coming back to...

    R
    Rohini Gaonkar
    Building a Replay-Tested Interactive Brokers Client in Gogo

    Building a Replay-Tested Interactive Brokers Client in Go

    I wanted an IBKR library that felt like Go and had testing I could trust. So I wrote one.

    T
    Thomas Marcelis
    Playwright in Pictures: Fully Parallel Modeplaywright

    Playwright in Pictures: Fully Parallel Mode

    Playwright’s fullyParallel mode is often treated as a simple performance switch. In practice, it...

    V
    Vitaliy Potapov
    Designing a CLI for Both Humans and Agentscli

    Designing a CLI for Both Humans and Agents

    Learn how Alpic designed its CLI for both human developers and AI agents — covering tradeoffs like polling, context windows, interactivity, and statelessness.

    J
    Julien Vallini

    Stay up to date

    Get the latest DeepSeek prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for DeepSeek and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.