Adding two numbers without cloning both - rust

use std::ops::Add;
#[derive(Debug)]
pub struct Vec3<N>{
x: N,
y: N,
z: N
}
impl<N> Vec3<N>{
pub fn new(x: N, y: N , z: N) -> Vec3<N>{
Vec3{x:x,y:y,z:z}
}
}
impl<N : Clone + Add<Output=N>> Vec3<N>{
pub fn add(&mut self,v: &Vec3<N>){
self.x = self.x.clone() + v.x.clone();
self.y = self.y.clone() + v.y.clone();
self.z = self.z.clone() + v.z.clone();
}
}
impl<N: Add<Output=N>> Add for Vec3<N>{
type Output = Vec3<N>;
fn add(self, v: Vec3<N>) -> Vec3<N>{
Vec3{x: self.x + v.x
,y: self.y + v.y
,z: self.z + v.z}
}
}
This allows me to write.
mod vec3;
use vec3::*;
fn main() {
let mut v1 = Vec3::<f32>::new(1.0,2.0,3.0);
let v2 = Vec3::<f32>::new(1.0,2.0,3.0);
v1.add(&v2);
let v3 = v1 + v2;
println!("{:?}", v3);
}
This let v3 = v1 + v2; consumes v1 and v2. But that is probably not always wanted, so I added another add function with the signature pub fn add(&mut self,v: &Vec3<N>)
My problem is with this code snippet
impl<N : Clone + Add<Output=N>> Vec3<N>{
pub fn add(&mut self,v: &Vec3<N>){
self.x = self.x.clone() + v.x.clone();
self.y = self.y.clone() + v.y.clone();
self.z = self.z.clone() + v.z.clone();
}
}
I needed to clone the values of both vectors in order to avoid a move. But I really wanted to write it like this
self.x = self.x + v.x.clone(); or self.x += v.x.clone(); I don't see why I would have to clone both values.
How could this be done?

There appears to be no available way to overload "+=" operator. However, you can avoid using exclipt "clone" if you replace Clone trait with Copy (however, you can use them together if needed):
impl<N: Copy + Add<Output = N>> Vec3<N> {
pub fn add(&mut self, v: &Vec3<N>){
self.x = self.x + v.x;
self.y = self.y + v.y;
self.z = self.z + v.z;
}
}
Notice how you don't have to call "clone" at all!
This is a direct quote from Rust's documentation:
When should my type be Copy?
Generally speaking, if your type can implement Copy, it should. There's one important thing to consider though: if you think your type may not be able to implement Copy in the future, then it might be prudent to not implement Copy. This is because removing Copy is a breaking change: that second example would fail to compile if we made Foo non-Copy.
You can find more information about Copy trait here.

Seems not to be possible at the moment. The reason is a missing += operator overload.
But clone() on primitive types seems to be just a noop so it actually doesn't matter, I guess.

Related

Storing arbitrary function callables into a hashmap in Rust

I am coming from Python and learning Rust. I am trying to store arbitrary functions (or pointers to functions) in a hashmap. And retrieve the function by string key and execute it. Basically trying to convert this simple Python code into Rust.
def foo(x, y):
return x + y
def bar(x, y, z):
return x + y + z
if __name__ == '__main__':
dict = {}
dict['foo'] = foo
dict['bar'] = bar
print(dict["foo"](1,2))
Because of the difference in the number of arguments, Rust compiler doesn't accept this kind of code (I believe Rust needs to know exact size of the function in hashmap values, and it needs to be consistent across storing functions). So I am wondering if anyone has a correct way (or Rust way) to do this. I also tried with matching, but is failing with the same reason.
The closest I got in Rust was something like
fn foo(x: i32, y: i32) -> i32 {
x + y
}
fn bar(x: i32, y: i32, z: i32) -> i32 {
x + y + z
}
fn main() {
let mut dict: std::collections::HashMap<&str, fn(i32, i32) -> i32> = std::collections::HashMap::new();
dict.insert("foo", foo);
dict.insert("bar", bar);
println!("{}", (dict["foo"])(1, 2));
}
But this line dict.insert("bar", bar); isn't compiling because the function bar has 3 arguments instead of 2.
You can store Box<dyn Any>:
fn main() {
let mut dict: std::collections::HashMap<&str, Box<dyn std::any::Any>> =
std::collections::HashMap::new();
dict.insert("foo", Box::new(foo as fn(i32, i32) -> i32));
dict.insert("bar", Box::new(bar as fn(i32, i32, i32) -> i32));
let v = dict["foo"].downcast_ref::<fn(i32, i32) -> i32>().unwrap()(1, 2);
println!("{v}");
}
However, I'd recommend you to rethink your design. Needing so much dynamism is rare in Rust, and perhaps your Python knowledge is leading you in the wrong direction.

Mismatched types parameter error on rust generics

expected type parameter T, found type parameter A error display. I have written lifetime implementation code also but it stills doesn't solve the problem. What's wrong I am doing?
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: PartialOrd, A: PartialOrd>(x: T, y: A) -> T {
if x > y {
x
} else {
y
}
}
// fn main() {
// let x = 3;
// let y = 5.0;
// let max_value = max(&x, &y);
// println!("The maximum value is {}", max_value);
// }
// fn max<'a, T: PartialOrd + Copy, A: PartialOrd + Copy>(x: &'a T, y: &'a A) -> &'a T {
// if x > y {
// x
// } else {
// y
// }
// }
T and A do not have to be the same type, so you have two problems.
The first is that you constrain T and A to be PartialOrd, which is the same thing as PartialOrd<Self>. So your actual constraints are T: PartialOrd<T>, A: PartialOrd<A>. This means you can compare the order of T's to other T's and A's to other A's, but x > y compares a T to an A.
Instead, you need to constrain T: PartialOrd<A>. (This also fails, but because of the invocation in main() -- more on that later.)
Second, the function is declared to return T but the else block returns y, which is not a T. Rust is statically typed, so it expects the types to exactly match.
This could be fixed by requiring that A can be converted to T (that is, A: Into<T>) and then you can return y.into() from the else block.
So at this point, we have:
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: PartialOrd<A>, A: Into<T>>(x: T, y: A) -> T {
if x > y {
x
} else {
y.into()
}
}
But now you are left with more problems:
There are no types T and A satisfying T: PartialOrd<A> where T is an integer and A is a float, therefore you cannot call this function with 3 and 5.0 as you do in main().
Likewise, there's no implementation of Into<T> on A for an integer type T and a float type A.
x > y will move x and y, and then you cannot return them later. This is trivially fixed by constraining both T and A to be Copy.
The second issue could be fixed by having an enum that means "either T or A" and returning that instead. The either crate has such a type called Either, which we can use here as Either<T, A>:
use either::Either;
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: PartialOrd<A> + Copy, A: Copy>(x: T, y: A) -> Either<T, A> {
if x > y {
Either::Left(x)
} else {
Either::Right(y)
}
}
(The println! works because Either<T, A> implements Display when both T and A do.)
You are still left with the problem where there's no built-in ordering implementation between integers and floats.
A "hail mary" solution could be to require that T and A can both be converted to f64 and then convert x and y to f64 before comparing them:
use either::Either;
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: Copy + Into<f64>, A: Copy + Into<f64>>(x: T, y: A) -> Either<T, A> {
if x.into() > y.into() {
Either::Left(x)
} else {
Either::Right(y)
}
}
This is the first bit of code we have that actually compiles, and this might be good enough for your purposes. There are still some issues that remain, however:
i64 and u64 cannot be losslessy converted to f64, therefore they do not implement Into<f64>, and so if you change let x = 3; to let x = 3u64; (or 3i64) compilation will again fail.
f64 does not implement Ord because it's possible for there to be two f64 values x and y that are not equal but neither is greater than the other -- if either value is NaN, for example. This won't cause your program to crash, but it may produce an unexpected or incorrect result.
I suspect that this is a learning exercise, so hopefully this answer helps you understand what is wrong with the original code. I would not recommend a function like this in a real-world program; instead, it would be far better to convert both arguments to be of the same Ord-implementing type ahead of time and then you can use the built-in std::cmp::max function (or Ord::max).

Operator overloading with vectors: cannot add vector of complex numbers

I'm trying to implement the Add trait for a Vector type that I defined.
use std::ops::Add;
use num::traits::Float;
#[derive(PartialEq, Debug, Clone)]
pub struct Vector<T>(Vec<T>);
impl<T: Float> Add for Vector<T> {
type Output = Vector<T>;
fn add(self, w: Self) -> Self::Output {
let dim = self.0.len();
let mut t = vec![T::zero(); dim];
for i in 0..dim {
t[i] = self.0[i] + w.0[i];
}
Vector(t)
}
}
Adding vector of float values works fine.
let v = Vector(vec![1., 2., 3.]);
let w = Vector(vec![1., 2., 6.]);
let result = v + w;
println!("{:?}", result);
However, when I try to add a vector of complex numbers, it doesn't work. Also, the error is a little vague.
let x = Complex::new(1., 3.);
let y = Complex::new(9., -1.);
let z = Complex::new(0.32, 81.);
let v: Vector<Complex<f32>> = Vector(vec![x, y, z]);
// cannot add `vector::Vector<num::Complex<f32>>` to `vector::Vector<num::Complex<f32>>`rustc(E0369)
let result = v + v;
Am I missing something about the Add implementation? How would I enable the add operation for vector of complex numbers?
Link to code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c5d3b0314968fa261287a19be4ad9536
So, I think the reason my code doesn't work is because num::traits::Float is not the right type to use. The reason being is that it has too many methods.
To make it work, I defined a trait Num, which is "narrower" compared to Float.
pub trait Num: Add + Zero + Clone + Copy {}
impl<T> Num for T where T: Add + Zero + Clone + Copy {}
Then, use that trait instead of Float.
impl<T: Num> Add for Vector<T> {
type Output = Vector<T>;
fn add(self, w: Self) -> Self::Output {
let dim = self.0.len();
let mut t = vec![T::zero(); dim];
for i in 0..dim {
t[i] = self.0[i] + w.0[i];
}
Vector(t)
}
}
With the above change, adding vector of floats and complex numbers now works.
// Adding vector of floats works.
let v = Vector(vec![1., 2., 3.]);
let w = Vector(vec![1., 2., 6.]);
let result = v + w;
println!("{:?}", result);
let x = Complex::new(1., 3.);
let y = Complex::new(9., -1.);
let z = Complex::new(0.32, 81.);
let v: Vector<Complex<f32>> = Vector(vec![x, y, z]);
let w: Vector<Complex<f32>> = Vector(vec![x, y, z]);
// Adding vector of complex numbers also works!
let result = v + w;
println!("{:?}", result);
On the side note, I'm also implementing other traits (Sub, Div, Mul, etc.) and having a different issue, but that's another thing.
Link to playground
Thanks #RobinZigmond and #Dogbert!

Why do `x + y` and `*x + *y` give the same result when x and y are references? [duplicate]

This question already has an answer here:
Understanding (automatic?) Deref/coercion when adding references and values of numbers
(1 answer)
Closed 2 years ago.
I have to implement a function that adds two numbers:
fn add(x: &i32, y: &i32) -> i32 {
println!("x is: {}, y is {}", x, y);
println!("*x is: {}, *y is {}", *x, *y);
x + y
}
fn double(x: i32) -> i32 {
add(&x, &x)
}
fn main() {
assert_eq!(double(5), 10);
println!("Success!");
}
The output is:
x is: 5, y is 5
*x is: 5, *y is 5
Success!
Per my understanding, the add function should not be able to perform x+y as they both are addresses. Only *x + *y should work as it dereferences the addresses and provides the values stored there. However, both statements yield the same result. Why is that?
The Add trait (operator +) is implemented for &i32s as well as i32s. In fact, you can have any combination:
i32 + i32
i32 + &i32
&i32 + i32
&i32 + &i32
They all do the same thing, they are there for convenience.
See also:
Why do I need to dereference a variable when comparing it but not when doing arithmetic?
How could rust multiply &i32 with i32?
Why does &v[1] + &v[2] have the same result as v[1] + v[2] in Rust?
Understanding (automatic?) Deref/coercion when adding references and values of numbers

What is the right way to implement generic computation algorithms in Rust?

It is quite a nuisance to implement a generic computation algorithm in Rust. It feels like I am reinventing all the stuff not in the algorithm, but in the codomain of Church numerals.
For example, here's an implementation of factorial that works in Rust 1.7:
#![feature(zero_one)]
use std::num::{One, Zero};
use std::ops::{Sub, Mul};
use std::cmp::Eq;
fn fact<T>(n: T) -> T
where T: Clone + Eq + Zero + One + Mul<T, Output = T> + Sub<T, Output = T>
{
if n == T::zero() {
T::one()
} else {
fact(n.clone() - T::one()) * n
}
}
fn main() {
println!("{}", fact(10));
}
Is there any right way of doing this? Is there any discussion going on with it?
Probably factorial is not good example, let's try is_even:
fn is_even<T>(x: T) -> bool
where T: std::ops::Rem<Output = T> + std::ops::Add<T, Output=T> + std::num::One + std::num::Zero + std::cmp::PartialEq
{
let two = T::one() + T::one();
(x % two) == T::zero()
}
If you want a two stuff, you must reimplement two.
If I wanted to implement is_even I would obviously start by implementing is_divisible which is more generic:
#![feature(zero_one)]
use std::cmp;
use std::num;
use std::ops;
fn is_divisible<T>(x: T, by: T) -> bool
where T: ops::Rem<Output = T> + num::Zero + cmp::PartialEq
{
(x % by) == T::zero()
}
It seems easy enough.
However, is_even has even more constraints and this is getting a bit long, so let's follow DRY:
trait Arithmetic:
From<u8> +
cmp::PartialEq + cmp::Eq + cmp::PartialOrd + cmp::Ord +
ops::Add<Self, Output = Self> + ops::Sub<Self, Output = Self> +
ops::Mul<Self, Output = Self> + ops::Div<Self, Output = Self> + ops::Rem<Self, Output = Self> {}
impl<T> Arithmetic for T
where T: From<u8> +
cmp::PartialEq + cmp::Eq + cmp::PartialOrd + cmp::Ord +
ops::Add<T, Output = T> + ops::Sub<T, Output = T> +
ops::Mul<T, Output = T> + ops::Div<T, Output = T> + ops::Rem<T, Output = T>
{}
Alright, this trait should cover us. Mind that it's missing a ops::Neg bound because this bound is not implemented for unsigned traits; so if we need Neg we'll have to add it; but it's easy enough.
As for the issue about constants, well indeed working your way from zero upwards is insane. It's quite the reason why the Zero and One traits are still unstable.
The generic conversion traits are convert::From and convert::Into, and that is what one would use.
So let us reformulate is_divisible, and finally implement is_even:
fn is_divisible<T>(x: T, by: T) -> bool
where T: Arithmetic
{
(x % by) == 0.into()
}
fn is_even<T>(x: T) -> bool
where T: Arithmetic
{
is_divisible(x, 2.into())
}
And really, those two functions seem both perfectly clear whilst still being generic.
Full code here
Now, we might argue that creating this Arithmetic trait is a long-winded way of getting to is_even. It is. However:
if you only need is_even, obviously you care little if it takes 6 bounds; it's a one off
if you need multiple generic functions working on numerics, then the small cost of creating this trait and function are negligible in the grand scheme of things
In short, it works. And it's really not that onerous.

Resources