Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent to accessors in Ada

Tags:

accessor

ada

Is there a way to create an equivalent to C# get/set in Ada ?

I have a type like this (in Ada) :

-- Ada :
type MyType is record 
    Value : Integer;
end record;

I want to split the value like this

-- Ada :
type MyType is record 
    ten  : Integer;
    unit : Integer;
end record;

But I want to keep MyType.Value (referenced in many readonly files). I want to create an accessor but I did not find how to do in Ada. I know how to do in C# :

// C# :
int Value
{
    get
    {
        return this.ten * 10 + this.unit;
    }
    set
    {
        this.unit = value % 10;
        this.ten = value / 10;
    }
}

What I want to do :

-- ada :
MyType var := MyType'(Value => 15); -- unmodified code
var.Value := 65; -- can be modified like before

Integer ten := var.ten; -- new getter
like image 250
A.Pissicat Avatar asked Dec 22 '22 20:12

A.Pissicat


2 Answers

This is a job for a private type.

package Hidden is
   type T is tagged private;

   function New_T (Value : Integer) return T;

   function Value (Tee : T) return Integer;
   function Ten   (Tee : T) return Integer;
   function Unit  (Tee : T) return Integer;
private -- Hidden
   type T is tagged record
      Ten  : Integer;
      Unit : Integer;
   end record;
   ...
end Hidden;

Now you can write things like

V : T := New_T (42);
...
Put_Line (Item => V.Value'Image & V.Ten'Image & V.Unit'Image);
V := New_T (23);
like image 65
Jeffrey R. Carter Avatar answered Feb 04 '23 09:02

Jeffrey R. Carter


As I said in the comment of my answer to your previous question, There's no language construct that does it for you. Depending on your use-case, you could possibly employ controlled types:

type MyTypeView (Data : not null access MyType) is limited
  new Ada.Finalization.Limited_Controlled with record
   Value: Integer;
end record;

overriding procedure Initialize (Object : in out MyTypeView) is
begin
   Object.Value := Object.Data.ten * 10 + Object.Data.unit;
end Initialize;

overriding procedure Finalize (Object : in out MyTypeView) is
begin
   Object.Data.ten := Object.Value / 10;
   Object.Data.unit := Object.Value mod 10;
end Finalize;

This would allow you to alter the Value in the way you want with the View:

declare
   --  assuming MyObj is an object of type MyType
   View : MyTypeView (MyObj'Access);
   --  Initialize will be called, setting View.Value
begin
   --  can access value as "property"
   Do_Something (View.Value);
   --  can assign value as "property"
   View.Value := 123;
   --  when View goes out of scope, Finalize will be called, updating MyObj
end;

Note however that as long as View lives, View.Value is detached from the original object, meaning that at the end;, other modifications of MyObj that happened after View has been created will be discarded. In a single-threaded program, this means that you may not call any subroutines that may instantiate a View of the same object while the current view lives (and may not directly instantiate a second View of this object inside the block).

like image 45
flyx Avatar answered Feb 04 '23 07:02

flyx