# DST unions

**URL:** <https://internals.rust-lang.org/t/dst-unions/14420>\
**Category:** language design\
**Created:** [April 4, 2021, 7:45am UTC](https://internals.rust-lang.org/t/dst-unions/14420 "2021-04-04T07:45:52Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![beepster](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/beepster/32/7914_2.png) [@beepster](https://internals.rust-lang.org/u/beepster)\
**Post date:** [April 4, 2021, 7:45am UTC](https://internals.rust-lang.org/t/dst-unions/14420/1 "2021-04-04T07:45:53Z")

</div>

Currently, unions cannot contain DSTs. This is the cause of `MaybeUninit` not supporting them. I propose to make this possible.

In general, the alignment/size of a union is the largest of the alignment/sizes of its fields. The pointer metadata of a DST union is the same as its DST field. This metadata is used to calculate the alignment/size of its DST field.

Extern types cannot have their size measured so unions of extern types are not able to do so either.

For trait object unions, it is sound to use any `DynMetadata<dyn Foo>`, not necessarily the vtable corresponding to the data inside the union. However, it is unsound to get a reference to the `dyn Foo` within the union unless the vtable is valid for the data inside the union.

Any feedback is appreciated.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [April 4, 2021, 10:25am UTC](https://internals.rust-lang.org/t/dst-unions/14420/2 "2021-04-04T10:25:48Z")

</div>

Since enums can be [encoded as a struct with a tag and a union](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a89fe43d9c3c71c858f0d40546535a6e), and structs support DSTs in their last field, wouldn’t such a proposal also effectively introduce enums with unsized fields? (In which case they could also be introduced properly... well, maybe enums _are_ more complicated due to things like niche optimization, so let’s not focus on them too much.)

What’s your take on unsized coercions? If I have a

```rust
union Either<Left: ?Sized, Right: ?Sized> {
    left: ManuallyDrop<Left>,
    right: ManuallyDrop<Right>,
}

```

can I turn `Either<[bool; 10], i32>` into `Either<[bool], dyn Any>`? (Probably not, how is Rust supposed to know which one of the vtables to include..)

* * *

* * *

* * *

For the use-case of `MaybeUninit` you’d only need support for a single `T: ?Sized` argument, right? I think things only become complicated once you want to support _multiple_ different parameters. I guess, in general, there are union fields that are

1. always `Sized`,
2. always `!Sized` and their pointer metadata comes from some fixed type `dyn Trait` or `[Type]`
3. potentially unsized, depending on a type parameter `T`, where `T: ?Sized` and the type of the pointer metadata _comes directly_ from `T`; or
4. potentially unsized, depending one or multiple parameters, but through some indirection (e.g. associated type of traits, etc.)

For structs, similar cases are possible for the last field, but the only really interesting/useful _unsized_ case is just the 3rd one, since otherwise it’s hard to construct the struct anyways (without lots of unsafe code).

Focusing on this case then, we might restrict unsized unions to cases where where _every field_ is either

- _always `Sized`_

or

- _potentially using metadata depending **directly** from a type parameter `T`_

with the additional restrictions that

- _all of the potentially unsized fields use **the same** type parameter `T`_; and
- _the type parameter `T` is not used in any of the always sized fields_.

This includes `MaybeUninit`. AFAICT, in these cases unions should then be able to support [`Unsize`](https://doc.rust-lang.org/std/marker/trait.Unsize.html).

* * *

Going back to the cases 2. or 4. above; I haven’t thought much about 4., but regarding 2., one might also allow unions where _all_ fields are either always sized or always unsized _and_ all of the metadata types are the same. This kind of union could then, perhaps, be constructed by transmuting a (similarly structured) union that’s of the form described in the previous section. However it is debatable how valuable such unions are after all. For structs, the possibility to do something like creating a newtype around e.g. `str` is a good use-case; on the other hand a union like

```rust
union Foo {
    x: str,
    y: (u8, str),
}

```

could always be replaced by something like this using a struct:

```rust
union FooInner<T: ?Sized> {
    x: ManuallyDrop<T>,
    y: ManuallyDrop<(u8, T)>,
}
struct Foo {
    inner: FooInner<str>
}

```

* * *

_Edit:_ Some more examples on the restrictions I tried to lay out above:

```rust
// allowed
union MaybeUninit<T: ?Sized> {
    uninit: (),
    value: ManuallyDrop<T>,
}

```

```rust
// allowed
union FooInner<T: ?Sized> {
    x: ManuallyDrop<T>,
    y: ManuallyDrop<(u8, T)>,
}

```

```rust
// not allowed
union Bar<T: ?Sized> {
    x: ManuallyDrop<Box<T>>,
    y: ManuallyDrop<T>,
}

```

```rust
// allowed
union Bar<S: ?Sized, T: ?Sized> {
    x: ManuallyDrop<Box<S>>,
    y: ManuallyDrop<T>,
}

```

```rust
// not allowed
union Bar<S: ?Sized, T: ?Sized> {
    x: ManuallyDrop<S>,
    y: ManuallyDrop<T>,
}

```

---

<div class="post-metadata">

**Author:** ![beepster](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/beepster/32/7914_2.png) [@beepster](https://internals.rust-lang.org/u/beepster)\
**Post date:** [April 14, 2021, 8:01pm UTC](https://internals.rust-lang.org/t/dst-unions/14420/3 "2021-04-14T20:01:16Z")

</div>

> [@steffahn](#):
>
> _the type parameter `T` is not used in any of the always sized fields._

What's the reasoning behind this? If its used in a Sized field, then it won't affect pointer metadata, so there's not really a reason to ban it

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [April 14, 2021, 8:14pm UTC](https://internals.rust-lang.org/t/dst-unions/14420/4 "2021-04-14T20:14:50Z")

</div>

The reasoning behind it is that this way unsized coercion can work for that type parameter `T`. You can't turn a `& union { T, Box<T> }` into `& union { dyn Trait, Box<dyn Trait> }` bcause of the `T` inside of the `Box`.

Sorry for the short answer I'm only on mobile.

Thinking about this, I probably need to a restriction in my list that would disallow multiple uses of `T` in the type of the same conditionally unsized field.

---

<div class="post-metadata">

**Author:** ![robinm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/robinm/32/6255_2.png) [@robinm](https://internals.rust-lang.org/u/robinm)\
**Post date:** [April 15, 2021, 1:43pm UTC](https://internals.rust-lang.org/t/dst-unions/14420/5 "2021-04-15T13:43:04Z")

</div>

> [@steffahn](#):
>
> can I turn `Either<[bool; 10], i32>` into `Either<[bool], dyn Any>` ? (Probably not, how is Rust supposed to know which one of the vtables to include..)

Couldn’t we store the v-table before the DST data? (ie. the layout of DST union would be a pointer + an unspecified amount of bytes for the data itself).

It’s probably even cleaner with `enum`, since the discriminant can be directly used to index a const array of v-table (assuming that the discriminant is a counter starting from 0).

---

<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:** [July 14, 2021, 1:43pm UTC](https://internals.rust-lang.org/t/dst-unions/14420/6 "2021-07-14T13:43:35Z")

</div>

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