To: J3 J3/21-110r1 From: Malcolm Cohen Subject: Enumeration types discussion specs and syntax Date: 2021-February-27 1. Introduction Two things have become clear over the last year: - our approach to "true enumeration types" has become too complicated, unnecessarily so, and needs to be cut back to basics (at least this time around); - even the basic approach to "true enumeration types" does not satisfy a significant part of the community, which needs better support for interoperable "enum types" than we currently provide with ENUM,BIND(C). The requirements for "better interoperable enums" are partially in conflict with the requirements for "true enums", so this paper proposes doing both of these separately, and not trying to shoehorn one into the other. It is possible to do either feature without the other. - "Simpler true enumerations" fulfills more of the WG5 requirements. - "Better interoperable enums" fulfills a large part of the type-safety WG5 requirement, and fixes a long-standing and well-known deficiency in the ENUM,BIND(C) feature. There is a good case for doing both of these, and a very strong case for doing at least one of them. This paper addresses "Better interoperable enums" only. The alternative syntax and potential future extension that were in the r0 of this paper have been removed. A revised version of section 3 from the r0 of this paper ("Simpler true enumerations") is the separate paper 21-120. 2. Better interoperable enums 2.1 Requirements Basically, have all the features of ENUM,BIND(C) plus a type name. The type name needs to provide type safety for procedure calls and assignment. 2.2 Specifications (A) Retains the ability to specify the internal representation, and thus to have gaps and duplicate values, that ENUM,BIND(C) currently has. (B) Provides a type name that can be used to declare variables of an interoperable enum type. (C) Variables of that type can take on any representable value, just as they can in C. (D) Dummy arguments of that type are only type-compatible with actual args with the same type and with integer expressions involving values or the enumerators of the type. (E) Upwards compatible with ENUM,BIND(C); the enumerators will still be of type integer, and can be used freely in integer expressions. (F) Assignment is type-safe in the same way as argument association. (G) No polymorphic entities with a declared type that is an enum type. (H) No intrinsic constructor of this type. (I) An enum entity in an i/o list acts like integer. For output that's the same as wrapping it in INT(...), for input it's the same as having an integer temporary assigned with "var = typename(tempo)". (J) Enum types can be used in generic resolution vs. other enum types and derived types, but not vs. integer (ambiguity). Comments: (1) It might be thought that it would be harmless to allow assignment to/from integers, but requiring an INT(...) or typename(...) in such cases is not an onerous requirement. The special weaseling for expressions involving the enumerators will handle most common cases anyway. (2) We could be stricter and allow only the enumerators themselves to be type-compatible, but that would disallow IOR(enum1,enum2), and enums are sometimes used to define bit-patterns for that purpose. (3) We could be less strict and merely require a warning diagnostic from compilers. I believe that strict typing is better than warnings. (4) We could instead have the enumerators be literal constants of the new type. That would be easier in the standard, but more strict on the user, and make it harder to gradually upgrade a program with the existing ENUM,BIND(C) to use enum type names. 2.3 Syntax and semantics The syntax is to extend the ENUM,BIND(C) statement with a type-name: <> ENUM, BIND(C) [ :: ] The is for a new kind of type, which is like a derived type with an anonymous integer(KIND=kind of the enumerators) component, but that is not a BIND(C) type, not extensible, and not a sequence type. We will call this an "enum type", as it acts more or less like C enums. Comment: The concept that all derived types are structure types is pretty well embedded into the standard at this time. Either we split derived types into structure types and enum types, or we add enum types as a separate concept and mention it everywhere necessary. The latter is probably easiest to do without making mistakes. But how we describe this in the standard can be left to the edits paper; here we are just describing the effect we want. Thus it cannot be extended, and CLASS() is not allowed, but it uses "normal" type compatibility (not the complicated sequence rules), and can be used in TYPE IS () when the SELECT TYPE selector is CLASS(*). Scalar values of the type can be created using the constructor enum_type_name ( integer expression ) There being no actual components or component name, there is no keyword form of this constructor. Instead of an integer expression, a boz literal constant may be used. Array values of the type can be created with an array constructor, either by having all s being of the type, or using an in the array constructor (in which case a mix of enum-type values and integer expressions using the enumerators is allowed). The internal representation of an enum type is the same as the integer kind of its enumerators, and its set of values is the set containing every enum_type_name ( integer value ) for all the integer values of that kind. Entities of an enum type are declared using the TYPE specifier, just as if it were a derived type. 2.4 Examples Module enum_mod Enum,Bind(C) :: myenum Enumerator :: one=1, two, three End Enum Enum,Bind(C) :: flags Enumerator :: f1 = 1, f2 = 2, f3 = 4 End Enum Contains Subroutine sub(a) Bind(C) Type(myenum),Value :: a Print *,a ! Acts as if it is Print *,Int(a). End Subroutine End Module Program example Use enum_mod Type(myenum) :: x = one ! Valid by (F) Type(myenum) :: y = myenum(12345) ! Explicit constructor Type(myenum) :: x2 = myenum(two) ! Constructor not needed but valid Call sub(x) Call sub(three) Call sub(myenum(-Huge(one))) End Program Program invalid Use enum_mod Type(myenum) :: z = 12345 ! INVALID - no enumerator in the expr Call sub(999) ! Need a cast. Call sub(f1) ! Wrong enum type. End Program ===END===