www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Strong typing and physical units

reply Cecil Ward <cecil cecilward.com> writes:
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;

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.

  point1.x = point2.y;

the above is illegal but we need a way to get the underlying 
value so we can handle rotation by angle of 90 deg or whatever. 
These two variables have the same units; their unit is pixels but 
they cond have a real SI physical unit of length in metres say. 
Even when they are of the same physical units type they need to 
be made incompatible to prevent y coordinates from getting mixed 
up with x coordinates by mistake.

also

point1.x = width; // illegal

and

point1.x = height; // even worse

Arbitrary sub typing would help here but would need accompanying 
tools to make it usable, the ‘get underlying value’ thing 
mentioned earlier might not be the only one, I’m not sure.

Any thoughts ?

—
I tried to do something with wrapping a double say in a 
(templated) struct with just one field value_ in it and an alias 
value_ this; but as a miserable D learner, I soon got lost.

for some reason when using alias this as above, I can do 
assignments to my struct, but I cannot initialise it using the 
alias this simplification mechanism. I’m not sure why. I’m 
assuming I need an appropriate trivial constructor but why 
doesn’t this get sorted out for you automatically when you’re 
using alias this? That would seem to be logical, no? Asking for 
too much - greedy :-)


Cecil Ward.
Jul 27 2020
next sibling parent reply WebFreak001 <d.forum webfreak.org> writes:
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.
Jul 27 2020
parent reply Cecil Ward <cecil cecilward.com> writes:
Of course, in C I used to do something like strong typing with an 
opaque type achieved by using something like typedef struct 
_something {} * type1; and then I had to do casting to get back 
the real type, which was unchecked but it did prevent the user 
from mixing up the types type1 and type2 say as they weren’t 
assignment compatible.

I would really like strong typing to be a built in feature. Would 
anyone else support this?
Jul 28 2020
next sibling parent Cecil Ward <cecil cecilward.com> writes:
I just remembered: another favourite bug of mine would be mixing 
up indices, using an index with the wrong array, an index to a 
different array entirely. they’re all just a nightmare load of 
meaningless ints or uints or hopefully size_t’s.
Jul 28 2020
prev sibling parent Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Tuesday, 28 July 2020 at 11:04:00 UTC, Cecil Ward wrote:
 Of course, in C I used to do something like strong typing with 
 an opaque type achieved by using something like typedef struct 
 _something {} * type1; and then I had to do casting to get back 
 the real type, which was unchecked but it did prevent the user 
 from mixing up the types type1 and type2 say as they weren’t 
 assignment compatible.

 I would really like strong typing to be a built in feature. 
 Would anyone else support this?
Once upon a time, typedef was present and backed by the compiler, but nowadays you can find it in Phobos [1], but with some quirk ... [1] https://dlang.org/phobos/std_typecons.html#.Typedef
Jul 28 2020
prev sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Tuesday, 28 July 2020 at 04:40:33 UTC, Cecil Ward wrote:
 [snip]
By the way, I found 2 implementations of unit of measurement in D: https://code.dlang.org/packages/units-d https://code.dlang.org/packages/quantities
Jul 28 2020
parent Cecil Ward <cecil cecilward.com> writes:
On Tuesday, 28 July 2020 at 07:16:53 UTC, Petar Kirov 
[ZombineDev] wrote:
 On Tuesday, 28 July 2020 at 04:40:33 UTC, Cecil Ward wrote:
 [snip]
By the way, I found 2 implementations of unit of measurement in D: https://code.dlang.org/packages/units-d https://code.dlang.org/packages/quantities
Thank you Peter! Very helpful. Do you guys have any thoughts also about the strong typing idea?
Jul 28 2020