Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Weird behavior with modular type

13 views
Skip to first unread message

Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 12:24:57 PM2/7/12
to
Hi all,

I expect the test to be shortened enough.


The following compiles and run without an error:


with Ada.Text_IO;
procedure Bug is

type Modular_Type is mod 256;
subtype Index_Type is Natural range 1 .. 3;

E : Modular_Type := 255;
I : Index_Type := 3;
B : Boolean;

begin
B := E < 10 ** I;
Ada.Text_IO.Put_Line (Boolean'Image (B));
end Bug;


It prints "FALSE"

Now, the following, with added “Natural'Pos (...)”, did not even compile:


with Ada.Text_IO;
procedure Bug is

type Modular_Type is mod 256;
subtype Index_Type is Natural range 1 .. 3;

E : Modular_Type := 255;
I : Index_Type := 3;
B : Boolean;

begin
B := E < Natural'Pos (10 ** I);
Ada.Text_IO.Put_Line (Boolean'Image (B));
end Bug;


That's counter intuitive. I would expect the first to behave as the
second, with either a failure to compile or range error at run‑time.

Someone remember a pointer to the most relevant part in the RM? I may be a
bit tired, could not find it.

Seems in the first case, the left‑side of “E < 10 ** I” has a modulo
applied, or else, I see no way to explain the result, "FALSE". But why
would this modulo be applied with a subtype of Natural and not with an
Universal_Integer?

I don't like it (and must be idiot in some way, don't you think?).


--
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University

Jeffrey Carter

unread,
Feb 7, 2012, 12:49:14 PM2/7/12
to
On 02/07/2012 10:24 AM, Yannick Duchêne (Hibou57) wrote:
>
> Seems in the first case, the left‑side of “E < 10 ** I” has a modulo applied, or
> else, I see no way to explain the result, "FALSE". But why would this modulo be
> applied with a subtype of Natural and not with an Universal_Integer?

Seems to me in both cases the expression on the right of "<" is
Universal_Integer. What compiler message did you get?

--
Jeff Carter
"Why, the Mayflower was full of Fireflies, and a few
horseflies, too. The Fireflies were on the upper deck,
and the horseflies were on the Fireflies."
Duck Soup
95

--- Posted via news://freenews.netfront.net/ - Complaints to ne...@netfront.net ---

Gautier write-only

unread,
Feb 7, 2012, 12:54:36 PM2/7/12
to
On 7 fév, 18:24, Yannick Duchêne (Hibou57)

>        B := E < 10 ** I;

E is of type Modular_Type.
10 ** I is untyped (Universal_Integer ?). It can be an expression of
type Modular_Type, among other possibilities.
So, the compiler chooses the "<" which has Modular_Type on both sides,
right ?
Then 10 ** 3 = 1000 = 232 (in the Modular_Type world) < 255 = E.
E is larger, thus the FALSE.
_________________________
Gautier's Ada programming
http://sf.net/users/gdemont

Adam Beneschan

unread,
Feb 7, 2012, 1:02:40 PM2/7/12
to
On Feb 7, 9:24 am, Yannick Duchêne (Hibou57)
<yannick_duch...@yahoo.fr> wrote:
>
> Now, the following, with added "Natural'Pos (...)", did not even compile:
>
> with Ada.Text_IO;
> procedure Bug is
>
> type Modular_Type is mod 256;
> subtype Index_Type is Natural range 1 .. 3;
>
> E : Modular_Type := 255;
> I : Index_Type := 3;
> B : Boolean;
>
> begin
> B := E < Natural'Pos (10 ** I);
> Ada.Text_IO.Put_Line (Boolean'Image (B));
> end Bug;
>
> That's counter intuitive. I would expect the first to behave as the
> second, with either a failure to compile or range error at run-time.

By the way, I don't see any reason this shouldn't compile, although
offhand I think it should raise a Constraint_Error at runtime (since
1024 would be the right argument of a function "<" (Left, Right : E)
return Boolean and 1024 can't be converted to E without a
Constraint_Error). When I compile on GNAT (4.5.2), it says "static
expression fails Constraint_Check". This looks like a GNAT bug,
though, because there's no static expression. Apparently it thinks
it's static because it knows the value of I must still be 3 at that
point, but that doesn't make it a static expression according to the
language rules, so the program shouldn't be rejected. (Inserting a
call to a null nested procedure before the first line of Bug makes the
error message go away.)

-- Adam

Adam Beneschan

unread,
Feb 7, 2012, 1:06:55 PM2/7/12
to
On Feb 7, 9:49 am, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org>
wrote:
> On 02/07/2012 10:24 AM, Yannick Duchêne (Hibou57) wrote:
> >
>
> > Seems in the first case, the left-side of "E < 10 ** I" has a modulo applied, or
> > else, I see no way to explain the result, "FALSE". But why would this modulo be
> > applied with a subtype of Natural and not with an Universal_Integer?
>
> Seems to me in both cases the expression on the right of "<" is
> Universal_Integer. What compiler message did you get?

If the argument on the right of "<" is a *static* Universal_Integer
whose value is larger than 255, then an error message should be
generated (4.9(35)). Here, the expression is not static, so there
shouldn't be an error; as I mentioned earlier, GNAT does give an error
which appears to me to be a compiler bug.

-- Adam

Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 1:13:04 PM2/7/12
to
Le Tue, 07 Feb 2012 18:24:57 +0100, Yannick Duchêne (Hibou57)
<yannick...@yahoo.fr> a écrit:
> Seems in the first case, the left‑side of “E < 10 ** I” has a modulo
> applied
Sorry, read "the right‑side".

Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 1:15:52 PM2/7/12
to
Le Tue, 07 Feb 2012 18:49:14 +0100, Jeffrey Carter
<spam.jrc...@spam.not.acm.org> a écrit:

> On 02/07/2012 10:24 AM, Yannick Duchêne (Hibou57) wrote:
> >
>> Seems in the first case, the left‑side of “E < 10 ** I” has a modulo
>> applied, or
>> else, I see no way to explain the result, "FALSE". But why would this
>> modulo be
>> applied with a subtype of Natural and not with an Universal_Integer?
>
> Seems to me in both cases the expression on the right of "<" is
> Universal_Integer. What compiler message did you get?

Message is as follow:

bug.adb:12:23: value not in range of type "Modular_Type" defined at
line 4
bug.adb:12:23: static expression fails Constraint_Check

Compiled with GNAT.

Line 12 is the one containing “B := E < Natural'Pos (10 ** I);”.

By the way, formally speaking, the expression is not static, and it should
compile, although expected to raise a range‑check‑error at runtime.

Adam Beneschan

unread,
Feb 7, 2012, 1:15:27 PM2/7/12
to
On Feb 7, 9:24 am, Yannick Duchêne (Hibou57)
<yannick_duch...@yahoo.fr> wrote:
> second, with either a failure to compile or range error at run-time.
>
> Someone remember a pointer to the most relevant part in the RM? I may be a
> bit tired, could not find it.
>
> Seems in the first case, the left-side of "E < 10 ** I" has a modulo
> applied, or else, I see no way to explain the result, "FALSE". But why
> would this modulo be applied with a subtype of Natural and not with an
> Universal_Integer?
>
> I don't like it (and must be idiot in some way, don't you think?).

I think my first attempt to respond may have failed... retrying...

In the first example, "**" is a function whose left operand is the
modular type Modular_Type, and whose right operand has type Integer
(actually Integer'Base). Unlike most other binary operators, whose
two operands are of the same type, "**" always has a right operand of
type Integer [and sometimes subtype Natural], regardless of the type
of the left operand. Perhaps that's what's confusing you? Anyway,
this means that in 10**I, the type of 10 is the modular type
Modular_Type, which means that "**" is a modular operation, which
wraps around.

In the second example, the left operand of "**" has type Integer,
because of the Natural'Pos which means that the expression inside
parentheses has to be of type Integer (subtype Natural). Thus, the
value of Natural'Pos (10**I) is 1024--this operation doesn't wrap
around. And to use this value as an operand to "<", it has to be
converted to type Modular_Type, which will get a Constraint_Error
because 1024 is out of range of the modular type. (Type conversions
don't automatically wrap.) So this program, unlike the first, should
get a Constraint_Error. It should compile, though; it appears to be a
compiler bug that it didn't compile.

-- Adam


Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 1:21:05 PM2/7/12
to
Le Tue, 07 Feb 2012 19:06:55 +0100, Adam Beneschan <ad...@irvine.com> a
écrit:
>> Seems to me in both cases the expression on the right of "<" is
>> Universal_Integer. What compiler message did you get?
>
> If the argument on the right of "<" is a *static* Universal_Integer
> whose value is larger than 255, then an error message should be
> generated (4.9(35)). Here, the expression is not static, so there
> shouldn't be an error; as I mentioned earlier, GNAT does give an error
> which appears to me to be a compiler bug.

I believe too this is a compiler bug for the failure to compile, as you
confirm, I will submit a report (as an non‑supported user).

I still can't explain the first and the second interpretation. In the
first case “10 ** I” seems to be interpreted as “(10 ** I) mod 256” and
“Natural'Pos (10 ** I)” seems not.

That's why I expecting an answer from the RM. But could not remmember
where such a thing is specified. So much different interpretation when
switching from a Natural to an Universal_Integer.

Adam Beneschan

unread,
Feb 7, 2012, 12:53:25 PM2/7/12
to
On Feb 7, 9:24 am, Yannick Duchêne (Hibou57)
<yannick_duch...@yahoo.fr> wrote:
> second, with either a failure to compile or range error at run-time.
>
> Someone remember a pointer to the most relevant part in the RM? I may be a
> bit tired, could not find it.
>
> Seems in the first case, the left-side of "E < 10 ** I" has a modulo
> applied, or else, I see no way to explain the result, "FALSE". But why
> would this modulo be applied with a subtype of Natural and not with an
> Universal_Integer?
>
> I don't like it (and must be idiot in some way, don't you think?).

In the first example, 10 ** I is a modular operation; the left
argument of ** is a modular type (whose value is 10), and the right
argument is of type Natural. (The right argument of the predefined
"**" is always of type Integer [sometimes subtype Natural], unlike
most other predefined binary operations which have the same type for
the left and right arguments. Maybe that's what's confusing you.)
Anyway, since 10 ** I is an operation on a modular type, it wraps
around. In the second example, 10 ** I is an operation on Natural,
because it's the expected type when you have Natural'Pos; here, the
left argument is an Integer value of type 10. So Natural'Pos (10 **
I) has value 1024, and it's an error to convert it to a modular type
when it's out of range.

-- Adam

Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 1:23:05 PM2/7/12
to
Le Tue, 07 Feb 2012 18:54:36 +0100, Gautier write-only
<gautier...@hotmail.com> a écrit:

> On 7 fév, 18:24, Yannick Duchêne (Hibou57)
>
>> B := E < 10 ** I;
>
> E is of type Modular_Type.
> 10 ** I is untyped (Universal_Integer ?). It can be an expression of
> type Modular_Type, among other possibilities.
> So, the compiler chooses the "<" which has Modular_Type on both sides,
> right ?
> Then 10 ** 3 = 1000 = 232 (in the Modular_Type world) < 255 = E.
> E is larger, thus the FALSE.

Nice attempt to guess, but there are still question‑marks in this :-P

I will check the RM deeper later or tomorrow if no‑ones recall something.

Georg Bauhaus

unread,
Feb 7, 2012, 1:32:28 PM2/7/12
to
This spit for the assignment to B seems to confirm:

| Node #44 N_Identifier "false" (Node_Id=1727) (analyzed)
| Rewritten: original node = N_Op_Lt "Olt" (Node_Id=42471)
| ...
| Chars = "false" (Name_Id=300001085)
| Is_Static_Expression = True
| Etype = N_Defining_Identifier "boolean" (Entity_Id=12s)
| Entity = N_Defining_Identifier "false" (Entity_Id=107s)

-gnatdg gives

b := false;

Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 1:35:01 PM2/7/12
to
Le Tue, 07 Feb 2012 19:15:27 +0100, Adam Beneschan <ad...@irvine.com> a
écrit:
> In the first example, […] Anyway,
> this means that in 10**I, the type of 10 is the modular type
> Modular_Type

Why? “I” is a subtype of Natural, so 10**I should be too. Things look like
if the left‑hand side of “<” has a consequence on the interpretation of
its right‑hand side.

Adam Beneschan

unread,
Feb 7, 2012, 1:40:17 PM2/7/12
to
On Feb 7, 10:35 am, Yannick Duchêne (Hibou57)
<yannick_duch...@yahoo.fr> wrote:
> Le Tue, 07 Feb 2012 19:15:27 +0100, Adam Beneschan <a...@irvine.com> a
> écrit:
>
> > In the first example, [...] Anyway,
> > this means that in 10**I, the type of 10 is the modular type
> > Modular_Type
>
> Why? "I" is a subtype of Natural, so 10**I should be too.

Please reread what I wrote about "**". It is not like other
operators. Its right operand is always Integer (of which Natural is a
subtype). Therefore, knowing that I is an integer is *not* enough to
determine the type of the left operand. The type of 10, and the type
of 10**I, cannot be determined until you look at the larger context,
which means that this:

> Things look like
> if the left-hand side of "<" has a consequence on the interpretation of
> its right-hand side.

is exactly correct. The compiler can't determine the type of 10 or
10**I until it sees the left-hand side of "<".

-- Adam


Yannick Duchêne (Hibou57)

unread,
Feb 7, 2012, 2:22:03 PM2/7/12
to
Le Tue, 07 Feb 2012 19:40:17 +0100, Adam Beneschan <ad...@irvine.com> a
écrit:
> is exactly correct. The compiler can't determine the type of 10 or
> 10**I until it sees the left-hand side of "<".
Rigth, understood.

That's a tiny trap to care about.

J-P. Rosen

unread,
Feb 8, 2012, 1:53:42 AM2/8/12
to
Le 07/02/2012 19:21, Yannick Duchêne (Hibou57) a écrit :
> I still can't explain the first and the second interpretation. In the
> first case “10 ** I” seems to be interpreted as “(10 ** I) mod 256” and
> “Natural'Pos (10 ** I)” seems not.
>

/operations/ of modular type wrap, and only operations. In the first
case, there is an operation (**). In the second case, there is none (the
** is on Universal_Integer, which is not a modular type).

Static expressions have to belong statically to their type, so it seems
correct to me.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

Adam Beneschan

unread,
Feb 8, 2012, 10:29:29 AM2/8/12
to
On Feb 7, 10:53 pm, "J-P. Rosen" <ro...@adalog.fr> wrote:
> Le 07/02/2012 19:21, Yannick Duchêne (Hibou57) a écrit :
>
> > I still can't explain the first and the second interpretation. In the
> > first case “10 ** I” seems to be interpreted as “(10 ** I) mod 256” and
> > “Natural'Pos (10 ** I)” seems not.
>
> /operations/ of modular type wrap, and only operations. In the first
> case, there is an operation (**). In the second case, there is none (the
> ** is on Universal_Integer, which is not a modular type).
>
> Static expressions have to belong statically to their type, so it seems
> correct to me.

Except that there's no static expression here.

-- Adam

Randy Brukardt

unread,
Feb 8, 2012, 10:37:31 PM2/8/12
to
"Yannick Duchêne (Hibou57)" <yannick...@yahoo.fr> wrote in message
news:op.v9bmlfrvule2fv@douda-yannick...
...
>I still can't explain the first and the second interpretation. In the
>first case "10 ** I" seems to be interpreted as "(10 ** I) mod 256" and
>"Natural'Pos (10 ** I)" seems not.

Yes, that's right of course. In the first case, everything has your modular
type, in the latter case the expression has type Universal_Integer (which is
obviously different).

Ada always prefers non-universal types, so those are only used in rare
circumstances.

Randy.


Randy Brukardt

unread,
Feb 8, 2012, 10:40:20 PM2/8/12
to
"Yannick Duchêne (Hibou57)" <yannick...@yahoo.fr> wrote in message
news:op.v9bmorujule2fv@douda-yannick...
...
>Nice attempt to guess, but there are still question-marks in this :-P

No guess here, that's the correct analysis. (I didn't quote it because for
some reason your message don't quote automatically.)

Randy.


0 new messages