Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Anonymous labeled structs and enums are some of my top wished-for features in programming languages! For instance, in Rust you can define labelled and unlabelled (i.e. tuple) structs

    struct Foo(i32, i32);
    struct Bar{sum: i32, product: i32}
But you can only e.g. return from functions an anonymous tuple, not an anonymous labelled struct

    fn can() -> (i32, i32)
    fn cant() -> {sum: i32, product: i32}



In Dart, we merged tuples and records into a single construct. A record can have positional fields, named fields, or both. A record type can appear anywhere a type annotation is allowed. So in Dart these are both fine:

    (int, int) can() => (1, 2);
    ({int sum, int product}) alsoCan() => (sum: 1, product: 2);
    (int, {int remainder}) evenThis() => (1, remainder: 2);
The curly braces in the record type annotation distinguish the named fields from the positional ones. I don't love the syntax, but it's consistent with function parameter lists where the curly braces delimit the named parameters.

https://dart.dev/language/records


How do you distinguish a tuple with both positional and named fields from a tuple that has a record as a field

Like how do you write the type of (1, {sum:2}) ? Is it different from (1 , sum :2)?


The syntax is a little funny for mostly historical reasons. The curly braces are only part of the record type syntax. There's no ambiguity there because curly braces aren't used for anything else in type annotations (well, except for named parameters inside a function type's parameter list, but that's a different part of the grammar).


so my examples would be (1, (sum:2)) and (1, sum:2)?


Yes, exactly.


Hmm. Let me first check that I've understood what you care about

    struct First(this: i8, that: i64)
    struct Second(this: i8, that: i8)
    struct Third(that: i64, this: i8)
    struct Fourth(this: i8, that: i64)
    struct Fifth(some: i8, other: i64)
You want First and Fourth as the same type, but Second and Third are different - how about Fifth?

I see that this is different from Rust's existing product types, in which First and Fourth are always different types.

Second though, can you give me some examples where I'd want this? I can't say I have ever wished I had this, but that might be a different experience.


they're not asking for a structural typing overhaul, just a way to make ad-hoc anonymous types with named fields and pass them around. a lot of times with tuple return types you're left wondering what that random `usize` is supposed to represent, so having names for it would be very convenient. i don't see why, under the hood, it couldn't just be implemented the exact same way as current tuple return types


> they're not asking for a structural typing overhaul, just a way to make ad-hoc anonymous types with named fields and pass them around.

And their point is that the two boil down to the same thing, especially in a non-trivial program. If switching field positions around changes their semantics, tuples may well the most sensible choice. As for "what that random usize is supposed to represent" that's something that can be addressed with in-code documentation, which Rust has great support for.


Also, if it's not just a "random usize" then you should use the new type paradigm. In a language like Rust that's not quite as smooth as it could possibly be, but it's transparent to the machine code. Rust's Option<OwnedFd> is the same machine code as C's int file descriptor, but the same ergonomics as a fancy Haskell type. We can't accidentally confuse "None, there isn't a file descriptor" for an actual file descriptor as we so easily could in C, nor can we mistakenly do arithmetic with file descriptors - which is nonsense but would work (hilarity ensues) in C.

If these aren't "random" usizes but FileSizes or ColumnNumbers or SocketTimeouts then say so and the confusion is eliminated.


It's interesting that languages which start with purely nominal structs tend to acquire some form of structurally typed records in the long run. E.g. C# has always had (nominally typed) structs, then .NET added (structurally typed) tuples, and then eventually the language added (still structurally typed) tuples with named items on top of that.


PHP has it all!

I think the main dividing line here is whether you want to lean into strict typing or whether you prefer a more loose typing structure. The extremes of both (where, for instance, the length of an array is part of its type definition or there are not contractual guarantees about data) are both awful. I think the level of type strictness you desire as a product is probably best dictated by team and project size (which you'll note changes over the lifetime of the product) with a lack of typing making it much easier to prototype early code while extremely strict typing can serve as a strong code contract in a large codebase where no one person can still comprehend the entirety of it.

It's a constant push and pull of conflicting motivations.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: