# Pre-RFC: Safe coercions

**URL:** <https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823>\
**Category:** Uncategorized\
**Created:** [February 21, 2017, 2:14am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823 "2017-02-21T02:14:07Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![dobenour](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dobenour/32/7241_2.png) [@dobenour](https://internals.rust-lang.org/u/dobenour)\
**Post date:** [February 21, 2017, 2:14am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/1 "2017-02-21T02:14:07Z")

</div>

This is a pre-RFC for safe coercions.

Safe coercions are implemented via a magic trait `Coercible<A, B>`. Instances of `Coercible<A, B>` exist as follows:

1. Between any two types A and B such that casting via `as` would be legal AND the two types have the same size, but NOT if one is a floating-point type and the other is not.
2. Between any two struct, enum, tuple, or slice types A and B, such that:
  - a. Instances of `Coercible<C, D>` exist for every corresponding member of A and B.
  - b. All fields that have different types in A and B are visible at the location where the coercion is made.

3. Optionally, other instances may exist, such as allowing an array of integers to be coerced to an array of bytes of the same size.

`Coercible<A,B>` looks as follows:

```rust
use std::mem;
unsafe trait Coercible<A, B> {
    #[inline(always)]
    fn coerce(a: A) -> B {
        unsafe { mem::transmute(a) }
    }
}

```

Creating instances of `Coercible` manually is nonsensical and a compile-time error. Alternatively, it may be possible for users to opt-in manually by implementing it. This doesn’t break Rust’s safety guarantees, since `Coercible` is an unsafe trait.

Because of rule 2b, it is not possible to use `Coercible` to circumvent privacy restrictions.

The inspiration for this comes entirely from GHC’s `Coercible` typeclass and matching function `coerce`, which serve the same purpose as here.

---

<div class="post-metadata">

**Author:** ![Fylwind](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fylwind/32/2117_2.png) [@Fylwind](https://internals.rust-lang.org/u/Fylwind)\
**Post date:** [February 21, 2017, 2:36am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/2 "2017-02-21T02:36:44Z")

</div>

That’s an interesting idea. It’d useful for situations where you want to switch out some phantom type deep inside some container (or nested containers).

But I’m not sure the idea of “visibilty-dependent trait implementations” would work without some additional machinery in the language. Trait implementations are global in Rust, much like in Haskell, so it would be odd to have one whose availability is dependent on which module you’re in.

Another concern is that the layout of structs may change after optimization. Currently there is no guarantee that the layout of two structs are the same even if they have identical underlying types and identical ordering.

Maybe it’s best to make Coercible a strictly opt-in trait. The user would opt-in by writing a blank `impl` along with the appropriate `Coercible` trait bounds for its interior types. The compiler would then check if the bounds are sane (i.e. do not violate memory safety or existing `Coercible` constraints), and if it passes the impl will be upheld by the compiler. The impl acts as an optimization constraint: these two types _must_ have the same internal memory representation even after optimization and possible reshuffling.

---

<div class="post-metadata">

**Author:** ![dobenour](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dobenour/32/7241_2.png) [@dobenour](https://internals.rust-lang.org/u/dobenour)\
**Post date:** [February 21, 2017, 3:18am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/3 "2017-02-21T03:18:05Z")

</div>

GHC handles this (visibility-dependent trait implementations) just fine, although instead of visibility (which Haskell doesn’t have) it uses whether or not the corresponding type constructor is in scope.

Can you see a reason why the layout of two structs with identical underlying types and ordering would change after optimization? I can’t. In fact, I would not be surprised if this would break existing code, at least in the case of `mem::transmute`-ing a phantom type parameter (this trick can be used to implement a form of subtyping I believe).

---

<div class="post-metadata">

**Author:** ![Fylwind](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fylwind/32/2117_2.png) [@Fylwind](https://internals.rust-lang.org/u/Fylwind)\
**Post date:** [February 21, 2017, 3:21am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/4 "2017-02-21T03:21:06Z")

</div>

> [@dobenour](#):
>
> Can you see a reason why the layout of two structs with identical underlying types and ordering would change after optimization?

Not saying it does. It’s just something that has never been actually specified.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [February 21, 2017, 4:26am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/5 "2017-02-21T04:26:03Z")

</div>

> [@dobenour](#):
>
> Between any two types A and B such that casting via as would be legal AND the two types havethe same size.

Does this include (i32, f32)?

What is the self type here?

---

<div class="post-metadata">

**Author:** ![dobenour](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dobenour/32/7241_2.png) [@dobenour](https://internals.rust-lang.org/u/dobenour)\
**Post date:** [February 21, 2017, 4:39am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/6 "2017-02-21T04:39:00Z")

</div>

Sorry about the bad code – I was thinking in Haskell terms, and Haskell doesn’t have any concept of `self`. So the current idea is a free function, rather than a method.

---

<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:** [March 25, 2019, 8:27am UTC](https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823/7 "2019-03-25T08:27:59Z")

</div>

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