CVS difference for acs/ac-00052.txt
--- acs/ac-00052.txt 2003/01/24 04:14:26 1.1
+++ acs/ac-00052.txt 2003/09/30 02:01:10 1.2
@@ -68,3 +68,324 @@
be useful in other situations too, but I don't know for sure.
+!topic Proposal for "semi-private" types
+!reference RM95-3.2.1, RM95-12.5(2)
+!from Niklas Holsti 03-09-26
+!keywords private types, generic formals, client-server contracts
+ In addition to the current "fully private" private types, it should
+ be allowed to declare types that are "partially private" in the
+ same sense and same syntax as for generic formal type parameters.
+ For example, in the public part of a package declaration we could
+ write 'type T is (<>);' or 'type T is range <>;' to inform the
+ clients that the type T is a discrete type or a signed integer
+ type without revealing full details such as the actual enumeration
+ literals or numerical ranges. The full declaration would be in the
+ private part of the package declaration, as for fully private types.
+Existing similar constructs
+ 1. Generic formal type parameters.
+Similar or related other proposals
+ 1. Being able to declare 'type T is tagged;' so that T'Class can
+ be used before the full declaration of T.
+Expected impact on compilers
+ Changes to the type-visibility and freezing definitions. However,
+ similar rules already exist for generics. Code generation for a
+ package declaration may be affected, because the full definition of
+ some types is not visible until the private part is compiled. No
+ difference in code generation for the body of a package, because
+ the type is then fully defined.
+ When an application is composed from software components, possibly
+ implemented by different parties or with a variety of
+ implementations for different platforms or variants of the
+ application, there is a kind of contract relationship between
+ "server" packages (the ones that provide types and operations) and
+ their "client" packages (the ones that use these types and
+ operations). This proposal focuses on the role of types in this
+ The server packages promise to provide certain types with certain
+ properties, and the client packages are designed to rely on the
+ existence and properties of these types. It is desirable for the
+ contract to be flexible so that the clients rely only on a minimal
+ and well defined set of type properties. This makes it possible to
+ change server implementations without forcing changes in the
+ clients. Just recompiling and relinking the application will be
+ Server implementations may need to vary depending on the target
+ platform, the geographic location, the specific variant of the
+ application and other similar reasons.
+ Contract flexibility is currently achieved mainly by hiding data
+ and type structures. The servers provide abstract data types
+ instead of concrete ones. Currently in Ada, there are only three
+ choices for exposing or hiding a type:
+ (1) the type is fully public;
+ (2) the type is fully private; or
+ (3) the type has some private parts and some public parts.
+ The last choice only applies to record and tagged types, where
+ some components may be of a private type and others of a public
+ type, and to array types where the index type may (and must) be
+ public while the component type can be private or a record with
+ some private and some public parts.
+ We will here ignore the third choice because it only amounts to
+ an aggregation of lower-level types where at the bottom level
+ only the first two choices (fully public or fully private) are
+ The problem is that if the type is fully public, its declaration
+ may reveal properties that are not meant to be part of the contract.
+ For example, assume that the contract means to define a discrete
+ type that can be used as an array index. If this type is declared
+ as a public type, the declaration must reveal whether the type is
+ an enumerated type, a signed integer type or a modular integer type.
+ It must also reveal the enumeration literals, the parent type if
+ any, or the actual integer ranges, as the case may be.
+ The clients may inadvertently come to rely on properties of the type
+ that are not meant to be in the contract and actually vary across
+ different server implementations, making the clients incompatible
+ with some server implementations. This is bad, since it limits the
+ reusability, maintainability and portability of the components and
+ the entire application.
+ On the other hand, if the type is fully private then the clients
+ can only use the type through server operations. Basic attributes
+ such as 'First and 'Last must be provided through server functions,
+ and no private type can be used as an array index or as the discrete
+ subtype in a "for .. loop" statement. This makes it harder to design
+ and implement applications that use private types, which leads to
+ an undesirable trade-off between short-term concerns (use public
+ types to achieve quick and cheap design and coding, fast execution,
+ small code size) and long-term concerns (use private types to help
+ maintenance, reuse, porting).
+ The proposed solution is inspired by the contract between a generic
+ and its users (instantiators), which is very similar to the contract
+ between servers and clients:
+ - The generic formals part corresponds to the contract. It reveals
+ only some of the properties of the types in the contract.
+ - The rest of the generic corresponds to the client. It is
+ allowed to use only those type properties that were revealed
+ in the formals part.
+ - An instantiation of the generic corresponds to an implementation
+ of the server. It provides concrete types that have the properties
+ revealed and required in the contract. The types also have other
+ properties, but the generic mechanism guarantees that the precise
+ nature of these other properties is irrelevant to the proper
+ working of this instance of the generic.
+ The proposal is simply this: Ada should allow, in the public part
+ of a package declaration, some of the same kinds of incomplete or
+ partially revealing type declarations as in generic formal type
+ Any package that "withs" this package would then have the same
+ knowledge about the declared entities as a generic unit has about
+ its formals. However, as for the current fully private types, the
+ full declarations would have to be stated in the private part of
+ the package declaration, so the compiler would still, after
+ compiling the package declaration, have full knowledge of the
+ declared entities.
+ Only the analogues of formal type declarations are proposed.
+ The other forms of generic formal parameter declarations are not
+ needed in this context because ordinary declarations can be used
+ instead; it is only the "partially private" aspect of formal types
+ that is currently missing.
+Example 1: Bongo-drum scheduling
+ package Bongo_Drum_Scheduling is
+ -- Provides thread scheduling according to the bongo-drum
+ -- method. The properties of this method may depend on the
+ -- processing platform, viz. how many drums there are, how
+ -- far the drum-beaters can count priorities, and how many
+ -- dancing threads can fit in the circle.
+ type Drum_Index is (<>);
+ -- Identifies a drum. You can use the fact that it is
+ -- a discrete type, but you can and must use 'First and
+ -- 'Last to find out the range, because it is private.
+ type Priority is range <>;
+ -- The priority of a thread. You can rely on it being an
+ -- integral type, so you can use addition and subtraction,
+ -- but you can and must use 'First and 'Last to find out
+ -- how many priority levels there are.
+ type Circle_Position is mod <>;
+ -- The position of a dancing thread in the circle around the
+ -- bongo players. You know it is a circle, but you must
+ -- use 'Modulus or 'Last to find out the circumference
+ -- (number of dancer positions).
+ type Thread is new Controlled with private;
+ -- The thread type is controlled, just so you know,
+ -- but I am not showing you the extension, not even as
+ -- a private type.
+ type Beat is record
+ Numerator : Circle_Position;
+ Denominator : Circle_Position;
+ end record;
+ -- Defines one component of the dancing/scheduling rhythm.
+ type Rhythm is array (Drum_Index) of Beat;
+ -- Bom-bom bom-bom-bom, tap tap, scratch and skip.
+ -- You know a lot about this type:
+ -- o It is a one-dimensional constrained array.
+ -- o Its component type is a record with two
+ -- components named Numerator and Denominator,
+ -- both of the modular type Circle_Position.
+ -- You also _do not_ know many things:
+ -- o The array length (you can and must use 'Length)
+ -- o The index range (you can and must use 'Range or
+ -- 'First or 'Last)
+ -- o The modulus of Circle_Position.
+ ... operation declarations omitted
+ type Dum_Index is (Tiny, Big, Medium);
+ -- In this set, we have three drums.
+ type Priority is new Natural;
+ -- We have lots of priorities.
+ type Circle_Position is mod 9;
+ -- Nine threads fit in the circle.
+ type Thread is new Controlled with record
+ ... new components
+ end record;
+ ... and so on.
+ end Bongo_Drum_Scheduling;
+Example 2: Some Ada predefined packages.
+ The proposed extension could be used in the LRM itself, to
+ make the public parts of the predefined packages real Ada
+ and hide the "implementation defined" remarks in the private
+ parts. For example:
+ package Standard is
+ type Integer is range <>;
+ -- Shows that Integer is a signed integer type, but
+ -- the actual bounds are private.
+ type Float is digits <>;
+ -- Shows that Float is a floating-point type, but the
+ -- actual precision is private.
+ end Standard;
+ (Note: RM95-A.1(48) states that "Standard has no private part".
+ I do not know if this is a deep requirement or merely a note
+ about the current definition of Standard.)
+ Another example:
+ package Interfaces.C is
+ type int is range <>;
+ end Interfaces.C;
+ The server-client type-contract can be implemented in other ways,
+ of course. Some of these ways are:
+ 1. Use fully public types and separate the intentionally public
+ and accidentally public properties in documentation or comments.
+ This does not give a compile-time check that the clients use
+ only the intentionally public (contracted) type properties.
+ 2. Use fully private types and implement all the necessary
+ operations on these types. This is limited by the inability to
+ overload assignment, indexing and literals.
+ 3. Write all the client packages as generic packages with all
+ the server-provided items as generic formals. This is quite
+ cumbersome and prevents any bidirectional interaction between
+ clients and servers. where the servers use some items provided
+ by the clients, for example composite types that combine
+ items from servers and clients or call-back operations that
+ let servers activate clients. Such bidirectional interaction
+ is usually necessary, in my experience.
+ Perhaps a wider syntax than in generics could be used, with more
+ options for revealing and hiding properties. For example:
+ type Apples_Count is new Natural range <>;
+ -- Apples are counted with a type derived from Natural,
+ -- but we are not showing the range, so use 'First and 'Last.
+ type Positive_Count is range 1 .. <>;
+ -- A count, starting from 1, with a private upper bound.
+ subtype Index is Integer range <>;
+ -- A subtype of Integer, with private bounds.
+ The current freezing rules may imply that some types must be
+ fully defined before the private part is compiled. For example,
+ if a type declared as "type Num is range <>" is then used as the
+ index type in an array declaration, the compiler may not know
+ how to implement the array type because the 'Size of the index
+ type is not known yet, being defined in the private part.
+From: Adam Beneschan
+Sent: Friday, September 26, 2003 3:34 PM
+Deja vu all over again? I posted the following to Ada-Comment on
+October 11, 2002. I was later told that this was essentially the same
+as Ada9X revision request #229, submitted on July 21, 1989.
+[Editor's note: see above.]
Questions? Ask the ACAA Technical Agent