CVS difference for ais/ai-00383.txt

Differences between 1.1 and version 1.2
Log of other versions for file ais/ai-00383.txt

--- ais/ai-00383.txt	2004/08/31 23:05:25	1.1
+++ ais/ai-00383.txt	2004/09/04 01:13:46	1.2
@@ -4,7 +4,7 @@
 !status received 04-08-31
 !priority Low
 !difficulty Medium
-!subject
+!subject Unconstrained arrays and C interfacing
 
 !summary
 
@@ -138,3 +138,422 @@
 implementation from doing this if they can figure out some meaning for it.
 
 ****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, August 31, 2004  8:21 PM
+
+We support unconstrained arrays as parameters in C conventions
+by giving the array the maximum bounds (i.e. index_subtype'first ..
+index_subtype'last).  Clearly there needs to be some other parameter
+which conveys the length, or some convention such as null termination.
+
+We have one customer who has requested a new convention, which
+we call "C_With_Array_Len" which adds an extra parameter in
+the C interface corresponding to the length of the array,
+so that the bounds become index_subtype'first .. index_subtype'first +
+len-param - 1.  If the array is multidimensional, a separate
+"len" parameter is added for each dimension.
+
+I'm not recommending this to be standardized, but it does indicate
+that some people are uncomfortable with our "standard" max-range
+approach.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, September 1, 2004  8:39 AM
+
+Related to this is the issue that Address_To_Access conversions
+cannot work with unconstrained arrays.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, September 1, 2004  3:46 PM
+
+For the record, that's not strictly true; it works fine in Janus/Ada. But
+that's because we ignore Implementation Advice 13.3(14) [following it would
+have been incompatible with our Ada 83 compilers, and would have caused
+problems with some run-time code - as then there would be no way to access the
+array descriptors. It also would mean that it would be impossible to use an
+Address Clause with a constrained at creation array object.]. ('Address and
+'Access in Janus/Ada always point at the top-level object; for an array of size
+not known at compile-time, that's the array descriptor, not the data. The same
+is true for a component constrained by a discriminant.)
+
+But it's clearly not portable (and contrary to the mentioned IA), so it would
+make sense to discuss this case as well in the AI.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, September 1, 2004  4:17 PM
+
+> For the record, that's not strictly true; it works fine in Janus/Ada. But
+> that's because we ignore Implementation Advice 13.3(14)
+
+Ouch! I would guess most of our customers big programs depend on that IA :-)
+
+> But it's clearly not portable (and contrary to the mentioned IA), so it
+> would make sense to discuss this case as well in the AI.
+
+Well if making something work means breaking some (really important in my
+view) IA, that's definitely an issue :-)
+
+What we do is to generate a warning that To_Pointer cannot be expected
+to be useful in this case:
+
+      3.    package A is new System.Address_To_Access_Conversions (String);
+            |
+         >>> warning: in instantiation at s-atacco.ads:45
+         >>> warning: Object is unconstrained array type
+         >>> warning: To_Pointer results may not have bounds
+
+In fact in GNAT the "may" is here because if the address was originally
+obtained by taking the address of a string, then the bounds may actually
+be where they are expected to be :-)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, September 1, 2004  4:24 PM
+
+> We have one customer who has requested a new convention, which
+> we call "C_With_Array_Len" which adds an extra parameter in
+> the C interface corresponding to the length of the array,
+> so that the bounds become index_subtype'first .. index_subtype'first +
+> len-param - 1.  If the array is multidimensional, a separate
+> "len" parameter is added for each dimension.
+>
+> I'm not recommending this to be standardized, but it does indicate
+> that some people are uncomfortable with our "standard" max-range
+> approach.
+
+Actually I think this is something that would be worth while
+semi-standardizing. GNAT tends to absorb such things anyway,
+so I think it might be worth including this as implementation
+advice. I trust it won't get too complicated (*).
+
+An alternative to having an extra parameter is to pass a descriptor.
+This is what is done in VMS for pass by descriptor.
+
+It also seems a shame to assume index_subtype'first, why not pass
+the bounds properly?
+
+(*) We just finished implementing the full blown Unchecked_Union.
+What a nightmare! And the sad thing is that our best guess is
+that none of the fancy extra features will get actually used :-(
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, September 1, 2004  4:48 PM
+
+> It also seems a shame to assume index_subtype'first, why not pass
+> the bounds properly?
+
+We are trying to present an interface that means something
+to a C programmer.  Arrays in C only have a length.  The
+low bound is always 0.  In Ada, the programmer gets to
+choose what is the more natural low bound (0, 1, whatever),
+but the C programmer needn't be bothered with this
+nicety.
+
+> (*) We just finished implementing the full blown Unchecked_Union.
+> What a nightmare! And the sad thing is that our best guess is
+> that none of the fancy extra features will get actually used :-(
+
+In our C code, we have many struct/union trees that match what
+the "full blown" Unchecked_Union is designed to support.
+For what that is worth...
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, September 1, 2004  5:14 PM
+
+Tucker Taft wrote:
+
+> In our C code, we have many struct/union trees that match what
+> the "full blown" Unchecked_Union is designed to support.
+> For what that is worth...
+
+But C unions don't allow more than one component in each variant!
+
+Also, it is not the data layout that is the issue, it is all the
+special casees of allowing things like equality when you can figure
+out the discriminants.
+
+Did you implement this feature fully yet?
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Thursday, September 2, 2004  7:38 AM
+
+If we are in the business of fixing A_To_A_Conversion, I would be in favor
+of making the access type a formal type (I know, for compatibility a new
+generic would be required).  It is totally dumb that each instantiation of
+this generic creates a collection, for which you cannot specify the
+storage size.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Thursday, September 2, 2004  7:56 AM
+
+Mea Culpa.  I wrote that section.  I did it that way on purpose, but
+after having used the thing a few times, I realized it is, as you say,
+"totally dumb".  But I don't think it's important enough to bother
+fixing.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Friday, September 3, 2004  3:14 AM
+
+Indeed! This is a fundamental inconsistency which should be fixed. moreover
+you cannot specify a storage pool, which is even worse.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Friday, September 3, 2004  7:19 AM
+
+I'm not sure I understand the concern here.  The generic
+is intended to provide an access value given an address.
+It was never expected that such an access value would
+be considered equivalent to an access value created by
+an allocator.  This generic is more like GNAT's
+'Unrestricted_Access. So what possible meaning would
+there be for the storage size or storage pool, since those
+attributes are relevant only for allocators (and unchecked
+deallocation)?
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Friday, September 3, 2004  8:20 AM
+
+I might add that anonymous access types, which we are
+now allowing in more contexts, have the same property
+of not allowing the specification of storage size or
+storage pool.  So this all sounds like a tempest
+in a teapot to me.  Do people really have a bunch
+of these A_To_A instantiations all over the place?
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Friday, September 3, 2004  8:58 AM
+
+I agree that it's a tempest in a tea pot.
+
+I think the issue is not Storage_Pool per se.  The issue is that if you
+have an access type, and you want to convert an Address value to that
+type, you have to call the To_Pointer function from the instance, and
+then convert *that* to your access type, using a normal type conversion.
+It would be slightly cleaner to be able to convert directly.
+
+So why don't you just use the access type declared in the instance of
+Address_To_Access_Conversions?  I think Pascal was saying, "Because I
+want a Storage_Size clause", and Robert was saying, "Yeah, and because I
+want a Storage_Pool clause."  Another obvious reason is that your access
+type belongs in a package spec, and the instance belongs in the body.
+
+I still say: it's not broken enough to fix.  Just put in the silly extra
+type conversion.  One hopes not to use this feature very often!
+
+By the way, why would you want to use Address_To_Access_Conversions to
+go the other direction?  I mean, isn't X.all'Address sufficient?
+(I usually don't want nulls in these cases...)
+
+P.S. The reason I didn't do it Pascal's way in the first place, is that
+I imagined the only usage would be for "peek/poke" functionality.  That
+is, I thought you would always do something like this:
+
+    Thing: Integer renames To_Pointer(Some_Address).all;
+
+    Thing := Thing + 1;
+
+with an immediate .all, and you don't care what the access type is.
+Declaring one and passing it to the instantiation is just annoying
+verbosity in this case.
+(In fact, you want an anonymous access type!)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Friday, September 3, 2004  3:54 PM
+
+Well I think it would be reasonable to have a note in the RM noting
+the case that is unlikely to work, or rather unlikely to work in
+anything approximating a portable manner.
+
+> I think the issue is not Storage_Pool per se.  The issue is that if you
+> have an access type, and you want to convert an Address value to that
+> type, you have to call the To_Pointer function from the instance, and
+> then convert *that* to your access type, using a normal type conversion.
+> It would be slightly cleaner to be able to convert directly.
+
+Can you say what you mean here, you can't just go converting access
+types when storage pools are involved???
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Friday, September 3, 2004  7:12 PM
+
+While I generally agree with you and Pascal on this topic, I don't understand
+the above. There is no restriction on converting between general access types
+as long as they designate the same type. The only problem comes if you call
+Unchecked_Deallocation on an access from another pool; that's defined to be
+erroneous in 13.11.2(16).
+
+Even if you had an A_to_A that allowed an access type with a pool, I would hope
+that using Unchecked_Deallocation on the result would still be erroneous. (It
+certainly wouldn't be meaningful unless it was previous allocated from that
+pool - in which case, why the heck do you need A_to_A??) So there isn't going
+to be any semantic difference here.
+
+The real issue to me is that we expanded the use of anonymous access types
+specifically so we could get rid of unnecessary explicit conversions, as
+they're confusing to the reader (a type conversion is supposed to indicate
+something happening). This is another source of unnecessary conversions, and it
+would make sense to get rid of them here as well.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Friday, September 3, 2004  7:30 PM
+
+> Well I think it would be reasonable to have a note in the RM noting
+> the case that is unlikely to work, or rather unlikely to work in
+> anything approximating a portable manner.
+
+You mean the access-to-unc-array case?  Yeah, a note seems reasonable.
+
+> > I think the issue is not Storage_Pool per se.  The issue is that if you
+> > have an access type, and you want to convert an Address value to that
+> > type, you have to call the To_Pointer function from the instance, and
+> > then convert *that* to your access type, using a normal type conversion.
+> > It would be slightly cleaner to be able to convert directly.
+>
+> Can you say what you mean here, you can't just go converting access
+> types when storage pools are involved???
+
+The package as currently defined:
+
+      generic
+          type Object(<>) is limited private;
+      package System.Address_To_Access_Conversions is
+         pragma Preelaborate(Address_To_Access_Conversions);
+
+         type Object_Pointer is access all Object;
+         function To_Pointer(Value : Address) return Object_Pointer;
+         ...
+      end System.Address_To_Access_Conversions;
+
+I thought Pascal's proposal was to change it to:
+
+      generic
+          type Object(<>) is limited private;
+          type Object_Pointer is access all Object;
+      package System.Address_To_Access_Conversions is
+         pragma Preelaborate(Address_To_Access_Conversions);
+
+         function To_Pointer(Value : Address) return Object_Pointer;
+         ...
+      end System.Address_To_Access_Conversions;
+
+That is, make the pointer type into a generic formal.
+
+With the current language, one can do this:
+
+    package Things is
+        type Thing is ...
+        type Thing_Ptr is access all Thing;
+        for Thing_Ptr'Storage_Pool use ...;
+        ...
+    end Things;
+
+    with System.Address_To_Access_Conversions;
+    package body Things is
+        package Conv is new System.Address_To_Access_Conversions(Thing);
+
+        function F(...) return Thing_Ptr is
+        begin
+            return Thing_Ptr(Conv.To_Pointer(Some_Address));
+
+With Pascal's proposal, the body becomes:
+
+    with System.Address_To_Access_Conversions;
+    package body Things is
+        package Conv is new
+            System.Address_To_Access_Conversions(Thing, Thing_Ptr);
+
+        function F(...) return Thing_Ptr is
+        begin
+            return Conv.To_Pointer(Some_Address);
+
+That is, the type conversion to Thing_Ptr is eliminated.  Either way, Thing_Ptr
+can have a Storage_Pool or Storage_Size clause.  And either way, the programmer
+had better ensure that Some_Address "makes sense" as a value of type Thing_Ptr.
+And either way, if you try to use Unchecked_Dealloc, you better make
+sure it originally came from the same pool.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Friday, September 3, 2004  7:41 PM
+
+> While I generally agree with you and Pascal on this topic, I don't
+> understand the above. There is no restriction on converting between general
+> access types as long as they designate the same type. The only problem comes
+> if you call Unchecked_Deallocation on an access from another pool; that's
+> defined to be erroneous in 13.11.2(16).
+
+Right.
+
+> Even if you had an A_to_A that allowed an access type with a pool, I would
+> hope that using Unchecked_Deallocation on the result would still be
+> erroneous.
+
+Yes.
+
+>... (It certainly wouldn't be meaningful unless it was previous
+> allocated from that pool - in which case, why the heck do you need A_to_A??)
+
+If you're playing games with storage pools, you might have a function
+that allocates some storage, and returns a pointer to that storage plus
+some offset.  And deallocate might need to recover the original storage
+pointer by subtracting that offset.  I've done something like that in
+low-level storage-pool code, where *this* storage pool is allocating
+hunks of storage from an underlying storage pool.
+
+> So there isn't going to be any semantic difference here.
+
+Right.
+
+> The real issue to me is that we expanded the use of anonymous access types
+> specifically so we could get rid of unnecessary explicit conversions, as
+> they're confusing to the reader (a type conversion is supposed to indicate
+> something happening). This is another source of unnecessary conversions, and
+> it would make sense to get rid of them here as well.
+
+Right.  So should it be:
+
+      generic
+          type Object(<>) is limited private;
+      package System.Address_To_Access_Conversions is
+         pragma Preelaborate(Address_To_Access_Conversions);
+
+         function To_Pointer(Value : Address) return access all Object;
+         ...                                         ^^^^^^^^^^^^^^^^^
+      end System.Address_To_Access_Conversions;
+
+where the result of To_Pointer can be *implicitly* converted to whatever
+appropriate access type you like?  Or something like that?
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent