4 ms·
If any Ada users are here, I have question on one section: procedure Main is type Distance is new Float; type Area is new Float; D1 : Distanc
by EdwardDiego 6y ago
If any Ada users are here, I have question on one section:
procedure Main is
type Distance is new Float;
type Area is new Float;
D1 : Distance := 2.0;
D2 : Distance := 3.0;
A : Area;
begin
D1 := D1 + D2; -- OK
D1 := D1 + A; -- NOT OK: incompatible types for "+" operator
A := D1 * D2; -- NOT OK: incompatible types for ":=" assignment
A := Area (D1 * D2); -- OK
end Main;
> The predefined Ada rules are not perfect; they admit some problematic cases (for example multiplying two Distances yields a Distance) and prohibit some useful cases (for example multiplying two Distances should deliver an Area). These situations can be handled through other mechanisms
I can get why you have to be explicit in type casts if you're trying to be safe, but is there any way to say that
type Area is Distance * Distance
Or
Type CubeVolume is Distance * Distance * Distance
So that of I say a: Area and b : CubeVolume and a := d1 * d2 it just works, and then b := a * d3 also works.
IOTW, explicit casts not needed.
Or is it the case that Ada really took the concept of "explicit is better than implicit" and went to town?
I just wonder because I love F#'s unit of measure types and how they can prevent logical type errors (say, multiplying 10 m/s by 3kg when assigning to a variable of type m/s^2).
Or for this case, if I wrote
x: Distance := y: Distance * z: Distance
It'd fail hard, because a Distance * a Distance is an Area.
I sorta figured Ada would have invented this sorta stuff and then it was cribbed by other languages.
So yeah, wondering what the other mechanisms the author mentions are. Because I've always heard Ada is great at type safety, so I'd be keen to see how safe it makes your code when combining values with units that aren't logical to combine.
- Avshalom 6y agoIt does have operator overloading so you could certainly define some function "*"(Left, Right : Distance) return Area and if dedicated enough build up a whole set of unit-types with corresponding conversion rules. Not an Ada guy at all though so no clue if there's a less by-hand way of doing it.
- synack 6y agoThe Units library does exactly what you describe. http://www.dmitry-kazakov.de/ada/units.htm http://www.dmitry-kazakov.de/ada/units.htm
- bob-ROS 6y agoI got it working with: with Ada.Text_IO; use Ada.Text_IO; procedure Main is type Distance is new Float; type Area is new Float; function "*" (Left, Right : Distance) return Area is temp : Distance; begin temp := Left * Right; return Area (temp); end "*"; D1 : Distance := 2.0; D2 : Distance := 3.0; A : Area; begin A := D1 * D2; -- OK Put_Line(A'Image); end Main; Interestingly, it took me several attempts to create this overload, make it a single line return would make it recursive: function "*" (Left, Right : Distance) return Area is begin return Left * Right; end "*"; -- ^ Does not work -- raised STORAGE_ERROR : stack overflow or erroneous memory access Also: function "*" (Left, Right : Distance) return Area is begin return Area (Left * Right); end "*"; -- ^ Does not work either, compiler gives me "ambiguous operand in conversion"
- Asooka 6y agoCould you do return Area(Float (Left) * Float (Right));
- OneWingedShark 6y agoIIRC, the one-liner here [assuming you disabled the default "" operator] would be: Return Area( Distance'Base'(Left * Right) ); The apostrophe at the inner portion is 'qualification', a method for directing the compiler that the enclosed value is supposed to be a particular subtype. (Typically used to resolve ambiguities.)
- foerbert 6y agoThere is now, at least with Ada 2012 and GNAT[0][1]. While I'm pretty sure only GNAT has implemented it, I'm not sure if it's actually in the 2012 standard or not. I haven't played with it yet, but it does looks pretty interesting. [0]https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gnat_ugn_unw/Performing-Dimensionality-Analysis-in-GNAT.html https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gnat_ugn_unw/Perfor... [1]https://blog.adacore.com/uploads/dc.pdf https://blog.adacore.com/uploads/dc.pdf
- pjmlp 6y agoPTC also supports Ada 2012.
- tmcb 6y agoI am not an Ada expert, but I came up with this. Please notice that the idea here is not to have the compiler do proper dimensional analysis but simply to avoid the default operator overloading of "*" for the Distance type that also returns a Distance value. Nothing very high-level, as we need to explicitly manipulate the single-component records, but it does the job. with Ada.Text_IO; use Ada.Text_IO; procedure Main is type Distance is record Value : Float; end record; type Area is record Value : Float; end record; function "*" (Left, Right : Distance) return Area is begin return (Value => Left.Value * Right.Value); end "*"; D1 : constant Distance := (Value => 10.0); D2 : constant Distance := (Value => 20.0); -- D3 : constant Distance := D1 * D2; -- Does not compile. GNAT returns the following error: -- main.adb:21:33: expected type "Distance" defined at line 4 -- main.adb:21:33: found type "Area" defined at line 8 A : constant Area := D1 * D2; begin Put_Line ("Area A is " & Float'Image(A.Value)); end Main;*
- ajdude 6y agoThis is the right way to approach it on my opinion.
- yannickmoy 6y agoAs someone said, the best solution here is to use the dimensionality analysis in GNAT: https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ugn/gnat_and_program_execution.html#performing-dimensionality-analysis-in-gnat https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ug... as in: with Ada.Text_IO; use Ada.Text_IO; with System.Dim.Float_Mks; use System.Dim.Float_Mks; with System.Dim.Float_Mks_IO; use System.Dim.Float_Mks_IO; procedure Main is subtype Distance is System.Dim.Float_Mks.Length; subtype Area is System.Dim.Float_Mks.Area; D1 : constant Distance := 10.0*m; D2 : constant Distance := 20.0*m; -- D3 : constant Distance := D1 * D2; -- Does not compile. GNAT returns the following error: -- main.adb:13:08: dimensions mismatch in object declaration -- main.adb:13:37: expected dimension [L], found [L**2] A : constant Area := D1 * D2; begin -- print: Area A is 2.00000E+02 m**2 Put ("Area A is "); Put (Item => A); Put_Line (""); end Main;
- okl 6y agoThere's a library for that: http://www.dmitry-kazakov.de/ada/units.htm http://www.dmitry-kazakov.de/ada/units.htm