Is there a way to represent a type that is essentially a unit (alternatively, a 1-D vector space)? For example, I want to represent 500 kilometers, which supports (let’s say) addition and subtraction of other amounts of kilometers, and scalar multiplication and integer division by builtin integer types.
Clearly you can do it by putting the number of km in a struct, but you’d have to write your own add, subtract, etc; what I’d rather have is something where I get the syntactic sugar of having +, -, * “just work.”
// appropriately create the `km` type such that...
const x: km = 500;
const y: km = 20;
const z: km = x + y;
const my_int: u32 = 30;
const k: km = my_int * x; // should work
const l: f32 = x / y;
// const w = x + my_int; should fail at compile time
Zig currently cannot create distinct types that inherits all the operations.
To fulfill the requirement your only option is to use a struct and have add, mul, etc. functions.
This is an unexpectedly difficult problem. Nominally-distinct primitive types might happen (they aren’t on the roadmap), but it’s unlikely Zig will go the full distance to properly support units in the type system, it adds a lot of complexity to get it right.
I think the notion of “unit” is not enough.
“Unit” is a name for some particular value of a physical quantity (“km” etc).
Are are not adding “names”, we are adding values of physical quantities.
Just some simple exercise:
const Quantity = enum {
distance,
};
const Unit = enum {
m, km
};
// also need some Quantity-Unit "compatibility"/"affinity"
const Value = struct {
q: Quantity = undefined,
u: Unit = undefined,
v: f32 = undefined,
fn add(v1: Value, v2: Value) !Value {
if (v1.q != v2.q) return error.QuantityMismatch;
if (v1.u != v2.u) return error.UnitMismatch; // or do scaling
return .{.q = v1.q, .u = v1.u, .v = v1.v + v2.v};
}
};
const p = @import("std").debug.print;
pub fn main() !void {
const d1 = Value{.q = .distance, .u = .m, .v = 500};
const d2 = Value{.q = .distance, .u = .km, .v = 1};
p("d1 = {any}\n", .{d1});
p("d2 = {any}\n", .{d2});
const d3 = try Value.add(d1, d2);
p("d3 = {any}\n", .{d3});
}
As intended, the program fails with UnitMismatch error.