Gem #26: The Mod Attribute
by Bob Duff —AdaCore
Let's get started…
Ada has two kinds of integer type: signed and modular:
type Signed_Integer is range 1..1_000_000; type Modular is mod 2**32;
Operations on signed integers can overflow: if the result is outside the base range,
Constraint_Error will be raised. The base range of
Signed_Integer is the range of
Signed_Integer'Base, which is chosen by the compiler, but is likely to be something like
Operations on modular integers use modular (wraparound) arithmetic.
X : Modular := 1; X := - X;
Negating X gives -1, which wraps around to
2**32-1, i.e. all-one-bits.
But what about a type conversion from signed to modular? Is that a signed operation (so it should overflow) or is it a modular operation (so it should wrap around)? The answer in Ada is the former -- that is, if you try to convert, say,
Integer'(-1) to Modular, you will get
I : Integer := -1; X := Modular (I); -- raises Constraint_Error
In Ada 95, the only way to do that conversion is to use
Unchecked_Conversion, which is somewhat uncomfortable. Furthermore, if you're trying to convert to a generic formal modular type, how do you know what size of signed integer type to use? Note that
Unchecked_Conversion might malfunction if the source and target types are of different sizes.
A small feature added to Ada 2005 solves the problem: the
generic type Formal_Modular is mod <>; package Mod_Attribute is function F return Formal_Modular; end Mod_Attribute; package body Mod_Attribute is A_Signed_Integer : Integer := -1; function F return Formal_Modular is begin return Formal_Modular'Mod (A_Signed_Integer); end F; end Mod_Attribute;
Mod attribute will correctly convert from any integer type to a given modular type, using wraparound semantics. Thus, F will return the all-ones bit pattern, for whatever modular type is passed to
Related Source Code
Ada Gems example files are distributed by AdaCore and may be used or modified for any purpose without restrictions.gem_26.ada