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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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