Unsafe way to escape the type system?

Let's say I want to convert one type to another, and I have enough info to know that it will work, but the compiler doesn't.

In other words I have A: From<B> but I can't specify this in the signature because of how the data is structured.

Is there any way, even if unsafe to do this? Here's an example:

//Don't need a return type, `convert()` is a side-effect thing
fn main() {
    convert(A{}, Kind::B);
}

//Ultimately, here's my problem:
fn convert<T: Foo>(x: T, kind: Kind) {
    match kind {
        Kind::B => {
            //fails
            let b:B = x.into();
        }
        _ => {}
    }
}

//I have this original data
struct A {}

//But all I know about it is that it satisfies this trait
trait Foo {}
impl Foo for A {}

//enum describing the type of operation
//as you can see it's decoupled from the actual data type
enum Kind {
    B,
    C
}

//These match the Kind 1:1 but that's knowledge I have, not the compiler
struct B {}
struct C {}

//We can associate them like this, but it doesn't really help
//since I can't add these constraints to `Foo`
impl From<A> for B {
    fn from(a:A) -> Self {
        B {}
    }
}
impl From<A> for C {
    fn from(a:A) -> Self {
        C {}
    }
}


Why not just add the conversion method to the trait?

1 Like

Looks like transmute might be what you want?

Not every Foo can be converted into B or C.

Yeah @abusch I think you may be right..

Then why not create a sub-trait for Foo for types that can be converted?

It's too deep down the chain, the parent function only knows it's Foo, not a specific sub-type.

You can add a fallible conversion method to the trait and give it a default impl that just panics.

5 Likes

ah that's a nice idea :slight_smile:

should I prefer that to transmute?

Yes.

5 Likes

I need to create a specific fn for each target type here, right? e.g.

convert_to_b()
convert_to_c()

Yes, if there are multiple conversions you need a method for each.

1 Like

Thanks again! off to implement :slight_smile:

I generally prefer something like this, so the caller can decide whether or not to panic!:

trait Foo {
    fn convert_to_b(self)->Result<B, Self> { Err(self) }
}
5 Likes

Do you mean something like this? Functions can have a separate 'bounds' section where arbitrary bounds can be given.

fn convert<T: Foo>(x: T, kind: Kind)
where
    B: From<T>,
{ ... }

You can also instead use TryFrom as a bound, which allows the conversion to fail:

use core::convert::TryFrom;

fn convert<T: Foo>(x: T, kind: Kind)
where
    B: TryFrom<T>, ...
{ ... }