Maybe-RFC: trait for `as` casting

This is a maybe-RFC, because I’m not even sure if the idea is actually as interesting as it seems to me.

Idea

To create an As trait, which represents possibility of casting with as keyword:

trait As<T> {
    fn as(self) -> T;
}

By default the trait is defined in stdlib for all types that can be casted with an as keyword.

Motivation

Currently there’s no way to define a type that is castable to another one. One can’t write a generic structure that holds anything castable to u32. Or a function that accepts fn item that can be casted to a specific fn pointer.

Another thing is elevation of as keyword to a fully functional operator, that can be defined by user for types, same as +, [] and ?. Automatic coercion between custom types becomes a thing.

This potentially makes the experimental CoerceUnsized trait fully covered and obsolete.

1 Like

Why aren’t From and Into good enough for this purpose? These are the standard traits with which user-defined conversions are supposed to be defined.

From and Into are definitely enough. Yet some conversions are defined with as and that gives them automatic coercion.

This has come up many times; the core problem is that as is too random in the kinds of things that it does to be usable generically.

Personally, I’d like to see subsets, like the WrappingFrom in

Since that at least has a justifiable semantics instead of “do something to turn a thing into a thing and who knows what will happen”.

7 Likes

Why a new trait in particular? For integers a wrapper type alone could suffice.

struct WrappingU16(u16);

impl From<WrappingU16> for u8 { … }

impl u16 {
    pub fn wrapping(self) -> WrappingU16 { WrappingU16(self) }
}

let x: u16 = 0;
let y: u8 = x.wrapping().into();
1 Like

The wrapper is going to work in non-generic case, but it’s a workaround adding custom cruft to code. The new trait is clean, global and generic solution. At least it’s supposed to be.

Because coherence. (std::num::Wrapping isn’t fundamental.)

It’s legal to

impl From<i32> for Foo { ... }

But using wrapping you get

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
 --> src/lib.rs:6:1
  |
6 | impl From<Wrapping<i32>> for Wrapping<Foo> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate