Skip to content

Feedback: building a non-physical application-owned quantity on UnitsNet.Modular #1728

Description

@Rafael-SOWNet

Feedback from building a non-physical, application-owned quantity on UnitsNet.Modular, in
case it is useful while Modular is still pre-release. This is a report, not a request — nothing
here needs an upstream change, and the probe runs against Modular as published.

Full write-up, definition and code: https://gist.github.com/48f6f6103616bcd79fa22f2bae60c7c9

What it is

A boolean/logic-state quantity where each unit is a named sense of the same bit. The case
it exists for is that standards disagree on polarity on purpose — KNX DPT 1.009 DPT_OpenClose
is 0 = open, 1 = close, while DPT 1.019 DPT_Window_Door is 0 = closed, 1 = open — so "1"
on the wire means nothing without its sense. That is a unit conversion, and 1 - {x} is the
conversion function.

73 units / 36 sense pairs, sourced per unit from KNX DPT 1.xxx, BACnet, OPC UA, IEC 61850,
IEC 61131-3, ANSI/ISA-18.2, NAMUR NE 107 and PackML. Verified on every build: 146 round-trips
over every unit with 0 failures, plus a constraint puzzle checked symbolically and against an
independently written native expression, agreeing on 32768/32768 assignments.

It generates cleanly, unchanged

Empty BaseDimensions, {x} and 1 - {x} conversions, 73 units, no warnings. The polarity
model carries the whole design: opposite-sense units are ordinary units with an inverting
conversion.

The generated struct being partial is a real extension point

The generator emits public readonly partial struct <Name>, so a consumer can declare the other
half and add what the generator does not — here &, |, ^, ~, ! and an explicit collapse
to bool, with no upstream change and no generator flag.

That is worth writing down because it answers "can Modular express a quantity with
domain-specific operators?" with yes, downstream, today. It also suggests the generator
should not emit such operators: over [0,1] the Zadeh (min/max) and probabilistic
(x*y, x+y-xy) t-norms disagree while coinciding on {0,1}, so generated operators would
have to pick one on every consumer's behalf.

The one thing that might deserve a docs line

Unit names become member names, so a consumer writing the other half of the partial is
constrained by the unit catalogue, not only by the public API. A private helper named
Valid would not compile:

error CS0102: The type 'LogicState' already contains a definition for 'Valid'

because Valid/Invalid is one of the sense pairs. Renaming fixed it, and nothing is wrong
with the generator — but "your unit names occupy the member namespace your own partial half has
to share" is not obvious until it bites, and it will bite anyone extending a generated quantity.
Happy to open a small docs PR if that seems worth having; equally happy to leave it.

Noted, not proposed

Parse("0 off") yields true. Correct by the model — 0 in the Off sense means not-off —
and still a trap for a human reading a log. KNX and BACnet solve the presentation side with
value-dependent text (active_text/inactive_text), which has no equivalent here and is
probably out of scope for a units library.


No rush on any of this. Filing it because pre-release feedback on an unusual use of the
generator seemed more useful sitting in the tracker than in a private workspace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions