Every time I look at Ada I find some cool little features I forgot about:

- Representation clauses that let you separately specify the layout of record types
- Requiring `aliased` on record fields for them to be individually addressable
- Variant records whose tag is immutable
- Variant records whose allocation size is variable and dependent on a parameter, sort of like C flexible array members but supporting multiple arrays (and of course differing between variants).
- Ragged arrays with non-uniform dimensions

It really is an alternate PL history branching off from Algol-68.

@zwarich representation clauses also let you specify where and how big the discriminant tag is, which is pretty neat
@zwarich you can almost do automatic untrusted parsing of variable length packed binary data in the type system itself with a combination of Unchecked_Conversion, 'Valid_Scalars, representation clauses, and dynamic predicates

literally the only thing missing is that discriminants can't be used to specify bit offsets (which sucks because the compiler has to support this for field offsets anyway!):
https://stackoverflow.com/questions/22768834/ada-packing-record-with-variable-sized-array
Ada: packing record with variable sized array

I am looking to create a packed record that can hold an array the varies in length from 5 - 50 elements. Is it possible to do this in such a way that the record can be packed with no wasted space?...

Stack Overflow
@duk I was having a very related discussion today on the Rust Discord about "parse, don't validate". This ceases to be such a hard-and-fast rule once your type system has the ability to validate predicates and then rely on the predicates down the line to eliminate error conditions (which obviously works out better with static enforcement). I wouldn't have imagined you could (almost) do something like this with Ada dynamic predicates, though.

@duk I do like that discriminants are explicitly named so they can be referred to elsewhere. I think the notation for specifying discriminants and distinguishing between constrained and unconstrained discriminants is a bit confusing, especially by modern notation. The discriminant syntax looks like a type parameter, which it arguably is in the constrained case, but in the unconstrained case it's not really a parameter. Also, the way that the constrained case is specified by the absence of a default value for the discriminant is a bit surprising, as is the interaction with heap allocation.

I get why all of these problems exist and don't have a comprehensively better solution, so I shouldn't rag on them too much.

@zwarich oh yeah the syntax is confusing for sure and Ada's heap allocation stuff was very, very obviously tacked on retroactively

there's a lot of stuff in Ada but language-wise it doesn't really compose as well as one would hope unfortunately, and there are weird gnarly edge cases around subtyping arrays and such that can bite you