Recent

Author Topic: Type checking of units of measurement  (Read 6371 times)

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #30 on: January 30, 2023, 09:47:51 pm »
Ok so I thought about the name.

As units are small, they are likely to collide with local variables. So it is better to have a short and easily identifiable name for the unit.

"Dim" is the best I can see for that, easy to read, so that would go nicely in the code if needed. For example:
Code: Pascal  [Select][+][-]
  1.  side := 100*Dim.cm;

I created a GitHub repository called DimPas.
https://github.com/circular17/DimPas

Taking into account the remark about the confusion between TDuration and THours for example, I changed the names to units only. So TDuration is now TSeconds.

If you're interested by this project I will gladly give you access to the repository.
« Last Edit: January 30, 2023, 09:53:07 pm by circular »
Conscience is the debugger of the mind

avra

  • Hero Member
  • *****
  • Posts: 2443
    • Additional info
Re: Type checking of units of measurement
« Reply #31 on: January 31, 2023, 01:09:34 am »
I created a GitHub repository called DimPas.
https://github.com/circular17/DimPas
Sorry, GPL3 is a show stopper for me since I create closed source a lot. That fact also switched my point of view so now I would like to see it as a package in FPC only if license changes to something more liberal - at least FPC modified LGPL.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

Bogen85

  • Hero Member
  • *****
  • Posts: 572
Re: Type checking of units of measurement
« Reply #32 on: January 31, 2023, 01:31:06 am »
I created a GitHub repository called DimPas.
https://github.com/circular17/DimPas
Sorry, GPL3 is a show stopper for me since I create closed source a lot. That fact also switched my point of view so now I would like to see it as a package in FPC only if license changes to something more liberal - at least FPC modified LGPL.

That is a show stopper for me as well. I would also like to see this as a package in FPC.

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #33 on: January 31, 2023, 10:35:37 am »
Oh yes I forgot about linking. I modified the licenses to LGPL3+link exception.

By the way it is not a show for me, but a community project. Thanks for the precious input I've received so far.
« Last Edit: January 31, 2023, 12:07:37 pm by circular »
Conscience is the debugger of the mind

avra

  • Hero Member
  • *****
  • Posts: 2443
    • Additional info
Re: Type checking of units of measurement
« Reply #34 on: February 01, 2023, 11:58:41 am »
I modified the licenses to LGPL3+link exception.
Thanks!  :D

However, provided license LGPL3 on it's own (as given in https://github.com/circular17/DimPas/blob/main/LICENSE) does not include linking exception, according to https://tldrlegal.com/license/gnu-lesser-general-public-license-v3-(lgpl-3):
Quote
If you distribute this library in an executable, you must make the source available for 3 years.

If you want to explicitly allow linking exception, then this might be one of the ways:
https://wiki.lazarus.freepascal.org/FPC_modified_LGPL
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #35 on: February 01, 2023, 02:01:10 pm »
Yes, that's what I meant, I've put a LICENSE.modifiedLGPL file.
Conscience is the debugger of the mind

avra

  • Hero Member
  • *****
  • Posts: 2443
    • Additional info
Re: Type checking of units of measurement
« Reply #36 on: February 01, 2023, 06:19:02 pm »
I've put a LICENSE.modifiedLGPL file.
Thanks again!  :D 8-) :D
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #37 on: February 01, 2023, 10:13:49 pm »
You're welcome.  :)

Continuing my experiments, I've added reciprocal units, unit products, degC, degF, Hz, rad, deg, deg/s, deg/s2, N, C, lx, Sv, kat.

I will have less time available, so feel free to look at the code and propose improvements, new unit combinations etc.

Here is how the units are structured. The principle is to define base units (meter, gram, second), then combine them as ratio or product. For example, m/s (speed) is a ratio and A.s (coulomb) is a product.

Then units can be combined again. (m/s)/s = m/s2 is the speed. kg.(m/s2) is the newton.

The way a unit is defined define operators that can be applied to it. For example, a speed (m/s) can be multiplied by a time (s) which gives a length (m).

It is needed to define explicitly an operator to combine units. For the speed, it is the "/" operator on meters and seconds.

For complicated units, such as the newton N, which is defined as kg.((m/s)/s), the predefined operators are to divide it by a mass or an acceleration. Not to multiply it by a second, for example, even though the unit is equivalent to (kg.(m/s))/s. If such operator is useful, then it would make sense to add it to the Dim unit.
Conscience is the debugger of the mind

qk

  • New Member
  • *
  • Posts: 13
Re: Type checking of units of measurement
« Reply #38 on: February 01, 2023, 10:59:07 pm »
Nice work Circular !

For each units combination in needed to have specific operators for mul and div, I have correctly understood ?

Thanks.

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #39 on: February 01, 2023, 11:33:56 pm »
Thanks  :)

Most operators are defined by the generic classes, so that there is no need to define them specifically for one unit combination. But there is a need for at least one explicit operator in order to build the new combination of units and of quantities.

Here is an example for defining rad/s:
Code: Pascal  [Select][+][-]
  1. type
  2.   // not necessary but useful when using rad/s in a new combination like (rad/s)/s
  3.   TRadianPerSecond = specialize TRatioUnit<TRadian, TSecond>;
  4.  
  5.   // needed for rad/s
  6.   TRadianPerSecondIdentifier = specialize TRatioUnitIdentifier<TRadian, TSecond>;
  7.   TRadiansPerSecond = specialize TRatioDimensionedQuantity<TRadian, TSecond>;
  8.  
  9. // combining units
  10. operator /(const {%H-}rad: TRadianIdentifier; const {%H-}s: TSecondIdentifier): TRadianPerSecondIdentifier; inline;
  11.  
  12. // combining dimensioned quantities
  13. operator /(const AAngle: TRadians; const ADuration: TSeconds): TRadiansPerSecond; inline;
  14.  
  15. implementation
  16.  
  17. operator /(const rad: TRadianIdentifier; const s: TSecondIdentifier): TRadianPerSecondIdentifier;
  18. begin end;
  19.  
  20. operator /(const AAngle: TRadians; const ADuration: TSeconds): TRadiansPerSecond;
  21. begin
  22.  result.Value:= AAngle.Value / ADuration.Value;
  23. end;

Conscience is the debugger of the mind

qk

  • New Member
  • *
  • Posts: 13
Re: Type checking of units of measurement
« Reply #40 on: February 02, 2023, 12:00:52 am »
Thanks!

I'm playing with your old code (first approach) writing a tool for creating dim.pas unit automatically.
I can confirm you that a lot of operators are needed.

Your last code is too complex for me.
Regars

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #41 on: February 02, 2023, 12:50:36 am »
Cool. That's a lot of operators indeed  :D

I realize I had not defined the comparisons operators. I've added them.
https://github.com/circular17/DimPas/commit/b421924200f8f4e266add7f0f21bc58f26270275

I see you've done the factored squared/cubed quantities (km2, km3 etc.) which is a good idea. This is something that could be added to my version.

I think the multiplication of units in your code isn't correct regarding the factor
Code: Pascal  [Select][+][-]
  1. operator *(const ALeft: TLengthUnit; const ARight: TLengthUnit): TAreaUnit;
  2. begin
  3.   result.Symbol := 'm2';
  4.   result.Factor := 1;
  5. end;

The factor will be always 1 but for you could multiply kilometers for example. That's one of the reason why in the end I did not use variables to define the factors but class functions with a different type each time.
Conscience is the debugger of the mind

qk

  • New Member
  • *
  • Posts: 13
Re: Type checking of units of measurement
« Reply #42 on: February 03, 2023, 11:40:54 pm »
Hi Circular,

I'm trying to create TSquareMillimeter unit
Code: Pascal  [Select][+][-]
  1.   TSquareMillimeter = specialize TUnitSquared<TMilliMeter>;
  2.   TSquareMillimeters = specialize TSquaredDimensionedQuantity<TMilliMeter>;
  3.   TSquareMillimeterIdentifier = specialize TUnitSquaredIdentifier<TMilliMeter>;  
  4.  
but this code doesn't work.

When I try to multiply mm x mm the error is : Operator is not overloaded: "TFactoredDimensionedQuantity$2$crcAAEB45C2" * "TFactoredDimensionedQuantity$2$crcAAEB45C2"

Is it necessary to add a new operator *?
« Last Edit: February 03, 2023, 11:51:30 pm by qk »

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #43 on: February 04, 2023, 12:51:57 pm »
Hi qk,

TMillimeter is a factored unit and squaring is not implemented for that.

I am adding that to the Dim unit, I will let you know when I'm finished.
Conscience is the debugger of the mind

circular

  • Hero Member
  • *****
  • Posts: 3961
    • Personal webpage
Re: Type checking of units of measurement
« Reply #44 on: February 04, 2023, 01:32:55 pm »
Ok I'm done. By the way, I've added strict type checking for factored types, to avoid any possible mistake when defining derived types. So here's how you would define square millimeters:

Code: Pascal  [Select][+][-]
  1. type
  2.   TMillimeter = specialize TMilliUnit<TMeter>;
  3.   TSquareMillimeter = specialize TFactoredUnitSquared<TMillimeter>;
  4.   TSquareMillimeters = specialize TFactoredSquaredDimensionedQuantity<TMeter, TMillimeter>;
  5.   TSquareMillimeterIdentifier = specialize TFactoredUnitSquaredIdentifier<TMeter, TMillimeter>;
  6.  
  7. var
  8.   mm2: TSquareMillimeterIdentifier;

Note: you don't need to define any operators for square units. For cubic units, you would need to define what is the cubed unit divided by the squared unit like:
Code: Pascal  [Select][+][-]
  1. // combining units
  2. operator/(const m3: TCubicMeterIdentifier; const m2: TSquareMeterIdentifier): TMeterIdentifier;
  3. begin end;
  4.  
  5. // combining dimensioned quantities
  6. operator/(const AVolume: TCubicMeters; const ASurface: TSquareMeters): TMeters;
  7. begin
  8.   result.Value := AVolume.Value / ASurface.Value;
  9. end;

EDIT: I've refactored the code of dim.pas by putting the includes next to where they are used, it makes more sense this way.
https://github.com/circular17/DimPas/blob/main/dim.pas
« Last Edit: February 04, 2023, 02:06:46 pm by circular »
Conscience is the debugger of the mind

 

TinyPortal © 2005-2018