comp.lang.ada
 help / color / mirror / Atom feed
From: bobduff@world.std.com (Robert A Duff)
Subject: Re: Question about base types
Date: 1997/01/27
Date: 1997-01-27T00:00:00+00:00	[thread overview]
Message-ID: <E4oE3q.1tq@world.std.com> (raw)
In-Reply-To: mheaney-ya023280002601971414080001@news.ni.net


In article <mheaney-ya023280002601971414080001@news.ni.net>,
Matthew Heaney <mheaney@ni.net> wrote:
>
>I have a question about the relationship between types, first named
>subtypes, and base types.

Good question.  This terminology is pretty messed up in Ada.  Ada 95
cleans it up a little bit, but it's still pretty awful.  Sigh.

>If I declare an integer type, say
>
>type T is range 1 .. 10;
>
>Then I think that according to the Ada model this means I'm declaring some
>unnamed type, but whose first named subtype is T:

That's right (except it's called the "first subtype" in Ada 95).  ALL
types are unnamed.  You can never refer directly to a type in an Ada
program.  You can refer to the first subtype, or the base subtype, or
some other subtype.  These are all subtypes of the same underlying type.
We call that the "type of" the subtypes.

>type <anonomous parent of T> is System.Min_Int .. System.Max_Int;
>subtype T is <anonomous parent of T> range 1 .. 10;
>
>Do I have this correct?

Not exactly.  The above declaration declares a type.  Like all types, it
has no name.  It has a "base range", which is chosen by the
implementation.  The base range is NOT necessarily System.Min_Int
.. System.Max_Int.  The RM requires that the base range include all the
values in 1..10, and that it be symmetric about zero (or be symmetric
plus one extra negative value).  So the compiler could choose -10..10 as
the base range, or -11..10, or -1000..1000, or -1001..1000, etc.  The
expectation is that the compiler will choose something efficient, so
it's usually -2**15..2**15-1, or -2**31..2**31-1, or something like
that.  The base range determines when overflow happens -- that is, the
range used for intermediate results.  In particular, if the correct
answer is in the base range, then the result of the expression is that
correct answer.  Otherwise, the result is either the correct answer, or
you get an overflow (and Constraint_Error is raised).

(Note the difference between constraint checking and overflow checking
-- constraint checking is done on assignment, parameter passing, etc.
Overflow checking has to do with arithmetic operations.  Constraint
checking is often/usually done in software (using additional compare
instructions or whatever), whereas overflow checking is normally done by
the hardware (i.e. the add instruction automatically traps on overflow,
or at least automatically sets an overflow flag that can be checked in
one "trap on overflow" instruction).)

The "base subtype" of this type, called T'Base, is an unconstrained
subtype whose bounds are the base range.  The "first subtype" of this
type is called T, and it is constrained to 1..10.  Suppose the base
range happens to be -2**31..2**31-1 (which is allowed, since it includes
1..10, and is symmetric about zero, except for the extra -2**31 value).
Then:

    X: T := 10;
    Y: T'Base := 1_000_000_000;

If you assign the value 11 to X (as in X := X + 1;), there is a
constraint check, so Constraint_Error will be raised.  If you assign Y
:= Y*Y, there is no Constraint_Check.  However, they may be an overflow
check on the expression "Y*Y", so Y will either contain the value
1_000_000_000_000_000_000, or you will get Constraint_Error.  Most
likely the latter.

>Now what is the relationship of T'Base to this model?  Is T'Base the name
>of the anonomous parent type

No, T'Base is the name of an unconstrained subtype of the type.
Unconstrained means constraint checks are not done, but overflow checks
might be done.  In most compilers overflow checks *are* done, most of
the time, because otherwise the compiler would have to implement
arbitrary-sized integers in order to store the result.  The base subtype
T'Base still has a range associated with it -- namely, the base range
chosen by the compiler.  (And there are cases where it is more efficient
to get the right answer than to do the overflow check -- e.g. in
floating point, where the hardware might do a calculation in a
double-precision register.)

>type T'Base is System.Min_Int .. System.Max_Int;
>subtype T is T'Base range 1 ..  10;
>
>Did the "anonmous parent" go away in Ada 95?  

Yes.

>...Or is it still
>
>type <anon> is range System.Min_Int .. System.Max_Int;
>subtype T is <anon> range 1 .. 10;

No.  (And this isn't quite right for Ada 83, either.)

>and T'Base simply "refers" to this anonomous type?
>
>I can declare objects of type T'Base, right?
>
>O : T'Base;

Yes.

>Is this declaration the same as
>
>O : <anonomous parent of T>;

Well, not exactly, but you won't go too far wrong if you think of it
that way.  Just remember that the *compiler* chooses the base range, and
it is not usually Min_Int..Max_Int.

The anonymous type declared by "type T is range 1..10;" is considered to
be derived from root_integer, in the sense that this type belongs to the
class of all integer types.  However, this isn't the same sort of
derivation that happens when you write an explicit derived type decl --
in particular, the base range is not inherited from root_integer, but is
chosen by the compiler.  (This model is different from the Ada 83 model,
where the type of T is considered to be derived from some integer type
in Standard.  This doesn't make much difference in the behavior of
programs, but it does mean that compilers can support large ranges
without having any large-ranged types in Standard.)

To write strictly portable code, you have to make sure that every
expression result (of type T) is in the range -10..10.  If you want to
make sure all variables are in the range 1..10, but you want to allow
expression results in the range -1000..1000, then you should say:

    type Dummy is range -1000..1000;
    subtype T is Dummy range 1..10;

which guarantees that T'Base includes -1000..1000, and possibly more.
Then declare your variables to be of subtype T.

Note that the RM uses phrases like "the type Standard.Integer".
Strictly speaking, this is nonsense, since the name Standard.Integer
denotes a subtype, not a type.  The above wording is really a shorthand
for "the (unnamed) type that underlies the subtype Standard.Integer", or
"the (unnamed) type of the subtype Standard.Integer".

One final confusion: The term "anonymous type" does not mean "a type
that has no name", since *all* types have no name.  Instead, the term
"anonymous type" means "a type whose first subtype has no name".  For
example, "task T is ..." declares an object of an anonymous task type --
the first subtype of that type has no name.  (This explains why Ada 95
changed the term "first named subtype" to "first subtype" -- the first
subtype is not necessarily "named".)

For record types, and type extensions, 'Base is illegal.  This helps
ensure that there are no values of the type that don't belong to the
first subtype of the type.  For scalars, however, there can be values
outside the first subtype, and even values outside the base subtype.
(E.g., integer types represent the infinite range of mathematical
integers, most of which are outside the base range.  This infinite range
is generally used for compile-time calculations of static expressions,
but at run time, overflow checks normally prevent the actual use of the
infinite range.  Too bad -- see the recent language-war thread in which
several people have pointed out the advantages of having arbitrary
ranges at run time in Smalltalk.)

- Bob




  reply	other threads:[~1997-01-27  0:00 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1997-01-26  0:00 Question about base types Matthew Heaney
1997-01-27  0:00 ` Robert A Duff [this message]
1997-01-30  0:00   ` Matthew Heaney
1997-01-30  0:00     ` Matthew Heaney
1997-01-30  0:00     ` Robert Dewar
1997-01-30  0:00       ` Matthew Heaney
     [not found]     ` <EACHUS.97Feb3221558@spectre.mitre.org>
     [not found]       ` <dewar.855063927@merv>
     [not found]         ` <EACHUS.97Feb6145918@spectre.mitre.org>
     [not found]           ` <dewar.855276722@merv>
1997-02-07  0:00             ` Mats Weber
1997-02-08  0:00               ` Robert Dewar
1997-02-10  0:00                 ` Mats Weber
1997-02-11  0:00                   ` Robert Dewar
     [not found]         ` <32FB45D4.2160@watson.ibm.com>
1997-02-10  0:00           ` Robert Dewar
1997-02-08  0:00   ` Robert Dewar
1997-02-09  0:00     ` Matthew Heaney
1997-02-09  0:00       ` Robert Dewar
1997-02-09  0:00         ` Matthew Heaney
1997-02-10  0:00           ` Robert Dewar
1997-02-10  0:00       ` Larry Kilgallen
1997-02-11  0:00   ` Robert I. Eachus
1997-02-12  0:00     ` Robert Dewar
1997-01-27  0:00 ` Mats Weber
1997-01-28  0:00   ` Robert A Duff
1997-01-29  0:00   ` Robert Dewar
1997-01-28  0:00 ` Robert I. Eachus
1997-01-28  0:00   ` Mats Weber
1997-01-29  0:00 ` Robert I. Eachus
1997-01-30  0:00   ` Robert A Duff
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox