News for hackers. Stuff that matters.
Re:Ada for the C++ and Java Developer [pdf] by EdwardDiego on Sunday March 28, 2021 @06:48AM (#26609294)
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.

Re:Ada for the C++ and Java Developer [pdf] by tmcb on Sunday March 28, 2021 @08:37AM (#26609813)
I 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;*
Re:Ada for the C++ and Java Developer [pdf] by yannickmoy on Monday March 29, 2021 @03:38AM (#26618624)
As 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_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;
Re:Ada for the C++ and Java Developer [pdf] by tmcb on Monday March 29, 2021 @04:26AM (#26618863)
Oh, thanks for pointing it out. Honestly, I was more interested in leveraging the type system than on proper dimensional analysis. I could find no mechanism by which Ada allows the programmer to disable the default operation overloads, so I decided to try that out.
Re:Ada for the C++ and Java Developer [pdf] by OneWingedShark on Tuesday March 30, 2021 @09:28AM (#26634356)
IIRC you can disable/forbid the default like so:

    Function "*"(Left, Right: Distance) return Distance is abstract;
then use:

    Function "*"(Left, Right : Distance) return Area;
Re:Ada for the C++ and Java Developer [pdf] by tmcb on Tuesday March 30, 2021 @11:28AM (#26635730)
That seems to do the trick for an individual predefined operator specification. Thanks!
Re:Ada for the C++ and Java Developer [pdf] by ajdude on Sunday March 28, 2021 @01:51PM (#26612458)
This is the right way to approach it on my opinion.
Re:Ada for the C++ and Java Developer [pdf] by foerbert on Sunday March 28, 2021 @08:14AM (#26609666)
There 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/Perfor... [1]https://blog.adacore.com/uploads/dc.pdf

Re:Ada for the C++ and Java Developer [pdf] by pjmlp on Sunday March 28, 2021 @09:28AM (#26610204)
PTC also supports Ada 2012.
Re:Ada for the C++ and Java Developer [pdf] by bob-ROS on Sunday March 28, 2021 @07:39AM (#26609493)
I 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"
Re:Ada for the C++ and Java Developer [pdf] by Asooka on Sunday March 28, 2021 @08:14AM (#26609672)
Could you do

    return Area(Float (Left) * Float (Right));
Re:Ada for the C++ and Java Developer [pdf] by bob-ROS on Sunday March 28, 2021 @08:23AM (#26609738)
Yes, that works.
Re:Ada for the C++ and Java Developer [pdf] by webreac on Sunday March 28, 2021 @04:29PM (#26614179)
Could you do

  return Area (Distance (Left * Right));

?
Re:Ada for the C++ and Java Developer [pdf] by OneWingedShark on Tuesday March 30, 2021 @09:33AM (#26634413)
IIRC, 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.)
Re:Ada for the C++ and Java Developer [pdf] by okl on Sunday March 28, 2021 @11:05AM (#26610943)
There's a library for that: http://www.dmitry-kazakov.de/ada/units.htm
Re:Ada for the C++ and Java Developer [pdf] by Avshalom on Sunday March 28, 2021 @07:14AM (#26609378)
It 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.

Re:Ada for the C++ and Java Developer [pdf] by synack on Sunday March 28, 2021 @09:07AM (#26610011)
The Units library does exactly what you describe. http://www.dmitry-kazakov.de/ada/units.htm