Type is a set of values and operations defined on it.
Ada uses this definition too:
type
defining characteristic of each object and expression of the language, with an associated set of values, and a set of primitive operations that implement the fundamental aspects of its semantics
It is only Ada subtype where Ada suddenly forgets that and invents not-a-type which is yet a type and a constraint. This is more or less Ada 83 heritage when the language had no related types, that is types the language routinely implicitly converts. So in Ada 83 a subtype is “same” type for the sake of purity, though semantically it is evidently not. Ada 95 changed that by adding tagged types which are implicitly converted (per introducing overloaded primitive operations.) But the wording regarding subtypes remained same.
In a discussion regarding software or language design this word play is irrelevant. Ada subtype is just a type.
Ada was designed that way so that you could have freedom within constraints (ie subsets) without having to have full-on separate types: just as mathematics has Integer, Natural, & Counting numbers to section into useful properties. (e.g. any Natural multiplied by a Natural is Natural; this sort of property doesn’t hold with certain sets like, say, Negative.) — Also, it would be a pain in the ass to require full-on type-conversions for these constrained subsets.
This is arguable.
Is “All values of type X that conform to a given constraint” a new type, or is it simply working with a subset of the set-of-values of a type. You are arguing that it must be a separate type, but this is not necessarily so.
Yes, a subtype is implicitly converted forth and back as necessary.
It is not because Ada subtype representation is same and most operations are defined in terms of the base type (S’Base) anyway. A conversion is at most a constraint check. Moreover it is exactly so when you clone a type rather than subtype it:
type X is new Integer [range ...]; – Does this incur “pain?”
It does not mean that extending this model would not be useful. One could allow representation change in order to have things Ada cannot now:
Enumeration type extension
String encoding support
Class-wide objects of small types and arrays
nD subarrays, columns, diagonals, planes …
Placing existing types up into the hierarchy of types (ad-hoc supertypes), e.g. you could create a common ancestor Field for Float and Complex and write subprograms working on both
Discriminant expressions:
type Buffer (L : Natural) is record
Data : Stream_Element_Array (0..L - 1);
end record;
etc. Yes, it would require full conversion, but one would have it manually anyway.
This changes the order for storage on the machine the program is running on. I would like to change the byte order of the serialization operation. Personally, I treat little endian as a machine detail and big endian as the natural representation. Big endian is how I prefer to serialize data for storage and transmission.
When I wrote my Modbus software I dealt with devices who’s developers think memcpy(buf, &float, sizeof (float)) is how to serialize. I use portable bit shifting operations.
Scalar_Storage_Order is applicable to arrays and records etc. where you use it?
“Existing code for a big-endian system can thus be ported to a little-endian system without any fuss, and without any change of data representation, just by adding appropriate attribute definitions on relevant record type declarations”
Needs testing but no code that could have mistakes in it.
For example I believe you could have two procedures that unchecked_convert to arrays with different scalar storage orders.