Rust trait alias - rust

I am working on a actor project which need alias for the trait because it is so long, but even with the nightly feature #![feature(trait_alias)] seems can not achieve.
In short I write a playground:
I want alias A<T> to be shorter causing I have many generic type on A in real case; and the same time I want to access the type Output = Self; from its implementations B.
Appreciate for any help.
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=5a9bb8d3f76112c0b73ea1da8af34959
#![feature(trait_alias)]
trait A<T> {
type Output;
fn test(a: T) -> Self::Output;
}
//To alias the trait, real situation longer than this.
//attempt 1:
trait B: A<String>{}
//attempt 2:
//trait B : A<String, Output=Self> where Self: std::marker::Sized {}
//impl<T> B for T where T: A<String, Output=T> {}
//attempt 3 with trait_alias:
//trait B = A<String>;
struct SA;
impl B for SA {
type Output = Self;
}

trait alias is only mean to be:
used wherever traits would normally be used as either bounds or trait objects. Source
So, your use case doesn't match, you can't do that.

Related

Concrete Option<Box<impl T>> conversion to Option<Box<dyn T>> in Rust [duplicate]

I'm having trouble understanding how values of boxed traits come into existence. Consider the following code:
trait Fooer {
fn foo(&self);
}
impl Fooer for i32 {
fn foo(&self) { println!("Fooer on i32!"); }
}
fn main() {
let a = Box::new(32); // works, creates a Box<i32>
let b = Box::<i32>::new(32); // works, creates a Box<i32>
let c = Box::<dyn Fooer>::new(32); // doesn't work
let d: Box<dyn Fooer> = Box::new(32); // works, creates a Box<Fooer>
let e: Box<dyn Fooer> = Box::<i32>::new(32); // works, creates a Box<Fooer>
}
Obviously, variant a and b work, trivially. However, variant c does not, probably because the new function takes only values of the same type which is not the case since Fooer != i32. Variant d and e work, which lets me suspect that some kind of automatic conversion from Box<i32> to Box<dyn Fooer> is being performed.
So my questions are:
Does some kind of conversion happen here?
If so, what the mechanism behind it and how does it work? (I'm also interested in the low level details, i.e. how stuff is represented under the hood)
Is there a way to create a Box<dyn Fooer> directly from an i32? If not: why not?
However, variant c does not, probably because the new function takes only values of the same type which is not the case since Fooer != i32.
No, it's because there is no new function for Box<dyn Fooer>. In the documentation:
impl<T> Box<T>
pub fn new(x: T) -> Box<T>
Most methods on Box<T> allow T: ?Sized, but new is defined in an impl without a T: ?Sized bound. That means you can only call Box::<T>::new when T is a type with a known size. dyn Fooer is unsized, so there simply isn't a new function to call.
In fact, that function can't exist in today's Rust. Box<T>::new needs to know the concrete type T so that it can allocate memory of the right size and alignment. Therefore, you can't erase T before you send it to Box::new. (It's conceivable that future language extensions may allow functions to accept unsized parameters; however, it's unclear whether even unsized_locals would actually enable Box<T>::new to accept unsized T.)
For the time being, unsized types like dyn Fooer can only exist behind a "fat pointer", that is, a pointer to the object and a pointer to the implementation of Fooer for that object. How do you get a fat pointer? You start with a thin pointer and coerce it. That's what's happening in these two lines:
let d: Box<Fooer> = Box::new(32); // works, creates a Box<Fooer>
let e: Box<Fooer> = Box::<i32>::new(32); // works, creates a Box<Fooer>
Box::new returns a Box<i32>, which is then coerced to Box<Fooer>. You could consider this a conversion, but the Box isn't changed; all the compiler does is stick an extra pointer on it and forget its original type. rodrigo's answer goes into more detail about the language-level mechanics of this coercion.
Hopefully all of this goes to explain why the answer to
Is there a way to create a Box<Fooer> directly from an i32?
is "no": the i32 has to be boxed before you can erase its type. It's the same reason you can't write let x: Fooer = 10i32.
Related
Why can't I write a function with the same type as Box::new?
Are polymorphic variables allowed?
How do you actually use dynamically sized types in Rust?
Why is `let ref a: Trait = Struct` forbidden?
I'll try to explain what conversions (coercions) happen in your code.
There is a marker trait named Unsize that, between others:
Unsize is implemented for:
T is Unsize<Trait> when T: Trait.
[...]
This trait, AFAIK, is not used directly for coercions. Instead, CoerceUnsized is used. This trait is implemented in a lot of cases, some of them are quite expected, such as:
impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
where
'b: 'a,
T: Unsize<U> + ?Sized,
U: ?Sized
that is used to coerce &i32 into &Fooer.
The interesting, not so obvious implementation for this trait, that affects your code is:
impl<T, U> CoerceUnsized<Box<U>> for Box<T>
where
T: Unsize<U> + ?Sized,
U: ?Sized
This, together with the definition of the Unsize marker, can be somewhat read as: if U is a trait and T implements U, then Box<T> can be coerced into Box<U>.
About your last question:
Is there a way to create a Box<Fooer> directly from an i32? If not: why not?
Not that I know of. The problem is that Box::new(T) requires a sized value, since the value passed is moved into the box, and unsized values cannot be moved.
In my opinion, the easiest way to do that is to simply write:
let c = Box::new(42) as Box<Fooer>;
That is, you create a Box of the proper type and then coerce to the unsized one (note it looks quite similar to your d example).

Why does the compiler treat those two equivalent(?) lines differently?

From what I understand, when x implements trait Foo,
the following two lines should be equivalent.
x.foo();
Foo::foo(&x);
However, I am facing a problem where the compiler accepts the first one, and rejects the second one, with a rather strange error message.
As usual, this example is available on the playground.
Consider the following two related traits.
pub trait Bar<'a> {
type BarError: Into<MyError>;
fn bar(&self) -> Result<(), Self::BarError>;
}
pub trait Foo: for<'a> Bar<'a> {
type FooError: Into<MyError>;
fn foo(&self) -> Result<(), Self::FooError>
where
for<'a> <Self as Bar<'a>>::BarError: Into<<Self as Foo>::FooError>;
}
This example is a bit complex, but I do need the lifetime parameter on Bar, and I can't have it on Foo. As a consequence:
I have to resort on Higher-Rank Trait Bounds (HRTB);
I can not rely on Bar::BarError in Foo (there are actually an infinite number of types Bar<'_>::BarError), so Foo must have its own FooError;
and so I need the complex trait bound in the foo method to convert BarErrors to FooErrors.
Now, let's implement Bar and Foo for a concrete type, e.g. Vec<i32>.
impl<'a> Bar<'a> for Vec<i32> {
type BarError = Never;
fn bar(&self) /* ... */
}
impl Foo for Vec<i32> {
type FooError = Never;
fn foo(&self) /* ... */
}
Note that Never is an empty enum, indicating that these implementations never fail. In order to comply with the trait definitions, From<Never> is implemented for MyError.
We can now demonstrate the problem: the following compiles like charm.
let x = vec![1, 2, 3];
let _ = x.foo();
But the following des not.
let x = vec![1, 2, 3];
let _ = Foo::foo(&x);
The error messages says:
error[E0271]: type mismatch resolving `<std::vec::Vec<i32> as Foo>::FooError == MyError`
--> src/main.rs:49:13
|
49 | let _ = Foo::foo(&x);
| ^^^^^^^^ expected enum `Never`, found struct `MyError`
|
= note: expected type `Never`
found type `MyError`
The compiler seems to believe that I wrote something like this (NB: this is not correct Rust, but just to give the idea).
let _ = Foo::<FooError=MyError>::foo(&x);
And this does not work because x implements Foo<FooError=Never>.
Why does the compiler adds this additional constraint? Is it a bug? If not, is it possible to write it otherwise so it compiles?
NB: you may wonder why I don't just stick to the first version (x.foo(&x)). In my actual situation, foo is actually named retain, which is also the name of a method in Vec. So I must use the second form, to avoid the ambiguity.
NB2: if I remove the HRTB in the declaration of method foo, both lines compile. But then I can not call Bar::bar in any implementation of Foo::foo, which is not an option for me. And changing foo to something like fn foo<'a>(&'a self) -> Result<(), <Self as Bar<'a>>::BarError) is not an option either, unfortunately.
From what I understand, when x implements trait Foo, the following two lines should be equivalent.
x.foo();
Foo::foo(&x);
This is true for an inherent method (one that is defined on the type of x itself), but not for a trait method. In your case the equivalent is <Vec<i32> as Foo>::foo(&x);.
Here is a playground link

Specify relation between types as a trait or macro

I would like to make something like the following work:
use std::ops::Add;
trait CanBeAdded: Sized where f64: Add<Self> {}
fn add2<X: CanBeAdded>(x: X) {}
fn main() {}
The above fails to compile:
error[E0277]: the trait bound `f64: std::ops::Add<X>` is not satisfied
--> src/main.rs:5:1
|
5 | fn add2<X: CanBeAdded>(x: X) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Add<X>` is not implemented for `f64`
|
= help: consider adding a `where f64: std::ops::Add<X>` bound
= note: required by `CanBeAdded`
Playground link
I'm trying to assert the existence of certain impls via a trait: i.e. X: CanBeAdded implies f64: Add<X>. While I can add the bounds to the where clause of the function like this:
fn add2<X>(x: X) where f64: Add<X> { }
I have many of them so it gets unwieldy and I would prefer to not repeat the bounds over and over. Is there a good solution to this? For example, is it possible to include a macro that expands to a series of where clauses?
It's actually quite unlikely that a random type X is such that f64: Add<X>.
Given that f64 is a built-in, the only module which can define implementations of Add for f64 is the one where Add is defined. We can check the listed implementations here:
impl Add<f64> for f64
impl<'a> Add<&'a f64> for f64
And that's all.
Still, if that is all that you want, you can define the trait differently.
First, we define a new marker trait. It's pretty uninteresting by itself as it has absolutely no method:
trait ReverseAdd<T> { type Output; }
Then, we add a blanket implementation, to automatically implement the trait for any type that implements Add, but with the relationship reversed:
impl<T, U> ReverseAdd<T> for U where T: Add<U> {
type Output = <T as Add<U>>::Output;
}
And finally, we use it as our bound:
fn add2<X: ReverseAdd<f64>>(x: X) {
}

How do you create a Box<dyn Trait>, or a boxed unsized value in general?

I have the following code
extern crate rand;
use rand::Rng;
pub struct Randomizer {
rand: Box<Rng>,
}
impl Randomizer {
fn new() -> Self {
let mut r = Box::new(rand::thread_rng()); // works
let mut cr = Randomizer { rand: r };
cr
}
fn with_rng(rng: &Rng) -> Self {
let mut r = Box::new(*rng); // doesn't work
let mut cr = Randomizer { rand: r };
cr
}
}
fn main() {}
It complains that
error[E0277]: the trait bound `rand::Rng: std::marker::Sized` is not satisfied
--> src/main.rs:16:21
|
16 | let mut r = Box::new(*rng);
| ^^^^^^^^ `rand::Rng` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `rand::Rng`
= note: required by `<std::boxed::Box<T>>::new`
I don't understand why it requires Sized on Rng when Box<T> doesn't impose this on T.
More about the Sized trait and bound - it's a rather special trait, which is implicitly added to every function, which is why you don't see it listed in the prototype for Box::new:
fn new(x: T) -> Box<T>
Notice that it takes x by value (or move), so you need to know how big it is to even call the function.
In contrast, the Box type itself does not require Sized; it uses the (again special) trait bound ?Sized, which means "opt out of the default Sized bound":
pub struct Box<T> where T: ?Sized(_);
If you look through, there is one way to create a Box with an unsized type:
impl<T> Box<T> where T: ?Sized
....
unsafe fn from_raw(raw: *mut T) -> Box<T>
so from unsafe code, you can create one from a raw pointer. From then on, all the normal things work.
The problem is actually quite simple: you have a trait object, and the only two things you know about this trait object are:
its list of available methods
the pointer to its data
When you request to move this object to a different memory location (here on the heap), you are missing one crucial piece of information: its size.
How are you going to know how much memory should be reserved? How many bits to move?
When an object is Sized, this information is known at compile-time, so the compiler "injects" it for you. In the case of a trait-object, however, this information is unknown (unfortunately), and therefore this is not possible.
It would be quite useful to make this information available and to have a polymorphic move/clone available, but this does not exist yet and I do not remember any proposal for it so far and I have no idea what the cost would be (in terms of maintenance, runtime penalty, ...).
I also want to post the answer, that one way to deal with this situation is
fn with_rng<TRand: Rng>(rng: &TRand) -> Self {
let r = Box::new(*rng);
Randomizer { rand: r }
}
Rust's monomorphism will create the necessary implementation of with_rng replacing TRand by a concrete sized type. In addition, you may add a trait bound requiring TRand to be Sized.

Type mismatch in trait bound - Why can't rustc infer the type on its own?

I just ran into an issue in some code of mine and managed to trim it down to the following minimal example :
use std::iter::IntoIterator;
use std::marker::PhantomData;
trait Bar<'a> {
fn compile_plz(&self) -> &'a str;
}
struct Foo<'a> {
ph: PhantomData<&'a str>
}
impl<'a> Bar<'a> for Foo<'a> {
fn compile_plz(&self) -> &'a str {
"thx"
}
}
fn do_something_with_bars<'a, I>(it: I) -> Result<(), ()> where I: IntoIterator<Item=&'a Bar<'a>> {
Ok(())
}
fn take_bar<'a, B>(b: &'a B) where B: Bar<'a> {
do_something_with_bars(vec![b]);
}
fn main() {
let f = Foo{ph: PhantomData};
take_bar(&f);
}
This fails with the following error :
23:5: 23:27 error: type mismatch resolving <collections::vec::Vec<&B> as core::iter::IntoIterator>::Item == &Bar<'_>:
expected type parameter,
found trait Bar [E0271]
However, changing vec![b] to vec![b as &Bar] works fine. But since b is of type &B, and B has a Bar<'a> bound, why can't the compiler figure out that b is indeed a &Bar?
It could theoretically attempt to 'fix' the type to &Bar. However, you're hitting the variance problem here - a vector of &B is not a vector of &Bar just because a &B is a &Bar, and neither is the inverse true.
Example: Say we treat a vector of &B as a vector of &Bar. Now we have a value of type &C where &C is a &Bar but not a &B - can we put a &C into our vector? Well, obviously not, because the implementation is a vector of &B. So we can only allow reads, not writes. On the other hand, we can attempt to treat a vector of &Bar as a vector of &B - this works fine as long as we only write &Bs into our vector (because it's allowed to accept &Bs of course) - but since it's still a vector of &Bar, it can contain things that aren't &Bs, so we aren't allowed to read from it.
Hence, a container that allows both read and write at the same time needs to be invariant in its generic argument. You'll always have this problems in languages that have both polymorphism and generics in this fashion.
So, back to the actual question: Since this problem exists, there can't be an automatic escape hatch that would turn your expression that is initially going to be inferred to be vector of &B to the type vector of &Bar. Be explicit about your types, and this won't happen.
Full type inference maybe could help here, but I'm not sure if full type inference is even possible in a language like rust.

Resources