Implementing the addition operator on a generic trait - rust

I have the following generic trait and struct:
pub trait Parameter<T> {
fn get(&self) -> T;
}
// Struct to add parameters of the same addable type.
pub struct ParameterAdd<T: Add> {
first_parameter: Box<dyn Parameter<T>>,
second_parameter: Box<dyn Parameter<T>>,
}
impl<T: Add<Output = T>> Parameter<T> for ParameterAdd<T> {
fn get(&self) -> T {
return self.first_parameter.get() + self.second_parameter.get();
}
}
I am trying to implement a public API for adding together 2 objects which implement the Parameter trait, such that calling get() on the sum returns the sum of the respective get() methods, what is the idiomatic way to go about this?

Implementing std::ops::Add as follows has given me my desired result.
impl<T: Add<Output = T>> Add for Box<dyn Parameter<T>> {
type Output = ParameterAdd<T>;
fn add(self, other: Self) -> ParameterAdd<T> {
ParameterAdd{
first_parameter: self,
second_parameter: other,
}
}
}
With this implementation, I can add together Parameter<T>s given that is addable.

Related

Make a generic trait that holds something that implements a separate trait?

I have a trait that makes sure whatever struct implements it holds specific data types so I can use those structs in any place where that trait is implemented,
trait HasShape{
fn ref_vertices(&self) -> &Vec<Vertex>;
fn ref_vbo(&self) -> &VertexBuffer<Vertex>;
// Goes on for the rest of the trait
}
trait Drawable
{
fn draw(&self, target: &Frame);
}
impl<T> Drawable for T
where T: HasShape
{
fn draw(&self, target: &Frame) {
let vertices = self.ref_vertices();
// Use the fields on type that are required by HasShape
}
}
And I have another trait that is similar however it needs to hold an object that implements HasShape as well as other fields
trait HasPos<T>
where
T: HasShape
{
fn ref_shape(&self) -> &T;
fn ref_pos(&self) -> &Vector2f32;
// Rest is the same style as HasShape
}
trait Manipulate<T>
where T: HasShape
{
fn translate(&self, x: f32, y: f32);
// Rest are similar functions that change the fields of HasPos
}
My question is, how do I implement HasShape for all types that have HasPos so I can use anything that implements HasPos in place of a HasShape object?
like this
impl<T: HasPos<T>> HasShape for T
where T: HasShape
{
fn ref_vertices(&self) -> &Vec<Vertex>{
self.ref_shape().ref_vertices()
}
// Every function in HasShape just gets the field from the object in HasPos
}
That way I can call functions from Drawable on any object that implements HasPos as well?
impl<T: HasPos<T>> HasShape for T
where T: HasShape
This doesn't make much sense; you are implementing HasShape for all types that already implement HasShape.
If I understand correctly, you want to auto-implement HasShape for all objects that already implement HasPos. If so, you actually have two generics; one for the object you want to implement HasShape for, and one for the nested type of HasPos.
The impl is a little weird with a generic that isn't actually part of the type, though, so you need to convert T of HasPos to an associated type, like so:
#![allow(unused_variables)]
use std::marker::PhantomData;
pub struct Frame;
pub struct Vertex;
pub struct VertexBuffer<B>(PhantomData<B>);
pub struct Vector2f32;
trait HasShape {
fn ref_vertices(&self) -> &Vec<Vertex>;
fn ref_vbo(&self) -> &VertexBuffer<Vertex>;
// Goes on for the rest of the trait
}
trait Drawable {
fn draw(&self, target: &Frame);
}
impl<T> Drawable for T
where
T: HasShape,
{
fn draw(&self, target: &Frame) {
let vertices = self.ref_vertices();
// Use the fields on type that are required by HasShape
}
}
trait HasPos {
type Shape: HasShape;
fn ref_shape(&self) -> &Self::Shape;
fn ref_pos(&self) -> &Vector2f32;
// Rest is the same style as HasShape
}
trait Manipulate<T>
where
T: HasShape,
{
fn translate(&self, x: f32, y: f32);
// Rest are similar functions that change the fields of HasPos
}
impl<T> HasShape for T
where
T: HasPos,
{
fn ref_vertices(&self) -> &Vec<Vertex> {
self.ref_shape().ref_vertices()
}
fn ref_vbo(&self) -> &VertexBuffer<Vertex> {
self.ref_shape().ref_vbo()
}
}
Note that there is one caveat, though: Now you can never manually implement HasShape and HasPos for the same type.
struct MyType;
impl HasPos for MyType {
type Shape = MyType;
fn ref_shape(&self) -> &Self::Shape {
todo!()
}
fn ref_pos(&self) -> &Vector2f32 {
todo!()
}
}
impl HasShape for MyType {
fn ref_vertices(&self) -> &Vec<Vertex> {
todo!()
}
fn ref_vbo(&self) -> &VertexBuffer<Vertex> {
todo!()
}
}
error[E0119]: conflicting implementations of trait `HasShape` for type `MyType`
--> src/lib.rs:73:1
|
46 | impl<T> HasShape for T
| ---------------------- first implementation here
...
73 | impl HasShape for MyType {
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyType`
This also means that no HasShape can have itself as its HasPos type, because this will create an infinite recursion:
struct MyType;
impl HasPos for MyType {
type Shape = MyType;
fn ref_shape(&self) -> &Self::Shape {
&self
}
fn ref_pos(&self) -> &Vector2f32 {
todo!()
}
}
fn main() {
let x = MyType;
x.ref_vertices();
}
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Aborted

Implement methods for trait without additional traits

Looking for "blanket" implementation of the method(s) for trait.
Let's say for a trait
pub trait A {
fn do_a(&self);
}
want to have boxed method that wraps with box, without introducing any additional traits:
fn boxed(self) -> Box<Self>;
I can have another trait to achieve that (playground)
pub trait A {
fn do_a(&self);
}
pub trait Boxed {
fn boxed(self) -> Box<Self>;
}
impl<T> Boxed for T
where
T: A,
{
fn boxed(self) -> Box<Self> {
Box::new(self)
}
}
However, new trait Boxed is required for that.
You can add boxed directly to A with a default implementation so that structs won't need to implement it themselves:
trait A {
fn do_a(&self);
fn boxed (self) -> Box<Self>
where Self: Sized
{
Box::new (self)
}
}
struct Foo{}
impl A for Foo {
fn do_a (&self) {
todo!();
}
// No need to redefine `boxed` here
}
fn main() {
let foo = Foo{};
let _object: Box<dyn A> = foo.boxed();
}
Playground

Is it possible to use `impl Trait` as a function's return type in a trait definition?

Is it at all possible to define functions inside of traits as having impl Trait return types? I want to create a trait that can be implemented by multiple structs so that the new() functions of all of them returns an object that they can all be used in the same way without having to write code specific to each one.
trait A {
fn new() -> impl A;
}
However, I get the following error:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/lib.rs:2:17
|
2 | fn new() -> impl A;
| ^^^^^^
Is this a limitation of the current implementation of impl Trait or am I using it wrong?
As trentcl mentions, you cannot currently place impl Trait in the return position of a trait method.
From RFC 1522:
impl Trait may only be written within the return type of a freestanding or inherent-impl function, not in trait definitions or any non-return type position. They may also not appear in the return type of closure traits or function pointers, unless these are themselves part of a legal return type.
Eventually, we will want to allow the feature to be used within traits [...]
For now, you must use a boxed trait object:
trait A {
fn new() -> Box<dyn A>;
}
See also:
Is it possible to have a constructor function in a trait?
Why can a trait not construct itself?
How do I return an instance of a trait from a method?
Nightly only
If you wish to use unstable nightly features, you can use existential types (RFC 2071):
// 1.67.0-nightly (2022-11-13 e631891f7ad40eac3ef5)
#![feature(type_alias_impl_trait)]
#![feature(return_position_impl_trait_in_trait)]
trait FromTheFuture {
type Iter: Iterator<Item = u8>;
fn returns_associated_type(&self) -> Self::Iter;
// Needs `return_position_impl_trait_in_trait`
fn returns_impl_trait(&self) -> impl Iterator<Item = u16>;
}
impl FromTheFuture for u8 {
// Needs `type_alias_impl_trait`
type Iter = impl Iterator<Item = u8>;
fn returns_associated_type(&self) -> Self::Iter {
std::iter::repeat(*self).take(*self as usize)
}
fn returns_impl_trait(&self) -> impl Iterator<Item = u16> {
Some((*self).into()).into_iter()
}
}
fn main() {
for v in 7.returns_associated_type() {
println!("type_alias_impl_trait: {v}");
}
for v in 7.returns_impl_trait() {
println!("return_position_impl_trait_in_trait: {v}");
}
}
If you only need to return the specific type for which the trait is currently being implemented, you may be looking for Self.
trait A {
fn new() -> Self;
}
For example, this will compile:
trait A {
fn new() -> Self;
}
struct Person;
impl A for Person {
fn new() -> Person {
Person
}
}
Or, a fuller example, demonstrating using the trait:
trait A {
fn new<S: Into<String>>(name: S) -> Self;
fn get_name(&self) -> String;
}
struct Person {
name: String
}
impl A for Person {
fn new<S: Into<String>>(name: S) -> Person {
Person { name: name.into() }
}
fn get_name(&self) -> String {
self.name.clone()
}
}
struct Pet {
name: String
}
impl A for Pet {
fn new<S: Into<String>>(name: S) -> Pet {
Pet { name: name.into() }
}
fn get_name(&self) -> String {
self.name.clone()
}
}
fn main() {
let person = Person::new("Simon");
let pet = Pet::new("Buddy");
println!("{}'s pets name is {}", get_name(&person), get_name(&pet));
}
fn get_name<T: A>(a: &T) -> String {
a.get_name()
}
Playground
As a side note.. I have used String here in favor of &str references.. to reduce the need for explicit lifetimes and potentially a loss of focus on the question at hand. I believe it's generally the convention to return a &str reference when borrowing the content and that seems appropriate here.. however I didn't want to distract from the actual example too much.
You can get something similar even in the case where it's not returning Self by using an associated type and explicitly naming the return type:
trait B {}
struct C;
impl B for C {}
trait A {
type FReturn: B;
fn f() -> Self::FReturn;
}
struct Person;
impl A for Person {
type FReturn = C;
fn f() -> C {
C
}
}
Fairly new to Rust, so may need checking.
You could parametrise over the return type. This has limits, but they're less restrictive than simply returning Self.
trait A<T> where T: A<T> {
fn new() -> T;
}
// return a Self type
struct St1;
impl A<St1> for St1 {
fn new() -> St1 { St1 }
}
// return a different type
struct St2;
impl A<St1> for St2 {
fn new() -> St1 { St1 }
}
// won't compile as u32 doesn't implement A<u32>
struct St3;
impl A<u32> for St3 {
fn new() -> u32 { 0 }
}
The limit in this case is that you can only return a type T that implements A<T>. Here, St1 implements A<St1>, so it's OK for St2 to impl A<St2>. However, it wouldn't work with, for example,
impl A<St1> for St2 ...
impl A<St2> for St1 ...
For that you'd need to restrict the types further, with e.g.
trait A<T, U> where U: A<T, U>, T: A<U, T> {
fn new() -> T;
}
but I'm struggling to get my head round this last one.

Alias generic trait with default types

I have a trait that is generic: trait Trait<T> and I want to create another trait that specifies the generics: type Alias = Trait<String>. This would allow impl Alias for T and not have to specify the type parameters. I tried a couple ways of doing this and haven't found any that works.
This is not a duplicate of Type alias for multiple traits or Aliasing trait with associated types because doing trait Alias: Trait<T> requires people to implement Trait<T> anyway. I want to offer a trait that hides the generics.
A clearer code sample:
trait DefaultEvents = Events<UserStruct, ChannelStruct, IrcStruct>;
struct MyHandler;
impl DefaultEvents for MyHandler {
...
}
Here's my best suggestion, it's going to mean a bit more work on your part (with lots of manual trait inheritance), but it should achieve the user convenience that you want.
pub mod user_friendly {
pub trait GivesNum<T> {
fn get_num(&self) -> T;
}
pub trait GivesDouble {
fn get_double(&self) -> f64;
}
impl<S> GivesNum<f64> for S where S: GivesDouble {
fn get_num(&self) -> f64 { self.get_double() }
}
}
// now your library's user needs to do less
use user_friendly::*;
struct MyStruct { num: f64 }
impl GivesDouble for MyStruct {
fn get_double(&self) -> f64 { 2.0 * self.num }
}
fn main() {
let s = MyStruct{ num: 5.0 };
println!("MyStruct.get_num() = {}", s.get_num());
}
Try it on Rust Playground

Enforce Eq check on trait

Suppose the following objects:
pub struct MyStruct<T>{
items: Vec<T>
}
pub impl<T> MyStruct<T> {
pub fn new() -> MyStruct {
MyStruct{ items::new(); }
}
pub fn add(&mut self, item: T) where T : Eq {
self.items.push(item);
}
}
pub trait C {}
pub struct Another {
mystruct: MyStruct<Box<C>>
}
pub impl Another {
pub fn exec<C>(&mut self, c: C) where C: Eq + C {
self.mystruct.add(c);
}
}
On exec I'm enforcing that C also is Eq, but I'm receiving the following error:
error: the trait `core::cmp::Eq` is not implemented for the type `C`
I had to make
pub impl<T> MyStruct<T>
instead of
pub impl<T : Eq> MyStruct<T>
because since C is a trait I cant enforce Eq when using MyStruct::new, so I left the check for the type guard on the function. What's happening here?
Let’s look at the relevant definitions for Eq:
pub trait Eq: PartialEq<Self> {
…
}
pub trait PartialEq<Rhs: ?Sized = Self> {
fn eq(&self, other: &Rhs) -> bool;
…
}
Now consider MyStruct<Box<C>>: the type that it wants to implement Eq is Box<C>, a boxed trait object. To implement Eq, Box<C> must first implement PartialEq<Box<C>>, like this:
impl PartialEq for Box<C> {
fn eq(&self, other: &Box<C>) -> bool;
}
impl Eq for Box<C> { }
That is, you must be able to compare an arbitrary Box<C> with any other arbitrary Box<C>. The boxed trait objects that you are comparing could be of different concrete types, here. Thus you need to write this implementation manually. In such cases, you will typically want the trait to include some way of normalising the form of the object into a concrete, comparable type; for some types this is obvious; if AsRef<T> was to have a PartialEq implementation added, the implementation to add would be fairly obvious:
impl<T: PartialEq> PartialEq for AsRef<T> {
fn eq(&self, other: &AsRef<T>) -> bool {
self.as_ref() == other.as_ref()
}
}
(Note also that if C implements PartialEq, Box<C> does, so such implementations as we’re discussing should go on the unboxed trait object, not on the boxed trait object.)
Quite often, however, there is not an obvious and simple implementation. There are a few approaches you could take:
Convert the objects (potentially expensively, though ideally cheaply) into some base type, e.g. a String which can then be compared;
Give up;
Constrain C to 'static types and use some fancy Any magic to make it so that it uses the base type’s PartialEq implementation, returning false if the two trait objects are not of the same concrete type. This one is a fairly useful one, so I’ll give some code for it:
#![feature(core)]
use std::any::{Any, TypeId};
use std::mem;
fn main() { }
trait PartialEqFromC {
fn eq_c(&self, other: &C) -> bool;
}
impl<T: PartialEq + Any + C> PartialEqFromC for T {
fn eq_c(&self, other: &C) -> bool {
if other.get_type_id() == TypeId::of::<Self>() {
self == unsafe { *mem::transmute::<&&C, &&Self>(&other) }
} else {
false
}
}
}
trait C: Any + PartialEqFromC {
}
impl PartialEq for C {
fn eq(&self, other: &C) -> bool {
self.eq_c(other)
}
}
Note that this example depends on the unstable feature core for Any.get_type_id and is thus tied to nightly only; this can be worked around by duplicating that definition from the Any trait into a new supertrait of C and could also be simplified by mopafying the C trait.

Resources