Version 1.1 of acs/ac-00101.txt

Unformatted version of acs/ac-00101.txt version 1.1
Other versions for file acs/ac-00101.txt

!standard 13.11(24)          04-10-05 AC95-00101/01
!class confirmation 04-10-05
!status received no action 04-10-05
!status received 04-09-20
!subject New for constants
!summary
!appendix

From: Martin Krischik
Sent: Monday, September 20, 2004  2:47 AM

on c.l.a there had been an interesting observation:

Georg Bauhaus <sb463ba@l1-hrz.uni-duisburg.de> writes:

> If the pointers are to constant strings (I should have stressed
> this) there is no call to __gnat_malloc. As is
>
>   type String_P is access constant String;
>   S : constant String_P := new String'("foo!");

However, no one there was able to confirm if this is a gnat specific
optimisation or a true language feature.

Any comments?

****************************************************************

From: Florian Weimer
Sent: Monday, September 20, 2004  6:04 AM

See 13.11(24):

 24. A default (implementation-provided) storage pool for an
     access-to-constant type should not have overhead to support
     deallocation of individual objects.

****************************************************************

From: Martin Krischik
Sent: Tuesday, September 21, 2004  2:45 AM

Thank you - now I see - If deallocation is not needed then allocation is not
needed as well. Cool.

****************************************************************

From: Pascal Leroy
Sent: Wednesday, September 22, 2004  3:37 AM

No, this is confused.

13.11(24) is an implementation advice, so it is not binding, and an
implementation is free to ignore it.  At any rate, the reason for this
advice is that Unchecked_Deallocation is not available for an access to
constant, so there is no need to do the bookkeeping that is normally
required to properly deallocate objects.  This has nothing to do with how
the allocation is performed.

AARM 13.11(24.b) notes that, if the size of the allocated object is known
at compile time, the entire allocation may be avoided.  This is apparently
what GNAT does, and it's a good optimization, but it's not required by the
language.  Interestingly, the same paragraph points out that Storage_Error
should be raised in the following case:

	type String_P is access constant String;
	for String_P'Storage_Size use 0;
	S : constant String_P := new String'("foo!");

So this probably means that some code must be emitted on the allocator to
check for the size consumed in the storage pool, even if there is no
dynamic allocation.

Because this optimization is not a requirement of the language (it's not
testable in the first place), the portable idiom to avoid dynamic
allocation is the following:

	type String_P is access constant String;
	X : aliased constant String := "foo!";
	S : constant String_P := X'Access;

****************************************************************

From: Tucker Taft
Sent: Wednesday, September 22, 2004  7:01 AM

For what it is worth, the AdaMagic front end performs
this same "optimization."  That means that Aonix and
Green Hills compilers also have it.  One of the intents
was that a "ragged" table of strings could be created
fully statically as follows:

     type Message is access constant String;
     Message_Table : constant array(Positive range <>) of Message :=
       (1 => new String'("syntax error"),
        2 => new String'("undefined identifier"),
        3 => new String'("ambiguous expression"),
        ...);

This kind of thing is trivial to do in C, because C string
literals automatically become pointers to statically
allocated, statically initialized arrays of characters.
We were trying to enable the same thing in Ada.

As Pascal points out, explicitly declaring each string
separately as an aliased constant, and then using 'Access,
works in all compilers.  The above approach
works in "most" compilers, if that is enough for
you (I'll admit to being a bit disappointed that it doesn't
work in all Ada 95 compilers, given our original intent).

****************************************************************

From: Martin Dowie
Sent: Wednesday, September 22, 2004  7:43 AM

But ObjectAda (7.2.2 U14) doesn't seem to conform with
Pascal's other assertion regarding Storage_Error. So,
is that a bug or is Pascal incorrect?

****************************************************************

From: Pascal Leroy
Sent: Wednesday, September 22, 2004  8:50 AM

I was quite surprised myself to see this advice in the AARM, as it seems
that the check for Storage_Error would defeat the purpose of the
optimization.  On the other hand, setting the storage size to 0 is a
convenient idiom to prevent allocators for a given type, so one could
argue that a violation should be detected.  On the third hand this is
implementation advice anyway, so a compiler can pretty much do what it
wants.

****************************************************************

From: Tucker Taft
Sent: Wednesday, September 22, 2004  11:34 AM

I think the intent was to recognize
"for A'Storage_Size use 0;" as a way to disallow
allocators for a given access type, even for
access-to-constant.  There was not an expectation
that for storage sizes > 0 that there would be
any attempt to count total statically allocated
storage associated with an access-to-constant
type.

Of course "intent" is not a language rule. ;-)
However, the use of a zero storage size is becoming
a more "enshrined" feature of Ada 2005, so one
might expect that in Ada 2005, this implementation
advice would become a requirement.

****************************************************************

From: Robert Leif
Sent: Wednesday, September 22, 2004  3:31 PM

   Where is this?  It would be exceedingly useful to have 0 size types.  If
one has a possibility of performing 50 different measurements and only
wishes to store an arbitrary number of them, a variant record that includes
a type which requires no storage space should work.

****************************************************************

From: Robert A. Duff
Sent: Wednesday, September 22, 2004  3:07 PM

> AARM 13.11(24.b) notes that, if the size of the allocated object is known
> at compile time, the entire allocation may be avoided.  This is apparently
> what GNAT does, and it's a good optimization, but it's not required by the
> language.  Interestingly, the same paragraph points out that Storage_Error
> should be raised in the following case:
>
> 	type String_P is access constant String;
> 	for String_P'Storage_Size use 0;
> 	S : constant String_P := new String'("foo!");
>
> So this probably means that some code must be emitted on the allocator to
> check for the size consumed in the storage pool, even if there is no
> dynamic allocation.

Only if the Storage_Size is specified, which I suspect is vanishingly
rare for access-to-constant types intended to be used for static
allocation.  And if the Storage_Size is zero, it is almost certainly
known at compile time to be zero.  So I don't see any gratuitous
overhead to worry about here.  If you don't want checking for
Storage_Size, then don't specify it -- seems simple enough.

> Because this optimization is not a requirement of the language (it's not
> testable in the first place), the portable idiom to avoid dynamic
> allocation is the following:
>
> 	type String_P is access constant String;
> 	X : aliased constant String := "foo!";
> 	S : constant String_P := X'Access;

Well, *that*'s not required by the language, either.

> One of the intents
> was that a "ragged" table of strings could be created
> fully statically as follows:
>
>      type Message is access constant String;
>      Message_Table : constant array(Positive range <>) of Message :=
>        (1 => new String'("syntax error"),
>         2 => new String'("undefined identifier"),
>         3 => new String'("ambiguous expression"),
>         ...);

I wonder if it might have been better to support this idiom like this:

     Message_Table : constant array(Positive range <>) of Message :=
       (1 => "syntax error" 'Access,
        2 => "undefined identifier" 'Access,
        3 => "ambiguous expression" 'Access,
        ...);

which is essentially the same as what you do in C, except that Ada
doesn't have implicit conversion of arrays to pointers.

The above is syntactically illegal, of course.  That's due to the Ada 83
distinction between "objects" and "values", and the corresponding
syntactic distinction between "names" and "expressions".  That
distinction is unhelpful, in my opinion (a constant object ought to be
essentially the same thing as a value).  And, in fact, we found it
necessary to eliminate most of that distinction because of finalization
issues (result of a function is now a constant object).  We didn't
finish the job.

I've occasionally wanted to say things like:

    X: constant Natural := ("Hello")'Length;

as well.  Oh, well.

> As Pascal points out, explicitly declaring each string
> separately as an aliased constant, and then using 'Access,
> works in all compilers.

Well, it's not *required* to work (if "work" means "no heap
allocation").  And in fact some compilers *do* use heap allocation --
for example, the version of AdaMagic that is targeted to the Java
Virtual Machine.

I suppose the C idiom isn't required to work, either.  If you wrote a
C-to-JVM translator, it would probably do heap allocation for this idiom
as well (and represent C pointers as fat: Java reference plus offset).

>...  The above approach
> works in "most" compilers, if that is enough for
> you (I'll admit to being a bit disappointed that it doesn't
> work in all Ada 95 compilers, given our original intent).

I'm also a bit disappointed by this lack of uniformity.  Compilers
really *ought* to follow the advice, except when it's unreasonable
(like, you're targeting the JVM).  Perhaps if our syntax for this idiom
didn't include "new", it would have been more obvious.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, September 22, 2004  4:57 PM

Advice didn't need to have the broad consensus that normative parts of the
standard have. On several occasions when I lobbied against bad Advice
(including *this* Advice), I was told that "it's only Advice. You're free to
ignore it." Either that is true, or Advice like this doesn't belong in the
Standard in the first place.

In any case, this is bad advice because:
   -- It exists to support a programming style that should be avoided
(explicit use of access types for a non-dynamic structure);
   -- It is confusing to the reader ("new" means dynamic, except in this
special and unlikely case);
   -- It is worrying about a case that rarely comes up in practice;
   -- And it is contrary to current security thinking (which I've always
advocated) of keeping your code/constants separate from your data/stack. (We
use separate data spaces for these two areas, which of course might have to
be mapped to a single data space on OSes too dumb to understand the
distinction.)

The claim that we should all follow Advice, bad or not, unless there is no
practical alternative is silly. We don't follow the "Address should be
private" advice, either, because it would have seriously broken most of the
existing Janus/Ada runtime and most existing C interface code. Of course, we
*could* follow the advice (there is no technical reason for not doing so),
and your claim is that we should, no matter how much pain it makes for us
and our customers. That certainly is silly.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, September 22, 2004  7:23 PM

> Advice didn't need to have the broad consensus that normative parts of the
> standard have. On several occasions when I lobbied against bad Advice
> (including *this* Advice), I was told that "it's only Advice. You're free to
> ignore it." Either that is true, or Advice like this doesn't belong in the
> Standard in the first place.

Agreed.  As an implementer, you have complete freedom to ignore the impl
advice.  I don't happen to agree with your decision in this case, but
that's OK.

> The claim that we should all follow Advice, bad or not, unless there is no
> practical alternative is silly. We don't follow the "Address should be
> private" advice, either, because it would have seriously broken most of the
> existing Janus/Ada runtime and most existing C interface code. Of course, we
> *could* follow the advice (there is no technical reason for not doing so),
> and your claim is that we should, no matter how much pain it makes for us
> and our customers. That certainly is silly.

I made no such (silly) claim.  I said we should all follow the advice,
unless it's unreasonable to do so.  I gave one example (tthe Java target
prettty-much requires heap alloc).  But I certainly agree with you that
it's also unreasonable for an Ada 83 compiler converted to Ada 95 to
introduce gratuitous incompatibilities.

Note that the "Impl Advice" is not really advice on how to write your
compiler.  It's a "hope" that if there are two different ways off doing
things, we can push compiler implementers toward the same way.
Uniformity, and not Goodness, is the primary goal of Standards.

- Bob

P.S. I'm not that bad at spelling or typing -- my keyboard is acting up!

****************************************************************


Questions? Ask the ACAA Technical Agent