yesterday I ran accross the following problem. Trying to write a little
tetris game as an excercise in Ada programming I wanted to initialize
an array of arrays of char i.e. the different shapes of stones. Not
being sure about the aggregate syntax I experimented with an array of
length 1 as a start.
This didn't work, not for the wrong aggregate syntax (which is similar
enough to C) but because of the array length 1.
Simplified I did this:
type stone is array (1..2) of character;
shapes: constant array (1..1) of stone := ("[]");
____________________________________________^
At this point I got an error message about type stone expected.
When using two stones, it works:
shapes: constant array (1..2) of stone := ("[]", "{}");
I further simplified it to this:
type t1 is array (1..1) of integer;
v1: constant t1 := (1234);
didn't work with the message aggregates of length 1 were not allowed.
Why? My books don't seem to know about (mention) this peculiarity.
I use gnat 2.0 on OS/2.
Dirk
---
d...@roxi.rz.fht-mannheim.de <Dirk Zoller>
The world is switching from the 'computers are magical, programmers are
magicians' to 'computer=TV+typewriter+fax+telephone' --- Will Baguhn
: type stone is array (1..2) of character;
: shapes: constant array (1..1) of stone := ("[]");
: ____________________________________________^
You're trying to squash a string of length 2 into a character space.
Try initializing like this:
shapes: constant array (1..1) of stone := (1 => ('[',']'));
Although type stone could have been declared as a subtype of STRING of
length 2, then your initialization would have worked.
--
=========================================================================
gen...@cnj.digex.net
Software Engineer (extraordinaire!)
Level: International Hacker
Edison, NJ
Too much of a good thing is WONDERFUL.
-- Mae West
=========================================================================
: type stone is array (1..2) of character;
: shapes: constant array (1..1) of stone := ("[]");
Try:
shapes: constant array (1..1) of stone := (others => "[]");
... Bill
Yes, this is an annoyance. You can't write a one-element positional
aggregate in Ada. Nor a zero-element aggregate.
To use a one-element aggregate, you have to use named notation, as in:
Shapes: constant array(1..1) of Stone := (1 => "[]");
Or:
Shapes: constant array(1..1) of Stone := (others => "[]");
> You're trying to squash a string of length 2 into a character space.
No, stone is a string of length two, and the string literal is of length
two, so that part of it is OK. The only thing wrong with the original
example is that it tries to use positional notation for a one-element
aggregate, which is not allowed -- named notation is required.
>Try initializing like this:
>
> shapes: constant array (1..1) of stone := (1 => ('[',']'));
^^^^^^^^^ This will
work, but you can use the string literal there instead, if you want.
>Although type stone could have been declared as a subtype of STRING of
>length 2, then your initialization would have worked.
String literals work for all string types. A string type is any
one-dimensional array type whose element type is a character type.
You don't have to use the predefined type String in order to use string
literals.
The reason for the aggregate restriction is that it would be difficult
for compilers to determine whether:
( exp )
is a parenthesized expression of some type, or an aggregate of an array
type. If Ada had used some other notation for aggregates (say, [...]),
then this problem would not exist. However, I believe the original
requirements for Ada forbade using certain Ascii characters, like [ and
], because those characters were not available on all hardware and
certain characters are used for different purposes in certain countries
that have addition letters not in Ascii.
It's still an annoyance not to have a clean notation for zero and one
element aggregates.
- Bob
--
Bob Duff bob...@inmet.com
Oak Tree Software, Inc.
Ada 9X Mapping/Revision Team (Intermetrics, Inc.)
: : type stone is array (1..2) of character;
: : shapes: constant array (1..1) of stone := ("[]");
: : ____________________________________________^
: You're trying to squash a string of length 2 into a character space.
: Try initializing like this:
: shapes: constant array (1..1) of stone := (1 => ('[',']'));
: Although type stone could have been declared as a subtype of STRING of
: length 2, then your initialization would have worked.
I don't think so. (Let's be careful, I did not check it in a reference,
either. But nevertheless, I'm just as sure as you were. :-)
The ""-literals are available for _all_ arrays of characters, not only for
the predefined type string. The ('[',']') aggregate is equivalent (as far as it
matters here) to the "[]" literal.
The reason why your code worked and the code of Dirk Zoller didn't was the
"1 =>".
For an Ada compiler ("[]") does not look like an array aggregate: It's a
single string. Therefore one has to use named notation like in (1=>"[]") or
(others=>"[]"). The latter works only if the range "others" stands for is
known to the compiler. (in this case, it is).
Declaring stone to be a subtype of STRING would probably be helpful when doing
output, though.
: Too much of a good thing is WONDERFUL.
: -- Mae West
Me, too.
-Jahn
really? that's surprising, because GNAT goes out of its way to give
a clear error message here:
1. procedure k is
2. type stone is array (1..2) of character;
3. shapes: constant array (1..1) of stone := ("[]");
|
>>> positional aggregate cannot have one component
4. begin
5. null;
6. end;
and that's exactly right, the fix is to make the aggregate named
(1 => "[]")
: type stone is array (1..2) of character;
: shapes: constant array (1..1) of stone := ("[]");
: ____________________________________________^
You're trying to squash a string of length 2 into a character space.
Try initializing like this:
shapes: constant array (1..1) of stone := (1 => ('[',']'));
is wrong, it is perfectly fine to initialze an object of type stone with
the string literal "[]
" which is essentially identical to the aggregate ('[',']')
the ONLY problem is the one element aggregate.
You're right. In fact the array I really used was 3-dimensional. In
that case the error message was misleading. (I mailed details to
Robert.)
Thanks for your comments. Guess I grok this point (initializers for
arrays length 1) now.
This solution, or
shapes : constant array (1..1) of stone := (1=> "[]");
is/are the correct one. But I thought your real question was, why doesn't
positional notation work for aggregates of length 1?
I had no idea and was curious myself, so I stuck your example into our
compiler which promptly pointed me to paragraph 4 of the "old" Ada LRM.
It says:
... Aggregates containing a single component association must always
be given in named notation.
Apparently this was carried into Ada95 as well.
Thanks for bringing up a new (to me at least) part of Ada.
Joe
> (1 => "[]")
I was always under the understanding that positional notation was
ambiguous for the length 0 and 1 cases. If this is so, how can
GNAT display a non-mabiguous messsage? Is ambiguous too strong a
statement here ? Maybe that's where I'm confused ?
Scott Leschke
--
Scott Leschke
Indeed this error message can't possibly be given in all situations (because
otherwise the language could allow it!)
Basically the cases that GNAT cannot correct are cases where you write
valid Ada 95 code that simply isn't quite what you meant:
procedure x (a : integer);
procedure x (a : array_of_integer);
now you write
x ((1));
thinking that you are calling the second version with an aggregate, when
in fact you have written a valid call to the first version.
However, if there is an error, GNAT does the following:
if I expect type vector of clunk
and I actually have something of type clunk
and the expression in question is parenthesized
then output the appropriate error message complaining about misuse
of 1-element positional aggregates.
of course no error message can always be "right". When a compiler detects
an error, it is in the business of producing the best guess as to what
was intended. The above check is just one of many heuristics in the GNAT
error detection intended to give more accurate messages.
By the way, whenever you get an error message you don't like from GNAT,
send a note to gnat-report. It is impossible to always give good error
messages, but often such suggestions are useful in tuning up the error
messages.
As I said earlier giving the "right" message when an attempt is made to
use a one element aggregate is not generally always possible (because
otherwise the language could allow it).
In the case of an inner aggregate, which was the case at hand, it is
theoretically possible to still give the "right" message, but much
harder, because the expected type is not at hand (remember that
aggregates are resolved independent of context in a situation like
this).
The GNAT processing is:
if type array-of-x is expected, and we have a parenthesized x instead
then give special error message.
What would be needed in the other case is much more complex:
attempt to resolve array aggregate
if it fails, see if there are cases of parenthesized expression(s) in
the aggregate, and treat them as positional aggregates, and retru the
resolution. if it works, then give the special error message
much more complex! furthermore if there are several parenthesized expressions
in the aggregate, say K of them, a really thorough attempt would require
2**K attempts at resolution, which is getting a bit out of hand..
The error message game is an interesting one of trading off effort vs
return. Correctness is not involved, since you can't always be correct
in the real sense (that would require telepathy), and it is trivial to
be formally correct (any error message at all, even a bomb saying simply
error, would be officially correct).
So you do the best you can!
As I requested before, always send in examples of confusing error messages,
it is pretty much impossible to tell how easy it is to "fix" such cases.
One more point is that the amount of effort that it is worth putting in
very much depends on ones estimate of the frequency of the error, and how
bad the consequences are of messing up.
For example, GNAT goes to rather strenous and complex efforts to diagnose
the misuse of IS for semicolon and vice versa in procedure specs and bodies.
But this is a case where the error is common, and the failure to do correct
error recovery can lead to VERY mysterious error messages.