9

Totally as an Ada-type-system learning exercise, I was trying to make 3 types (or rather, a type and 2 subtypes):

  • Month_Type, an enumeration of all months
  • Short_Month_Type, a Month_Type subtype only having the months with 30 days
  • February_Month_Type, a subtype with just February

It seems that subtypes must use the range mechanism, correct? (Is there any other kind of subtype?) In order to get it to work with contiguous ranges, I had to put my Month_Type enumeration in this order:

   type Month_Type is (February, April, June, September, November, January, March, May, July, August, October, December);

Obviously this isn't the natural order of months, and I could see people/me trying to do Month_Type'First or something expecting to get January.

So, two general questions from this silly example:

  1. Can I have a subtype that specifies specific components of its base type instead of a range?
  2. Can I somehow hide the implementation detail of the order in which I put months (make 'First not visible, for example)?

Thanks!

J Cooper
  • 16,891
  • 12
  • 65
  • 110

4 Answers4

6

No, an enumeration subtype only admits a range_constraint in this context, but you could create any number of Sets using Ada.Containers.Ordered_Sets. There are examples here and here.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • That is available, but its unneeded except in complex cases. – T.E.D. Sep 01 '12 at 17:46
  • So, this is how I would have just approached things in other languages. What interested me was being able to use the type system itself to designate things like short months or odd numbers or whatever. But thank you for letting me know that this functionality is not always possible! – J Cooper Sep 02 '12 at 04:40
6

You can make an object that designates only certain values in an enumeration. We would generally call this a "set".

A lot of languages have sets as basic types (along with arrays and records). Of course some don't. Ada is kind of in the middle. It doesn't offically have type named "set" or anything, but boolean operations are defined to work like bitwise logical operations on arrays of boolean. If you pack the array, you get pretty much exactly what other languages' "set" type give you. So Ada does support sets, they are just called "arrays of boolean".

type Month_Set is array (Month) of Boolean;
Short_Month : constant Month_Set := 
    (September => true, April => true, June => true, November => true, 
     February => true, others => false);
Y_Month : constant Month_Set :=
    (January => true, February => true, May => True, July => true, 
     others => false);

-- Inclusion
if (Short_Month(X)) then ...

-- Intersection (Short_Y will include only February)
Short_Y := Short_Month and Month_Ending_in_Y;

-- Union (Short_Y will include All Short_Months and all Y_Months
Short_Y := Short_Month or Month_Ending_in_Y;

-- Negation (Short_Y will include all Short_Months not ending in Y
Shorty_Y := Short_Month and not Month_Ending_in_Y;
T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • +1 for an excellent alternative; see also [*4.5.1 Logical Operators and Short-circuit Control Forms*](http://www.adaic.org/resources/add_content/standards/05rm/html/RM-4-5-1.html). – trashgod Sep 01 '12 at 21:07
  • This is a great answer, and something I didn't know about Ada. As I explained in another comment, I was interested in the type system itself being able to recognize a Short_Month from a Y_Month, hopefully at compile time. But obviously not everything one desires is possible :) Thanks again. – J Cooper Sep 02 '12 at 04:43
5

You can use subtype predicates. In your case:

subtype Short_Month_Type is Month_Type with
  Static_Predicate => Short_Month_Type in April | June | September | November
castle-bravo
  • 1,389
  • 15
  • 34
  • It would probably be useful to mention that _subtype predicates_ were added in Ada 2012, and thus were not available at the time the origninal question was asked (by a few months) – egilhh May 23 '21 at 21:25
2

Trashgod answered the first question. To answer the second question, make the type itself private.

Shark8
  • 4,095
  • 1
  • 17
  • 31
  • Yes, that way one can expose as much, or as little, of the abstract data type as makes sense for the application. – trashgod Sep 01 '12 at 20:53
  • I suppose I worded it poorly, but if I make the whole enumeration private, then no consumer of the package can really use it at all, right? I suppose I'd have to provide public Make_Month functions if I wanted them to be able to sling Februarys around, but not be allowed to do Month_Type'First? – J Cooper Sep 02 '12 at 04:35
  • Yes; another virtue of hiding the implementation in the abstract data type is that you can change it as needed, with clients none the wiser. For example, Java's [`EnumSet`](http://docs.oracle.com/javase/6/docs/api/java/util/EnumSet.html) uses a packed boolean array internally for efficiency, as T.E.D. suggests. – trashgod Sep 02 '12 at 13:34