Structural Typing in C!!! Finally done hammering on this damn thing. Fuck.

https://thephd.dev/_vendor/future_cxx/papers/C%20-%20_Record%20types.html

Fuck!!

NXXX5: -fwrapv for Everyone - A Measured Approach to _Operators

@thephd Opt-in structural typing? That's really bloody cool!
@thephd after the compatibility changed in c23, me and gf started to try out `array(type)`/`vector(type)` macros and it works nicely except for when type has a space, like `struct foo` or `int *`

i'm excited for this so we can do those macros properly without random typedefs
@thephd ah _Record and _Record(types) sound really useful!

@thephd besides working with existing code, the one-sided compatibility can also be a tool for type safety, e.g.:

struct _Record vec3 { float x,y,z; };
struct vec3_direction { float x,y,z; };
struct vec3_position { float x,y,z; };

e.g. all these are vec3, but, vec3_direction and vec3_position are not interchangeable (without first converting to vec3).

I guess it's similar to how, for example, int* and float* are both considered void* if needed, but int* and float* are not interchangeable.

@thephd Ooh, this sounds very neat.

I think there may be a slight error with the canonical link for the page though. It seems to go to a different page about _Operators.

@thephd ha! Review link and the link point to different stuff. So... Meow!

@thephd Questioning the bit about _Record being entirely meaningless on forward declarations. If I have a function that takes a bla_vec3 *, I would expect to be able to pass a foo_vec3 * to it if they are compatible record types. But if I can't declare that fact on forward-declarations, I gotta go dig out the full type definitions just to get the _Record modifier.

That's okay, it's structural typing after all so I'm gonna need to provide the structure, but the error message I get from the compiler would be Less Than Awesome. It's just gonna tell me those types are incompatible and then I have to intuit that my include soup is missing a secret ingredient.

Allowing _Record on there would at least let the compiler give a clear hint in its diagnostic that hey this is a structural type but you didn't include the structure.

@MinkOfTheEnd I don't want people to think that adding _Record on a forward declaration is enough to make something a record, because it's fundamentally impossible for that to work. I think that's a greater danger than the missed include, which will be more obvious when doing any operation on a forward-declared type.

That being said, if implementations or vendors can coalesce on [[vendor::record(foo_vec, bar_vec, bla_vec)]] as a way to mark forward declarations for compatibility / record-ness, maybe that would be a more worthwhile endeavor so we don't have to leave it up to implementations to guess / provide a much stronger error.

@thephd Yeah, that makes sense. Having it be an attribute probably fits better with it being more of a hint than anything related to the type.

@thephd Some thoughts from the maintainer of a small C implementation:

1. I think structural typing in C would be valuable.

@thephd 2. I'm not sure _Record is a good name for it. To me, this calls to mind records in Pascal, which are essentially its version of structures and/or unions and do not have structural compatibility rules. The term "record" is also used in several other programming languages and in databases, often not with the meaning you're giving it. A possible alternative that comes to mind is "tuple", although that corresponds most naturally to what you call _Record(types).
@thephd 3. I'm not entirely convinced that having _Record, _Record(types), and potentially _Record(other::attributes) is valuable enough to justify the complexity of it. I'd be tempted to just specify one version and leave any implementation-specific variants up to the regular attribute syntax.
@thephd 4. Please make sure the standard wording reflects what you intend with regard to the interaction between _Record and anonymous structures and unions. For example, can an anonymous structure or union in a structure type declared with _Record(types) match with a named member of another for type compatibility purposes? I'd suggest including examples of these cases. (Also, your document seems to use "anonymous structure" differently from the definition in the standard, which is confusing.)
@thephd 5. Can named and unnamed bit-fields match each other when using _Record(types)? I think the answer is yes based on the proposed wording, but this gives rise to a slightly odd situation where two compatible structure types may have different numbers of initializable members. Whatever the answer winds up being, I'd suggest including an example.
@thephd 6. It would be nice to have better handling in the standard for situations where one structure type is an "extended" version of another, with extra members added. Maybe out of scope for this proposal, but it seems potentially related.

@sheumann I don't really have any connotation for "extending a base type with more members" because that's just inheritance to my brain. You could make a version of composition where you can add a member to a structure and then give it a way to say "actually, all of my members are part of the thing you put me inside". That might give you the layout of composition but the "feel" of extension/inheritance that you're looking for.

When I write "anonymous" in my prose, I'm just referring to structures and unions without tags. The official standardese is very clear that we are not modifying the base algorithm: however you were comparing bitfields before, and however you were comparing anonymous unions/structures before, you keep doing that just with the strcmp for the names removed for _Record(types). For just _Record, the tag name at the top level is ignored, but everything else proceeds as normal.

I don't think I want regular attribute syntax, due to attributes being ignorable. This cannot be ignorable: it changes the way code is written, and changes a fundamental property (compatibility rules). I wouldn't mind discarding _Record(types) and _Record(vendor::stuff) to just keep the base one, though it should be known that doing so will cook usecases.

I'm glad you think structural typing is valuable! Hopefully we can make progress with something along the lines of _Record.

@thephd That looks very interesting, thanks - as always - for your hard work!

One minor point of copy-editing: the final comment in the second code sample of par. 3.7 probably needs to be updated - presumably, the point of vendor::const is to _allow_ that code?

Again, thanks! Good to see C getting all sorts of neat goodies / 21st century features!

@thephd You're a few levels deeper into the C world than I am. Looks like a lot of work, good luck with your proposal.