# Record types

**URL:** <https://internals.rust-lang.org/t/record-types/18258>\
**Category:** language design\
**Created:** [February 2, 2023, 6:57pm UTC](https://internals.rust-lang.org/t/record-types/18258 "2023-02-02T18:57:19Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 2, 2023, 6:57pm UTC](https://internals.rust-lang.org/t/record-types/18258/1 "2023-02-02T18:57:20Z")

</div>

Is there a reason why Rust doesn't support:

```rust
type R = {x: f64, y: f64};

```

I believe it's possible if these structural record types are differentiated by _field_ order. For example, in the following program, `R1` and `R2` are different types:

```rust
type R1 = {x: f64, y: f64};
type R2 = {y: f64, x: f64};

```

They contain the same fields, but in different order. Then... we could probably allow implicit conversions between them. I believe implicit conversions can be inefficient if there are dozens of fields ― but that's not the case. Any opinions on that?

An use-case for that is when you want anonymous record types. For example:

```rust
struct C {
    m_x: {x: f64, y: f64},
}

```

Currently, you can only have nominal record types in Rust. Either `struct R {}` or `enum` variant (using `enum E { R {...} }`).

### Anonymous Initialization

How would one initialize an object of an anonymous recorrd type? Something like [TC39 Record & Tuple proposal](https://tc39.es/proposal-record-tuple/) should do.

```rust
let r: {x: f64, y: f64} = #{x: 0.0, y: 0.0};

```

Or `_{x: 0.0, y: 0.0}`.

---

<div class="post-metadata">

**Author:** ![Trequetrum](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Trequetrum](https://internals.rust-lang.org/u/Trequetrum)\
**Post date:** [February 2, 2023, 7:08pm UTC](https://internals.rust-lang.org/t/record-types/18258/2 "2023-02-02T19:08:03Z")

</div>

I think you lose coherence in the type system. This property states that every different valid typing derivation of a program leads to a resulting program that has the same runtime semantics.

Anonymous record types seems to lead to situations where records are nominally generic, it's not always clear when you're constructing nominally equal types? Should an anonymous struct from another library have some sort of structural type assigned or should it be secretly nominally typed and then fail to unify elsewhere.

Either way gets confusing, I think.

Maybe it's worth exploring! I'm not sure myself as I'm no type system expert!

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 2, 2023, 7:11pm UTC](https://internals.rust-lang.org/t/record-types/18258/3 "2023-02-02T19:11:56Z")

</div>

Anonymous record types should have no connection to each other. However there would be a type inference involved when you initialize an anonymous record type... Just that. And implicit conversions when you assign between compatible anonymous record types ("compatible" is when types have same fields, but different order).

---

<div class="post-metadata">

**Author:** ![Trequetrum](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Trequetrum](https://internals.rust-lang.org/u/Trequetrum)\
**Post date:** [February 2, 2023, 7:34pm UTC](https://internals.rust-lang.org/t/record-types/18258/4 "2023-02-02T19:34:11Z")

</div>

Sounds like you could give this a go with macros. Just expand it into a nominal type with some mangled name. Add some reflection capabilities to convert between the hidden structs. I don't think you can make the conversion implicit, but you can get a feel for how useful it is anyway?

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 2, 2023, 7:39pm UTC](https://internals.rust-lang.org/t/record-types/18258/5 "2023-02-02T19:39:21Z")

</div>

Can macros be used as type expressions? I'm already having some trouble on the playground with:

```rust
macro_rules! T {
    () => f64;
}

```

Diagnostic:

```plaintext
   Compiling playground v0.0.1 (/playground)
error: macro rhs must be delimited
 --> src/main.rs:2:11
  |
2 | () => f64;
  | ^^^

```

And I'll also want to initialize the anonymous record anyway.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 2, 2023, 7:44pm UTC](https://internals.rust-lang.org/t/record-types/18258/6 "2023-02-02T19:44:31Z")

</div>

> [@hydroper1](#):
>
> structural record types

There was an RFC about them; here's the comment where lang decided not to have them for at least the "foreseeable future":

> <https://github.com/rust-lang/rfcs/pull/2584#issuecomment-810313148>
>
> The lang team discussed this as part of our "Backlog Bonanza".
> \* (I cannot fin…d the video on youtube for the bonanza meeting where the bulk of the discussion took place... I believe it was roughly five months ago, though it may have been longer.)
> 
> The general consensus was that this proposal does not fit our current priorities. Some lang team members did say it feels like a feature we should have in the long term (or at least aspects of it, such as the \[feature sketch\](https://github.com/rust-lang/rfcs/pull/2584#issuecomment-794508491) provided by @scottmcm), but it is not something we can justify investing project time on in the foreseeable future.
> 
> We have already accepted https://github.com/rust-lang/rfcs/pull/2102 (tracking issue https://github.com/rust-lang/rust/issues/49804), which is somewhat related (but also much more narrow in scope.)
> 
> In any case, our inclination is to close. We might be willing to revisit items in the design space in the future, but not now.
> 
> @rfcbot close

And here's my personal take on things:

> <https://github.com/rust-lang/rfcs/pull/2584#issuecomment-794508491>
>
> @ibraheemdev I think the closest to an "official" feeling here is the general ro…admap of looking for finish out work-in-progress things, rather than open large new efforts like this one would be: https://rust-lang.github.io/rfcs/2857-roadmap-2020.html#follow-through-with-in-progress-designs-and-efforts
> 
> Personally (not speaking for the team) I think this is a cool RFC, and I agree that many of the pain points it addresses are worthy things, but it's also scary in that it has tendrils in so many places. My inclination here is that the way forward is to attack some of the things that would be nice from this in ways that would help nominal \`struct\`s too, and consider this RFC only after that.
> 
> For example, it's awesome that this RFC would allow 
> \`\`\`rust
> let color = { red: 0xA8, green: 0x3C, blue: 0x09 };
> do\_stuff\_with(color);
> \`\`\`
> But it would \*also\* be awesome to be able to do that with nominal types. So \[suppose\](https://ziglang.org/documentation/master/#Anonymous-Struct-Literals) we let you do this:
> \`\`\`rust
> let color = .{ red: 0xA8, green: 0x3C, blue: 0x09 };
> do\_stuff\_with(color);
> \`\`\`
> where inference would figure out that the struct literal is for a nominal \`Color\` type because of how it's used.
> 
> That's a small change (no change at all to MIR, for example), useful for nominal types immediately, and doesn't in any way block structural records in the future either.
> 
> (I'm reasonably confident that it'd be small because \[inference can already handle the "default then update the fields" version\](https://internals.rust-lang.org/t/pre-pre-rfc-syntactic-sugar-for-default-default/13234/7?u=scottmcm).)
> 
> Or, in general, if defining simple structs is heavy, maybe there are ways to make that lighter before jumping all the way to something with type system implications. Not to say we shouldn't \*ever\* have them, but we should take little steps first, so long as they don't close doors for the future.
> 
> (Though really this is largely a comment about Rust in its current 5-years-after-1.0 state. This is one of those features that does make abstract sense to me, and if someone was starting a new language I'd be all for them including it.)

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [February 2, 2023, 9:10pm UTC](https://internals.rust-lang.org/t/record-types/18258/7 "2023-02-02T21:10:53Z")

</div>

The very early Rust [had structural objects in 2010](http://venge.net/graydon/talks/intro-talk-2.pdf).

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [February 3, 2023, 12:38am UTC](https://internals.rust-lang.org/t/record-types/18258/8 "2023-02-03T00:38:15Z")

</div>

Yes, macros can be used in type position.

```rust
macro_rules! T {
    () => { f64 };
}

let _: T![] = 0.0;

```

The delimiters around the macro's output (or input) TokenStream is just to delaminate the output, and isn't actually relevant to what the macro expands to. For macros which want to expand to an actual expression block, they need to include that expression block inside the delimiters; you'll often see `=> {{ /* output */ }}`.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [February 3, 2023, 1:45am UTC](https://internals.rust-lang.org/t/record-types/18258/9 "2023-02-03T01:45:34Z")

</div>

This could also let [RFC 1506](https://rust-lang.github.io/rfcs/1506-adt-kinds.html) extend to unnamed tuples, so you could match `(A, B, C, D, E)` with a pattern like `{ 2: c, .. }`.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [February 4, 2023, 12:28am UTC](https://internals.rust-lang.org/t/record-types/18258/10 "2023-02-04T00:28:31Z")

</div>

It's not incoherent. Think of it as tuples where the fields have names. Records with the same fields are considered the same type, just like tuples with the same fields are considered the same type.

This is actually a big strength of this proposal, because it allows different libraries to use the same types, without having to depend on a common crate that exports these types. For example, two independent crates that both use a record type `{ red: u8, green: u8, blue: u8 }` could interoperate seamlessly.

A drawback of records is that you can't add methods to them or implement traits from another crate because of the orphan rules. This makes them significantly less useful.

I guess a big motivation for records is to simulate named arguments:

```plaintext
foo({ bar: 5, baz: true })

```

I think this is an important use case, but I'd rather have named arguments supported directly by the language, i.e.

```plaintext
foo(bar: 5, baz: true)

```

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 4, 2023, 12:54am UTC](https://internals.rust-lang.org/t/record-types/18258/11 "2023-02-04T00:54:05Z")

</div>

> [@Aloso](#):
>
> I guess a big motivation for records is to simulate named arguments:
> 
> `foo({ bar: 5, baz: true })`

Note that there's no need for _structural_ records for that. It would work with existing nominal records with two things:

- A way to create a struct literal of inferred type, [perhaps](https://github.com/rust-lang/rfcs/pull/2584#issuecomment-794508491) `foo(.{ bar: 5, baz: true })`
- Sugar to create an anonymous type in a function definition, like `fn foo(.{ bar: i32, baz: bool})`

Then you don't have to change the type system _at all_, which makes the whole thing massively easier to deal with.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [February 4, 2023, 3:54am UTC](https://internals.rust-lang.org/t/record-types/18258/12 "2023-02-04T03:54:59Z")

</div>

> [@Aloso](#):
>
> For example, two independent crates that both use a record type `{ red: u8, green: u8, blue: u8 }` could interoperate seamlessly.

In my experience with graphics programming, in situations where you want that set of fields and have interoperability considerations, you _also_ often want `#[repr(C)]` `#[derive(bytemuck::Pod)]` or similar — guaranteeing the representation, so that you can interconvert between `&[Color]` and `&[u8]` (the pixels of an image), or between `Color` and `[u8; 3]` or another vector representation (for more generic mathematical or bytewise operations).

So, a default-repr struct with no non-`std` trait impls — which is presumably what a structurally-typed record would be — wouldn't serve these use cases. (Of course there are other cases where it is simply passed by value to/from functions, where it would do just fine.)

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [February 4, 2023, 4:11pm UTC](https://internals.rust-lang.org/t/record-types/18258/13 "2023-02-04T16:11:32Z")

</div>

**NOT A CONTRIBUTION**

> [@scottmcm](#):
>
> .{ bar: 5, baz: true }

Whatever happened to the `_ { bar: 5, baz: true }` syntax? Has consensus been reached on that being undesirable, or is this just your preferred syntax?

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [February 4, 2023, 4:37pm UTC](https://internals.rust-lang.org/t/record-types/18258/14 "2023-02-04T16:37:12Z")

</div>

It's just an arbitrary preference for the time being, as far as I'm aware. `_` for a type name to me "feels" appropriate in pattern position, but potentially a bit more questionable in expression position; there's also other (extremely experimental) potential feature proposals which use `_` in expression position (e.g. autoclosure).

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 4, 2023, 4:52pm UTC](https://internals.rust-lang.org/t/record-types/18258/15 "2023-02-04T16:52:28Z")

</div>

Where's the proposal for the `.{}` or `_{}` syntax?

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 4, 2023, 10:48pm UTC](https://internals.rust-lang.org/t/record-types/18258/16 "2023-02-04T22:48:10Z")

</div>

> [@jjpe](#):
>
> Has consensus been reached on that being undesirable, or is this just your preferred syntax?

That's just the one I'd used in that old comment to which I'd linked. I don't think there's any consensus on the desirability of the feature nor its syntax.

I've been trying out the dot syntax, inspired by Swift, since `_::` is pretty noisy. Worse, the way we actually spell "get a thing from an inferred type in an expression" [today is the even longer `<_>::`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=16e92b95c87d56ceabf820e557acfdd6), but I think "you can use `<_>::SeqCst`" would just turn into another "lol rust's terrible syntax" meme. And I don't think that `std::_::min(a, b)` should _ever_ work, so using something that looks less like a path might be good anyway.

What'll actually happen? No idea. But I like having a couple different variations in the discussion anyway.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [February 8, 2023, 12:19am UTC](https://internals.rust-lang.org/t/record-types/18258/17 "2023-02-08T00:19:18Z")

</div>

> [@hydroper1](#):
>
> Where's the proposal for the `.{}` or `_{}` syntax?

I don't think an RFC for this exists yet, it's just a simple idea: A struct literal, e.g. `Struct { field: value }` can be written as `_ { field: value }`, when the type can be inferred, e.g. in a function argument. This is more concise and reduces boilerplate by requiring fewer imports. The `_` as a placeholder feels like the obvious choice, since it's already used for omitting a type that can be inferred, e.g. `Vec<_>`.

The syntax `{ field: value }` without an underscore is also a possibility, and looks appealing because JavaScript and Python have a similar syntax. However, it has some problems (which also apply to record types as proposed in this thread btw):

First, it's ambiguous with blocks in several situations, e.g.

- when there are no fields: `{}`
- when there's a single field using the shorthand syntax: `{ field }` instead of `{ field: field }`
- when all fields are omitted: `{ ..default() }`

JavaScript's syntax has a deliberate limitation because of this: When returning an object from an arrow function, the object must be wrapped in parentheses, e.g. `(x, y) => ({ x, y })`. But note that adding parentheses would not work in Rust, since blocks are expressions in Rust, and can appear anywhere.

The other problem with the `{ field: value }` syntax is that it looks so similar to a block that it may negatively impact diagnostics. For example, when you write `Struct { field = 42 }`, Rust will tell you to replace the `=` with a `:`. This useful diagnostic likely wouldn't work for `{ field = 42 }`.

What's nice about `_{}` or `.{}` is that it can be trivially extended to other parts of Rust. For example, `_::Variant` could become a shorthand for `SomeEnum::Variant`. Tuple structs and unit structs could be inferred as well with `_()` and `_`, although `_()` would be more controversial, because constructing a tuple struct is just a function call, strictly speaking.

One common argument against any proposal to make syntax more concise is **explicitness** : People argue that being forced to specify types explicitly makes the code easier to understand. I'd say this ship has sailed, since Rust already has powerful type inference and doesn't require specifying types in many places. Also, Rust's design has always been about giving programmers as much freedom as possible, instead of forcing them to follow certain paradigms. Rust devs can specify types everywhere if they think it helps them, but they don't have to.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [May 9, 2023, 12:19am UTC](https://internals.rust-lang.org/t/record-types/18258/18 "2023-05-09T00:19:39Z")

</div>

Closed on May 9, 2023, 12:19am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
