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