Strong typing and physical units
WebFreak001
d.forum at webfreak.org
Tue Jul 28 06:15:45 UTC 2020
On Tuesday, 28 July 2020 at 04:40:33 UTC, Cecil Ward wrote:
> I found an earlier post somewhere about work someone has done
> on physical units such as kg, volts and so forth.
>
> It would be very good to catch bugs such as
>
> volts_t v = input_current;
>
> [...]
This is easily done and uses enums: (officially defined in the
specification, not even a hack!)
enum DisplayUnit : int { init = 0 }
enum Width : DisplayUnit { init = DisplayUnit.init }
enum Height : DisplayUnit { init = DisplayUnit.init }
void foo()
{
Width width = cast(Width)16;
Height height = cast(Height)9;
//width = height; // illegal implicit conversion
//width = 4; // illegal implicit conversion
width = cast(Width)height; // legal, force conversion
DisplayUnit val = width; // allowed implicit conversion,
Width "inherits" DisplayUnit
int num = width; // also allowed, Width "inherits"
DisplayUnit which "inherits" int
writeln(num); // 9
writeln(width); // cast(Width)9
}
You can then also make helper functions for prettier syntax, see
https://run.dlang.io/is/X4BA32
> But that isn’t nearly enough. With strong typing where we can
> create arbitrary subtypes that are chosen to be incompatible
> because they are semantically incompatible in assignment,
> equality, addition and various other operations, we can catch a
> lot more bugs.
Sadly width += height (and probably all operators other than
assignment) are still allowed.
However for return codes this makes great sense: it implicitly
converts down to integers if the user wishes to lose type
information and otherwise prevents assigning or calling wrong
functions like some example `enum Win32Error : int` could not be
used to call a `validate(PosixError)` function
This is also great for opaque handles like for making file
descriptors type-safe: `enum File : int`, `enum Socket : int`
which you can't accidentally pass to type-safe APIs but can still
easily use in C APIs using ints or raw file descriptor access.
All your wrapper functions simply cast the internal C API return
values to these type-safe enum types based on context they know.
For other values representing something it doesn't work as great
as you need to have a helper function to construct them or always
cast them as well as to!string (and writeln) don't print the raw
value but rather prepend a "cast(T)" in the string, but it still
works and is possible.
More information about the Digitalmars-d-learn
mailing list