How to triple pendent traits un Rust without using dyn? - rust

I have three traits that are dependent on each other, but I can't find a way to define these traits statically without using dyn.
Defining two seems very simple:
pub trait TA<B: TB<Self>> {
fn getB() -> Option<B>;
}
pub trait TB<A: TA<Self>> {
fn getA() -> Option<A>;
}
But defining similar thing with three traits seems impossible (the code bellow doesn't compile):
pub trait TA<B: TB, C: TC> {
fn getB() -> Option<B>;
fn getC() -> Option<C>;
}
pub trait TB<A: TA, C: TC> {
fn getA() -> Option<A>;
fn getC() -> Option<C>;
}
pub trait TC<A: TA, B: TB> {
fn getA() -> Option<A>;
fn getB() -> Option<B>;
}

It seems like with another thought it was easier than I thought.
pub trait TA<B: TB<Self, C>, C: TC<Self, B>> {
fn getB() -> Option<B>;
fn getC() -> Option<C>;
}
pub trait TB<A: TA<Self, C>, C: TC<Self, A>> {
fn getA() -> Option<A>;
fn getC() -> Option<C>;
}
pub trait TC<A: TA<A, Self>, B: TB<B, Self>> {
fn getA() -> Option<A>;
fn getB() -> Option<B>;
}
Edit: #trenctl solution bellow looks much cleaner
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=062b05bf63efb1b6bfb2575bf963ff62
trait Ta {
type B: Tb<A = Self, C = Self::C>;
type C: Tc<A = Self, B = Self::B>;
fn get_b(&self) -> Option<Self::B>;
fn get_c(&self) -> Option<Self::C>;
}
trait Tb {
type A: Ta<B = Self, C = Self::C>;
type C: Tc<B = Self, A = Self::A>;
fn get_a(&self) -> Option<Self::A>;
fn get_c(&self) -> Option<Self::C>;
}
trait Tc {
type A: Ta<C = Self, B = Self::B>;
type B: Tb<C = Self, A = Self::A>;
fn get_a(&self) -> Option<Self::A>;
fn get_b(&self) -> Option<Self::B>;
}

Related

How to wrap a closure and still match a trait bound [duplicate]

I'm a newbie with Rust and I bumped into some obstacles when dealing with closures, either when returning them from functions and or methods, either when I need to store them as struct fields.
Let's start with what is working:
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo<F>
where
F: Fn(usize) -> usize,
{
fn new(foo: F) -> Self {
Self { foo }
}
}
fn main() {
let foo1 = Foo { foo: |a| a + 1 };
let foo2 = Foo { foo: build_func(2) };
let foo_func = build_func(3);
let foo3 = Foo { foo: foo_func };
}
This works as expected and the type of the closure that is built outside the struct is properly matched with the generic of Foo.
I wanted to achieve the same, but by hiding the creation of the closure simply by moving it inside the impl of Foo itself.
I tested these alternatives, but none of theme compiles:
struct Foo2<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
struct Foo3<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo3<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = |a| a + 1;
Self { foo }
}
}
struct Foo4<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo4<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> F {
move |a| a + b
}
}
struct Foo5<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo5<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
I understand that each closure has its own opaque and distinct type, but then I don't understand why on the other hand the initial implementation of Foo works then.
By reading the accepted answer here I seem to understand that the only option, in this case, would be to box the closure, but I still don't have a full understanding.
By combining boxed closure and trait aliases (I know it's not the "real" trait aliasing) I came up with this:
trait Func: Fn(usize) -> usize {}
impl<T> Func for T where T: Fn(usize) -> usize {}
struct Foo6 {
pub foo: Box<dyn Func>,
}
impl Foo6 {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Func {
move |a| a + b
}
}
fn main() {
let foo = Foo6::new();
println!("{}", (foo.foo)(1));
}
But I'm wondering whether it's possible to obtain an unboxed version.
The problem in this code:
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
is that to call it, the user code would need to write something like this:
let foo2 = <Foo2<?>>::new();
And specify some type there. Even if the type is not typed explicitly, it should be resolved there (type omission is mostly syntactic sugar). But the type of the stored value is decided inside that function, in the call to build_func(1), so the user has no type to use there and that function cannot be called.
My advice is to just write a free function:
fn new_foo2() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
Now the generic type is an impl in the return type of the function, that is an special opaque generic decided by the code of the function. So this works.
If you really, really want to write Foo2::new you can write the function implementation inside a dummy non-generic impl Foo2 block. Usually that would be impl Foo2<()> but the type () does not satisfies your constraints, but you can use any other dummy type that does:
impl Foo2<fn(usize)->usize> {
fn new() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
}
(Note that this new() does not return Self because the generic type is not correct.)
And now you can at least write:
let foo2 = Foo2::new();
The difference here is that you're returning Self from new(). Inside impl<F> Foo<F>, Self refers to Foo<F>. And F is a generic parameter - you cannot build a closure of type F, because it's a type your caller decides what it is, not you.
Your first version works because it tells the compiler "I will return some type implementing Fn; I'll leave it to you infer what exactly". On the other hand, the second versions are all "given any type F implementing Fn, I'll give you an instance of that type". That is of course impossible.
Instead you want the compiler to infer the used type here, too. The best solution will be to use impl Trait here, too. But impl Trait in positions other than return type is unstable. It will look like (playground):
#![feature(type_alias_impl_trait)]
type InnerFn = impl Fn(usize) -> usize;
struct Foo {
pub foo: InnerFn,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> InnerFn {
move |a| a + b
}
}
Another (quite hacky) solution is to have a generic parameter, but not use it and instead use impl Trait in new(). To not require the caller to specify the redundant parameter (since it can't be inferred anymore as it's unused), we can use a marker type, usually (). This requires us to remove the F: Fn(usize) -> usize bound from the struct and put it only on the impl, however this is a good style anyway (playground):
struct Foo<F> {
pub foo: F,
}
impl Foo<()> {
fn new() -> Foo<impl Fn(usize) -> usize> {
let foo = Self::build_func(1);
Foo { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
The last solution is indeed to box the closure, but you don't need a new trait for that - you can use Fn directly (playground):
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}

How to support two visitors which returns different return value types in Rust?

I am trying to implement a Visitor pattern in Rust.
I am not able to find a way to support two visitors which return different return value types.
Playground link
trait Visited<R> {
fn accept (self: &Self, v: &dyn Visitor<R>) -> R;
}
trait Visitor<R> {
fn visit_a(&self, a: &A<R>) -> R;
fn visit_b(&self, b: &B) -> R;
}
I've implemented two data structures that can be visited.
// ---- A ----
struct A<R> {
value: String,
b: Box<dyn Visited<R>>,
}
impl<R> Visited<R> for A<R> {
fn accept (&self, v: &dyn Visitor<R>) -> R {
v.visit_a(self)
}
}
// ---- B ----
struct B {
value: i32,
}
impl<R> Visited<R> for B {
fn accept(&self, v: &dyn Visitor<R>) -> R {
v.visit_b(self)
}
}
This worked okay when I just had a concrete visitor.
struct Visitor1 {}
impl Visitor<String> for Visitor1 {
fn visit_a(&self, a: &A<String>) -> String {
let b = a.b.accept(self);
format!("visitor1.visit_a(): {} {}", a.value, b)
}
fn visit_b(&self, b: &B) -> String {
format!("visitor1.visit_b(): {}", b.value)
}
}
However, the whole point of the Visitor pattern is to let multiple algorithm to be applied against the data structure.
When I wanted to add another visitor, I couldn't figure out how to make it work.
struct Visitor2 {}
impl Visitor<i32> for Visitor2 {
fn visit_a(&self, a: &A<i32>) -> i32 {
123
}
fn visit_b(&self, b: &B) -> i32 {
456
}
}
fn main() {
let a = A {
value: "HELLO".to_string(),
b: Box::new(B{ value: 32 })
};
let v1 = Visitor1{};
let s: String = a.accept(&v1);
println!("{}", s);
let v2 = Visitor2{};
let v: i32 = a.accept(&v2);
println!("{}", v);
}
The type of a is inferred as A<String>, and the a.accept(&v2) caused a type mismatch error.
I'd like to tell a to be visited by Visitor1 and Visitor2. How can I do this?
If you return only 'static types, you can use type erasure. The idea is to create a trait, ErasedVisitor, that is not generic and instead return Box<dyn Any>, and implement this trait for all Visitors and use it internally. This mean, though, that you cannot use a generic parameter, only an associated type (otherwise you get "unconstrained type parameter":
trait Visited {
fn accept_dyn(&self, v: &dyn ErasedVisitor) -> Box<dyn Any>;
fn accept<V: Visitor>(&self, v: &V) -> V::Result
where
Self: Sized,
{
*self.accept_dyn(v).downcast().unwrap()
}
}
impl<T: ?Sized + Visited> Visited for &'_ T {
fn accept_dyn(&self, v: &dyn ErasedVisitor) -> Box<dyn Any> {
T::accept_dyn(&**self, v)
}
}
impl<T: ?Sized + Visited> Visited for &'_ mut T {
fn accept_dyn(&self, v: &dyn ErasedVisitor) -> Box<dyn Any> {
T::accept_dyn(&**self, v)
}
}
impl<T: ?Sized + Visited> Visited for Box<T> {
fn accept_dyn(&self, v: &dyn ErasedVisitor) -> Box<dyn Any> {
T::accept_dyn(&**self, v)
}
}
trait Visitor {
type Result: 'static;
fn visit_a(&self, a: &A) -> Self::Result;
fn visit_b(&self, b: &B) -> Self::Result;
}
trait ErasedVisitor {
fn visit_a(&self, a: &A) -> Box<dyn Any>;
fn visit_b(&self, b: &B) -> Box<dyn Any>;
}
impl<V: ?Sized + Visitor> ErasedVisitor for V {
fn visit_a(&self, a: &A) -> Box<dyn Any> {
Box::new(<Self as Visitor>::visit_a(self, a))
}
fn visit_b(&self, b: &B) -> Box<dyn Any> {
Box::new(<Self as Visitor>::visit_b(self, b))
}
}
struct A {
value: String,
b: Box<dyn Visited>,
}
impl Visited for A {
fn accept_dyn(&self, v: &dyn ErasedVisitor) -> Box<dyn Any> {
v.visit_a(self)
}
}
Playground.
But if you can, the best way is to use static polymorphism (generics) instead of dynamic dispatch.
If you want your Visited trait to support multiple return types, you cannot tie the return type to the object itself. Currently, the return type is a generic, so every object has the return type hard-coded into it.
To solve this, you can remove the return type generic from the Visited trait and instead attach it to the accept function.
This has one drawback though: You can no longer create trait objects with this trait. That makes sense, because once cast to a dyn Visited, Rust no longer knows which type it is, making it impossible for the compiler to compile the accept function for all required types. It looses the knowledge between the compilated function and the types that it will get called with.
Normally, this is fine, but in your case, A holds a Box<dyn Visited>. This is impossible, due to the reasons described above.
So if we change Box<dyn Visited> to B, (and do some refactoring with the generics), we can get it to work:
trait Visited {
fn accept<V: Visitor>(&self, v: &V) -> V::Ret;
}
trait Visitor {
type Ret;
fn visit_a(&self, a: &A) -> Self::Ret;
fn visit_b(&self, b: &B) -> Self::Ret;
}
// ---- A ----
struct A {
value: String,
b: B,
}
impl Visited for A {
fn accept<V: Visitor>(&self, v: &V) -> V::Ret {
v.visit_a(self)
}
}
// ---- B ----
struct B {
value: i32,
}
impl Visited for B {
fn accept<V: Visitor>(&self, v: &V) -> V::Ret {
v.visit_b(self)
}
}
struct Visitor1 {}
impl Visitor for Visitor1 {
type Ret = String;
fn visit_a(&self, a: &A) -> String {
let b = a.b.accept(self);
format!("visitor1.visit_a(): {} {}", a.value, b)
}
fn visit_b(&self, b: &B) -> String {
format!("visitor1.visit_b(): {}", b.value)
}
}
struct Visitor2 {}
impl Visitor for Visitor2 {
type Ret = i32;
fn visit_a(&self, _a: &A) -> i32 {
123
}
fn visit_b(&self, _b: &B) -> i32 {
456
}
}
fn main() {
let a = A {
value: "HELLO".to_string(),
b: B { value: 32 },
};
let v1 = Visitor1 {};
let s: String = a.accept(&v1);
println!("{}", s);
let v2 = Visitor2 {};
let v: i32 = a.accept(&v2);
println!("{}", v);
}
visitor1.visit_a(): HELLO visitor1.visit_b(): 32
123
We can make this a little more convenient and make the actual type a generic of A. In contrast to a dyn Visited, this allows Rust to resolve its exact type at compile time, making it possible to compile it.
trait Visited {
fn accept<V: Visitor>(&self, v: &V) -> V::Ret;
}
trait Visitor {
type Ret;
fn visit_a<T: Visited>(&self, a: &A<T>) -> Self::Ret;
fn visit_b(&self, b: &B) -> Self::Ret;
}
// ---- A ----
struct A<T> {
value: String,
b: T,
}
impl<T: Visited> Visited for A<T> {
fn accept<V: Visitor>(&self, v: &V) -> V::Ret {
v.visit_a(self)
}
}
// ---- B ----
struct B {
value: i32,
}
impl Visited for B {
fn accept<V: Visitor>(&self, v: &V) -> V::Ret {
v.visit_b(self)
}
}
struct Visitor1 {}
impl Visitor for Visitor1 {
type Ret = String;
fn visit_a<T: Visited>(&self, a: &A<T>) -> String {
let b = a.b.accept(self);
format!("visitor1.visit_a(): {} {}", a.value, b)
}
fn visit_b(&self, b: &B) -> String {
format!("visitor1.visit_b(): {}", b.value)
}
}
struct Visitor2 {}
impl Visitor for Visitor2 {
type Ret = i32;
fn visit_a<T: Visited>(&self, _a: &A<T>) -> i32 {
123
}
fn visit_b(&self, _b: &B) -> i32 {
456
}
}
fn main() {
let a = A {
value: "HELLO".to_string(),
b: B { value: 32 },
};
let v1 = Visitor1 {};
let s: String = a.accept(&v1);
println!("{}", s);
let v2 = Visitor2 {};
let v: i32 = a.accept(&v2);
println!("{}", v);
}
visitor1.visit_a(): HELLO visitor1.visit_b(): 32
123

Automatic error conversion using the '?' operator for custom types

I'm struggling to understand the nuances of the ? operator. Take the following code:
link to playground
use std::{error::Error as StdError, fmt};
#[derive(Debug)]
struct MyError(Box<dyn StdError>);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for MyError{}
impl From<Box<dyn StdError>> for MyError {
fn from(err: Box<dyn StdError>) -> Self {
MyError(err)
}
}
#[derive(Debug)]
struct RandomErr(String);
impl fmt::Display for RandomErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for RandomErr{}
fn no_custom() -> Result<(), Box<dyn StdError>> {
Err(RandomErr("hello there".to_owned()))?
}
// This fails to compile
fn custom() -> Result<(), MyError> {
Err(RandomErr("hello there".to_owned()))?
}
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
Nope. There is no transitivity in From (or any trait, as far as I know). Rustc generally does what you tell it and no more to avoid problems like combinatory explosions in trait resolution.
So that C: From<B> and B: From<A> does not imply / translate to C: From<A>, you can write that reduced case and will hit E0277 (trait not satisfied):
struct A;
struct B;
struct C;
impl From<A> for B {
fn from(a: A) -> Self { B }
}
impl From<B> for C {
fn from(b: B) -> Self { C }
}
fn main() {
let _: C = From::from(A);
}

Multiple implementations for the same trait of the same type in Rust

With Rust traits, I can express a Monoid type class (forgive me for the naming of the methods):
trait Monoid {
fn append(self, other: Self) -> Self;
fn neutral() -> Self;
}
Then, I can also implement the trait for strings or integers:
impl Monoid for i32 {
fn append(self, other: i32) -> i32 {
self + other
}
fn neutral() -> Self { 0 }
}
However, how could I now add another implementation on i32 for the multiplication case?
impl Monoid for i32 {
fn append(self, other: i32) -> i32 {
self * other
}
fn neutral() { 1 }
}
I tried something like what is done in functional but that solution seems to rely on having an additional type parameter on the trait instead of using Self for the elements, which gives me a warning.
The preferred solution would be using marker traits for the operations - something I also tried but didn't succeed in.
The answer, as pointed out by #rodrigo, is to use marker structs.
The following example shows a working snippet: playground
trait Op {}
struct Add;
struct Mul;
impl Op for Add {}
impl Op for Mul {}
trait Monoid<T: Op>: Copy {
fn append(self, other: Self) -> Self;
fn neutral() -> Self;
}
impl Monoid<Add> for i32 {
fn append(self, other: i32) -> i32 {
self + other
}
fn neutral() -> Self {
0
}
}
impl Monoid<Mul> for i32 {
fn append(self, other: i32) -> i32 {
self * other
}
fn neutral() -> Self {
1
}
}
pub enum List<T> {
Nil,
Cons(T, Box<List<T>>),
}
fn combine<O: Op, T: Monoid<O>>(l: &List<T>) -> T {
match l {
List::Nil => <T as Monoid<O>>::neutral(),
List::Cons(h, t) => h.append(combine(&*t)),
}
}
fn main() {
let list = List::Cons(
5,
Box::new(List::Cons(
2,
Box::new(List::Cons(
4,
Box::new(List::Cons(
5,
Box::new(List::Cons(-1, Box::new(List::Cons(8, Box::new(List::Nil))))),
)),
)),
)),
);
println!("{}", combine::<Add, _>(&list));
println!("{}", combine::<Mul, _>(&list))
}

Supertrait only when Self : Sized

Lets suppose I have a trait
trait A {
fn new() -> Self where Self : Sized;
fn foo(&self) -> i32;
}
struct B {
data : i32
}
impl A for B {
fn new() -> Self {
B {data : 42}
}
fn foo(&self) -> i32 {
self.data
}
}
Now I can use Box<dyn A>, I just do not have the new() method available.
And when I have a generic T : A, I can do T::new(). So I can use A as a trait object (without the functions which would prevent this) and I can use it in a templated code and use all functions on it.
My question is, is it possible to get this behavior when having for example Clone as supertrait?
In the dyn A case A does not implement Clone. In the generic case is does.
You can do like that:
trait A {
fn new() -> Self where Self : Sized;
fn foo(&self) -> i32;
}
#[derive(Clone)]
struct B {
data : i32
}
impl A for B {
fn new() -> Self {
B {data : 42}
}
fn foo(&self) -> i32 {
self.data
}
}
fn make_clone<T: Clone + A>(toc: &T) -> T {
dbg!(toc.foo());
toc.clone()
}
fn main() {
let b = B{data: 0};
make_clone(&b);
}
so you can access A method and theClone supertrait from make_clone, you can obviously do the same thing with a supertrait instead of a generic method

Resources