I’m excited to share a new package I’ve been working on: quantify ! It’s a type-safe units of measurement library for Dart, designed to make working with physical units safer, more readable, and efficient.
Motivation & Goals:
-
True Type Safety: I wanted to catch unit mismatch errors at compile-time, not runtime. No more accidentally adding meters to seconds!
-
Intuitive API: This project was also a bit of an API proof of concept for me. I really wanted to explore Dart’s extension methods to create a fluent and natural syntax. Think 10.m (for meters) or myLength.inKm. It was a fun experiment that I think paid off!
-
Performance: Unit conversions should be fast. quantify uses double for precision and ensures that most conversions are just a single multiplication, thanks to pre-calculated factors.
-
Operator Overloading: Performing arithmetic with quantities should feel natural, like distanceA + distanceB.
-
Easy String Representation: Getting a nicely formatted string with the value and unit symbol (e.g., “1.5 km”) should be straightforward and configurable.
What quantify offers (v0.1.0):
Since this initial version focuses on establishing the core API and type safety, the number of units is currently limited. Many more are planned for future releases
-
Type-Safe Quantities: Classes like Length, Time, Temperature, and Pressure ensure you’re working with the correct types.
-
Elegant Syntax:
final pathA = 1500.m; // Create with ease using short extensions
final pathB = 2.5.km;
double pathAInMiles = pathA.inMi; // Get value in another unit
Length pathBAsYards = pathB.asYd; // Get a new Quantity object
print(pathA.toString(targetUnit: LengthUnit.kilometer, fractionDigits: 1));
// Output: "1.5 km"
// With non-breaking space and locale support (if you use 'intl')
print(pathA.toString(
targetUnit: LengthUnit.yard,
unitSymbolSeparator: '\u00A0', // Non-breaking space
locale: 'de_DE', // For German number formatting
fractionDigits: 0,
));
// Output: "1640 yd" (approx, German locale might show "1.640 yd" if grouping is active)
Arithmetic Operations:
final totalDistance = pathA + pathB; // pathB is auto-converted
print(totalDistance.toString(fractionDigits: 0)); // "4000 m"
- ↔️ Comparisons & Sorting: Quantities are Comparable.
Get Started:
As this is an early version and an API exploration, your feedback is especially valuable. Bug reports, or feature requests (especially for new units!) are highly welcome. Please open an issue or a PR on GitHub.
Happy coding!
Philipp
1 Like
Hi everyone,
I’ve just released quantify v0.2.0 , and it’s a big step forward, especially in terms of unit coverage!
A huge thank you to everyone who showed interest in v0.1.0.
What’s New in v0.2.0?
Version 0.2.0 completes the foundation with all 7 SI base units now implemented.
(International System of Units: SI from French Système international d’unités)
I’m excited about the library’s progress! Your feedback, bug reports, feature requests (especially for new derived units!), and contributions are always welcome. Please open an issue or PR on GitHub.
Quantify v0.9.0 is here with new units and relational operators
1. Relational Operators (>, <, >=, <=) for everything!
// Before
if (oneMile.compareTo(oneKm) > 0)
// Now
if (oneMile > oneKm)
2. Clear Distinction: Magnitude vs. Strict Equality
To avoid confusion, quantify now offers clear tools for different kinds of equality checks. isEquivalentTo
checks for the same physical amount, while the standard == operator checks for identical value and unit.
// Magnitude check: Do they represent the same distance?
print(1.m.isEquivalentTo(100.cm)); // true
// Strict check: Are they represented in the exact same way?
print(1.m == 100.cm); // false (different units)
3. Unit Expansion (from 4 to 17+ quantity types!)
Mass : kg, g, lb, oz, tonne, stone, and more.
Electric Current : A (ampere), mA, µA, kA.
Amount of Substance : mol, mmol, µmol.
Luminous Intensity : cd (candela), mcd.
Angle : rad (radians), deg (degrees), rev (revolutions), arcmin.
Angular Velocity : rpm, rad/s, deg/s.
Speed / Velocity : m/s, km/h, mph, kn (knots).
Acceleration : m/s², g (standard gravity).
Force : N (newton), lbf (pound-force), kgf.
Area : m², km², ha (hectare), acre, ft².
Volume : m³, L (liter), mL, gal (gallon), fl-oz, tsp, tbsp.
Frequency : Hz, MHz, GHz, rpm, bpm (beats per minute).
Electric Charge : C (coulomb), Ah (ampere-hour), e (elementary charge).
Solid Angle : sr (steradian), deg² (square degree).
Practical Examples
1.
ElectricCharge - Estimating Battery Runtimes
// A power bank with a capacity of 10,000 mAh (or 10 Ah)
final powerBankCapacity = 10.ah;
// A device drawing a constant 500 milliamperes
final deviceCurrent = 500.mA;
// How long will the power bank last? (Time = Charge / Current)
final runtime = powerBankCapacity.timeFor(deviceCurrent);
print('Runtime for a ${deviceCurrent.asMilliamperes}: '
'${runtime.toString(targetUnit: TimeUnit.hour)}');
// Output: Runtime for a 500.0 mA: 20.0 h
2.
Area - Scientifically Settle the Pizza Debate
Which is a better deal: one 18-inch pizza or two 12-inch pizzas?
With the new > operator, the code reads just like the question.
import 'dart:math' as math;
// Define our pizza diameters
final lDiameter = 18.inch;
final mDiameter = 12.inch;
// Calculate the area of each (Area = π * r²)
final pizza18 = Area(math.pi * math.pow(lDiameter.inInch / 2, 2), AreaUnit.squareInch);
final pizza12 = Area(math.pi * math.pow(mDiameter.inInch / 2, 2), AreaUnit.squareInch);
print('One 18-inch pizza: ${pizza18.toString(fractionDigits: 0)}');
print('Two 12-inch pizzas: ${(pizza12 * 2).toString(fractionDigits: 0)}');
if (pizza18 > pizza12 * 2) {
print(
'The 18-inch pizza is MORE pizza! '
'(By ${(pizza18 - pizza12 * 2).toString(fractionDigits: 0)})',
);
}
// Output:
// One 18-inch pizza: 254 in²
// Two 12-inch pizzas: 226 in²
// The 18-inch pizza is MORE pizza! (By 28 in²)
Your feedback and ideas for more fun examples are always welcome.
1 Like