8

In brief, why doesnt this work:

generic
   Max : in Positive;
package Modular_Gen_Issue is
   procedure Foo;
private
   type Mod_Thing is mod Max; -- NOK
   type Int_Thing is new Integer range 0 .. Max; -- OK

end Modular_Gen_Issue;

With compilation:

$ gnatmake modular_gen_issue.ads
gcc-4.4 -c modular_gen_issue.ads
modular_gen_issue.ads:6:26: non-static expression used for modular type bound
modular_gen_issue.ads:6:26: "Max" is not static constant or named number (RM 4.9(5))
gnatmake: "modular_gen_issue.ads" compilation error
$

How can I pass in a single number and use it to define a modular type ?

And yes it has to be a modular type!

NWS
  • 3,080
  • 1
  • 19
  • 34
  • 2
    After futzing around with this for a bit, yes, I'd like to know how to do it too! :-) If there's no joy here, perhaps try comp.lang.ada, at least to get a reason from some of the language lawyers that hang out there. – Marc C Jun 12 '13 at 13:01

2 Answers2

10

Sorry, you can't. Whenever you declare a modular type, the modulus has to be a static value, i.e. a value the compiler can figure out right then and there. And this doesn't work. This is true of many parts of type declarations, especially parts that the compiler needs in order to figure out how many bits an object needs to be, or other features about an object's representation. On the other hand, in Int_Thing, the upper bound of the range doesn't need to be static (the compiler already knows an Int_Thing will be represented the same as an Integer, and the range is used for bounds checking but isn't used to determine how big an Int_Thing will be).

If this is a real-life situation and you need a generic that can handle varying modular types, you might be able make the modular type itself a generic parameter:

generic
    type Mod_Thing is mod <>;
package Modular_Gen_Issue is ...

(P.S. The range of Mod_Thing in your example would be 0..Max-1, not 0..Max.)

ajb
  • 31,309
  • 3
  • 58
  • 84
  • As the compiler knows how many bits a positive is, and its upper bound (max), and knows a modular types lower bound is 0, im still not seeing how this is any different to the int_thing example. – NWS Jun 12 '13 at 15:05
  • 3
    The compiler doesn't know the upper bound (max) at the point it sees the type declaration, because you haven't instantiated the generic and given max a value. And yes, it _does_ need to know this when it's first processing the generic, before you instantiate it. Generics are not like C macros, where it just stores the text and doesn't look at it until you expand the macro. Generics have to obey the rules even before you instantiate them. – ajb Jun 12 '13 at 21:05
  • 2
    One other comment: the big difference with Int_Thing is that Int_Thing is derived from an existing type (Integer), and the compiler will make the size of the type the same as the one it's derived from. `0 .. Max` adds bounds checking but doesn't change the size. But when creating an all-new non-derived type, the compiler does need information that affects the size to be static. If you said `type Int_Thing is range 0 .. Max`, that would be illegal also. – ajb Jun 12 '13 at 22:12
  • The answer + Comments explain what is going on here imho. Thanks. – NWS Jun 13 '13 at 08:08
3

In addition to what ajb wrote, consider the following usage of your generic package:

procedure Foo (Bar : in Positive) is
   package Instance is new Modular_Gen_Issue (Max => Bar);
begin
   null;
end Foo;

Here, the package Instance is created with a non-static value that may change with every call to Foo. Because Ada allows this, the compiler must expect any parameter of a generic unit to be non-static. That's why you cannot declare your modular type in there, even though you could instantiate your package with a static value.

Extending ajb's suggestion, you can do:

generic
   type Mod_Thing_Base is mod <>;
package Modular_Gen_Issue is
   type Mod_Thing is new Mod_Thing_Base;
end Modular_Gen_Issue;

This way, you can define primitive operations of Mod_Thing (which you couldn't do by taking it as parameter directly).

flyx
  • 35,506
  • 7
  • 89
  • 126