CVS difference for ai05s/ai05-0142-4.txt

Differences between 1.4 and version 1.5
Log of other versions for file ai05s/ai05-0142-4.txt

--- ai05s/ai05-0142-4.txt	2009/06/26 01:49:35	1.4
+++ ai05s/ai05-0142-4.txt	2009/10/23 06:06:31	1.5
@@ -2078,3 +2078,170 @@
 did look up I read in the paper RM, so I didn't see the AARM notes.
  
 ****************************************************************
+
+From: Christoph Grein
+Sent: Monday, July  6, 2009  4:44 AM
+
+I have a reference counting safe pointers package:
+
+generic
+
+  type Object is limited private;
+
+package Safe_Pointers.On_Limited_Types is
+
+  type Safe_Pointer is private;
+
+  function Value (Pointer: Safe_Pointer) return Object;
+  -- further operations
+
+private
+
+  -- not shown
+
+end Safe_Pointers.On_Limited_Types;
+
+This was valid in Ada 95: Value was a return-by-reference function and returned a constant
+view. Ada 2005 removed the return-by-reference-types, so I have to replace Value by:
+
+  function Value (Pointer: Safe_Pointer) return access Object;
+
+which ruins the safety I had before with safe pointers.
+
+If I understand the AI correctly, it would allow to define
+
+  type Accessor_Type (Element: not null access Object) is taged limited private;
+
+  function Accessor (Pointer: aliased in out Safe_Pointer) return Accessor_Type;
+
+and I could write
+
+  X: Accessor_Type := Accessor (My_Pointer);
+
+where X.Element.all is a constant view of the object denoted by My_Pointer (a variable view
+if Limited is removed everywhere above), which would restore the safety of my safe pointers.
+
+How would I define the complete type and the body of Value?
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, July 6, 2009  1:13 PM
+
+...
+> where X.Element.all is a constant view of the object denoted by 
+> My_Pointer (a variable view if Limited is removed everywhere above), 
+> which would restore the safety of my safe pointers.
+
+X.Element.all is always a variable view; if you wanted a constant view you would need to
+add "constant" to the discriminant declaration.
+
+> How would I define the complete type and the body of Value?
+
+Well, I assume you mean the body of "Accessor" in your example (you'd probably call that
+Value). It depends of course on what's in your private part, since you didn't give that I
+can only guess.
+
+Assuming that the type Safe_Pointer is implemented as follows:
+
+    type Unsafe_Pointer is access all Object;
+
+    type Safe_Pointer is record
+        Ptr : Unsafe_Pointer;
+        Refs : Natural := 0;
+        ...
+    end record;
+
+You can make your function Value very simple:
+
+    function Value (Pointer : aliased in Safe_Pointer) return access Object;
+
+with a body of
+
+    function Value (Pointer : aliased in Safe_Pointer) return access Object is
+    begin
+        return Pointer.Ptr;
+    end Value;
+
+This is safe because of the accessibility checks. The Pointer parameter to Value will be
+required to live longer than the function result. Typically, the function result will have
+a very local lifetime. That means that it cannot be assigned to any other access type, so
+about all that can be done with it is to dereference it. If you do manage to use the value
+in a context (that's easier for "access Object" than for the discriminant case) where it
+lives a long time, the parameter has to live as long or longer, so it stays safe.
+
+Note that you don't need "in out" here, because you aren't (ever) going to return part of
+the actual object. If your Safe_Pointer type could be defined:
+    type Safe_Pointer is record
+        Obj : aliased Object;
+        Refs : Natural := 0;
+        ...
+    end record;     
+then you would need "in out". (That can't happen in this case, but it can for the containers.)
+
+Note that you'd probably want to declare Safe_Pointer "tagged" so that your users wouldn't
+have to declare every object as "aliased".
+
+For this definition, I'm assuming that there aren't any operations that can invalidate an
+existing Safe_Pointer object. If such operations exist (seems likely), then you would want
+a more complex scheme where you can keep track of the existence of the (raw) pointer:
+
+   type Accessor_Type (Element: not null access Object) is tagged limited private;
+
+   function Value (Pointer: aliased in out Safe_Pointer) return Accessor_Type;
+
+For uses of Value, generally you would ignore the Accessor_Type object and just dereference
+the discriminant directly:
+
+   ... Value (My_Ptr).Element.all ...
+
+We'd add a Raw_Refs counter to the Safe_Pointer:
+
+    type Safe_Pointer is tagged record
+        Ptr : Unsafe_Pointer;
+        Refs : Natural := 0;
+        Raw_Refs : Natural := 0;
+        ...
+    end record;
+
+Accessor_Type would be defined as limited controlled so that you get an indication when
+the access ceases to exist:
+
+   type Accessor_Type (Element: not null access Object) is new Ada.Finalization.Limited_Controlled with record
+       My_Ptr : not null access Safe_Pointer; -- Default initialization will raise Constraint_Error.
+   end record;
+
+   procedure Finalize (Object : in out Accessor_Type);
+
+We want a default-initialized object of Accessor_Type to raise an exception, as we only want
+Value to create one. We can't use the unknown discriminants
+(<>) trick here, as the whole point is the discriminant.
+
+And the bodies:
+
+   function Value (Pointer: aliased in out Safe_Pointer) return Accessor_Type is
+   begin
+       Pointer.Raw_Refs := Pointer.Raw_Refs + 1;
+       return (Element => Pointer.Ptr, My_Ptr => Pointer'Access);
+   end Value;
+
+   procedure Finalize (Object : in out Accessor_Type) is
+   begin
+       Object.My_Ptr.Raw_Refs := Object.My_Ptr.Raw_Refs - 1;
+	    -- Will raise Constraint_Error if there is an underflow, that shouldn't be possible.
+   end Finalize;
+
+Then, any operation that invalidates a Safe_Pointer object should first check that the Raw_Refs counter
+is equal to 0; if it is not, an exception should be raised instead. (The containers raise Program_Error
+for a "tampering" event.)
+
+This way, once someone creates an access value to access the actual object, the Safe_Pointer will be
+"locked" against modification until the access value is no longer accessible (that is, the locking will
+continue so long as the access value exists).
+
+Of course, there are a number of ways to circumvent this safety (using Unchecked_Deallocation,
+Unchecked_Access, or Unchecked_Conversion). But that is true for any Ada feature; one has to assume
+that the programmers are not intentionally shooting themselves in the foot. (Uncontrolled use of
+"Unchecked" anything is dangerous - that's why they're called "Unchecked", after all.)
+
+****************************************************************

Questions? Ask the ACAA Technical Agent