This is a continuation of this question. Suppose I want to describe results (values) of some measurements. We have physical quantities, each quantity (length, mass, force etc) can be measured in various units (grams, kilograms etc for mass and whatnot). Of course, this can be modeled in a number of ways, I constructed this (as an exercise with… say, “multi-level” tagged unions):
const p = @import("std").debug.print;
const tag = @import("std").meta.activeTag;
const Value = struct {
const Quantity = union(enum) {
const DistUnit = union(enum) {
mm: void,
m: void,
km: void,
};
const TimeUnit = union(enum) {
s: void,
min: void,
h: void
};
const MassUnit = union(enum) {
mg: void,
g: void,
kg: void,
};
dist_in: DistUnit,
time_in: TimeUnit,
mass_in: MassUnit,
};
name: []const u8,
q: Quantity,
v: f32,
fn quantityName(v: Value) []const u8 {
return @tagName(v.q);
}
fn unitName(v: Value) []const u8 {
return switch (v.q) {
inline else => |u| @tagName(u),
};
}
fn isEquatableTo(this: Value, other: Value) bool {
if (tag(this.q) != tag(other.q))
return false;
// return switch (this.q) { // failure
// inline else => |tu| tu,
// } == switch (other.q) {
// inline else => |ou| ou,
// };
// const aa = switch (this.q) { // failure
// inline else => |u| u,
// };
// const bb = switch (other.q) {
// inline else => |u| u,
// };
// return aa == bb;
return true;
}
};
In Value.isEquatableTo()
function I want to check if two values are “the same” meaning
- they are of same quantity (mass is not distance for ex)
- they measured in same units (kg is not mg for ex)
First part is ok, I stumbled at the second. I messed with inline else
, but failed to compare unit tags. How to do this?!?
Also there is a thing which I was not able to understand.
Here is main
function:
pub fn main() !void {
const v = Value{.name = "tower-height", .q = .{.dist_in = .m}, .v = 27.5};
const a = Value{.name = "apple-mass", .q = .{.mass_in = .kg}, .v = 0.2};
p("{s} is {} {s}\n", .{v.name, v.v, v.unitName()});
p("{s} is {} {s}\n", .{a.name, a.v, a.unitName()});
p("{} // {s} {s}\n", .{v.isEquatableTo(a), v.quantityName(), a.quantityName()});
// p("{} // {s} {s}\n", .{v.isEquatableTo(v), v.quantityName(), v.quantityName()});
const x = switch (v.q) {
inline else => |u| u,
};
p("{}\n", .{x});
}
The last part with switch
works fine here, but when similar statement is used in isEquatableTo
, compiler says:
4.zig:57:20: error: incompatible types: '4.Value.Quantity.DistUnit' and '4.Value.Quantity.TimeUnit'
const aa = switch (this.q) { // failure
^~~~~~
4.zig:58:32: note: type '4.Value.Quantity.DistUnit' here
inline else => |u| u,
^
4.zig:58:32: note: type '4.Value.Quantity.TimeUnit' here
inline else => |u| u,
^
Why is it so?