Why does BitAnd::bitand() not allow references? - rust

This code:
impl<I> BitAnd for BitSparseArray<I> where I: PrimInt + Unsigned + std::fmt::Debug {
type Output = Self;
fn bitand(&self, rhs: &Self) -> Self::Output {
assert_eq!(self.numbits, rhs.numbits);
...
}
}
fails to compile with:
error[E0053]: method `bitand` has an incompatible type for trait
--> src/lib.rs:44:5
|
44 | fn bitand(&self, rhs: &Self) -> Self::Output {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `BitSparseArray`, found reference
|
= note: expected fn pointer `fn(BitSparseArray<I>, BitSparseArray<I>) -> BitSparseArray<_>`
found fn pointer `fn(&BitSparseArray<I>, &BitSparseArray<I>) -> BitSparseArray<_>`
And a move operation would result without the reference, which means the user of this will lose the source structures to a move.
Why would there not be an option to do references here as well? Of course, I could use explicit functions to do what I want, but that would not be as cool of an approach!

Related

How to make trait method take &Self parameter

I'm trying to create a trait with some default method implementation. One of the methods has to take an instance of the same type and perform some computations.
Here is the simplistic example of what I'm trying to achieve:
struct A {
val: f32,
}
trait S {
fn val(&self) -> f32;
fn add(&self, other: &Self) -> f32 {
add(&self, other)
}
}
impl S for A {
fn val(&self) -> f32 {
self.val
}
}
fn add<T: S>(first: &T, second: &T) -> f32 {
first.val() + second.val()
}
This fails to compile with the error:
15 | | fn add(&self, other: &Self) -> f32 {
16 | | add(&self, other)
| | ^^^^^ expected `&Self`, found type parameter `Self`
17 | | }
I do not understand the error message, for other is of type &Self not Self, so why does compiler thinks otherwise?
If I change it to reference add(&self, &other) (which doesn't seem right, since other is already a reference type), I get another error:
|
16 | add(&self, &other)
| ^^^ the trait `S` is not implemented for `&Self`
...
26 | fn add<T: S>(first: &T, second: &T) -> f32 {
| - required by this bound in `add`
Is there a way to achieve this with default trait implementation, or this can work only with concrete types (like in this question: How do I implement the Add trait for a reference to a struct?)?
EDIT: If I call it like add(self, other), it tries to send the trait object, but I want to send the objects by reference. And really, I want to send concrete implementations and not trait objects.
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> src/main.rs:16:9
|
16 | add(self, other)
| ^^^ doesn't have a size known at compile-time
You're passing &self to add(), which makes it a double reference and the arguments to add() don't agree in types. The T of add is apparently determined by the first argument, which is why the compiler appears to expect the other argument to also have the &&Self parameter. (Read the note at the end of the error message.)
Call it with add(self, other) and it will compile. Note that you'll also need to opt out of the implicit Sized bound on add by adding + ?Sized.
// rest as in your code
trait S {
fn val(&self) -> f32;
fn add(&self, other: &Self) -> f32 {
add(self, other)
}
}
fn add<T: S + ?Sized>(first: &T, second: &T) -> f32 {
first.val() + second.val()
}
Playground

Why am I getting recursion when trying to implement trait for all reference types

I'm new to rust and having trouble implementing traits. Let me know if I'm going about this the wrong way. I'm trying to setup a trait with two functions for accessing a value. The get_value seems to function properly but when trying to setup the set_value with the &mut self reference, I'm getting the following error
warning: function cannot return without recursing
--> src\main.rs:7:5
|
7 | fn set_value(&mut self, new_value: bool) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
8 | (*self).set_value(new_value);
| ---------------------------- recursive call site
|
= note: `#[warn(unconditional_recursion)]` on by default
= help: a `loop` may express intention better if this is on purpose
warning: 1 warning emitted
Example code:
trait Trait1 {
fn set_value(&mut self, new_value: bool);
fn get_value(&self) -> bool;
}
impl<'a, T> Trait1 for &'a T where T: Trait1 {
fn set_value(&mut self, new_value: bool) {
(*self).set_value(new_value);
}
fn get_value(&self) -> bool {
(*self).get_value()
}
}
impl<'a, T> Trait1 for &'a mut T where T: Trait1 {
fn set_value(&mut self, new_value: bool) {
(**self).set_value(new_value)
}
fn get_value(&self) -> bool {
(**self).get_value()
}
}
struct Foo {
value: bool
}
impl Trait1 for Foo {
fn set_value(&mut self, new_value: bool) {
self.value = new_value;
}
fn get_value(&self) -> bool {
self.value
}
}
fn main() {
}
You're getting the recursion error, because you only deref self once, turning it into a &T -- the type you're currently trying to implement the trait for -- while you want to get at a T. You don't get that error if you deref it twice like you do in the impl for &mut T.
You'll get another error, though, namely that that implementation won't work. You can't just deref a shared reference and then borrow a mutable reference from the referent. *self is a &T. You can't get a &mut T from that no matter how much you deref it.

How to implement the Ord trait without getting the error "use of unstable library feature 'clamp'"?

I have a struct that I want to use it as a key in BTreeMap, so I implement PartialEq, Eq, PartialOrd and Ord. The last causes a problem as there is an unsafe clamp trait method.
I implement it this way:
use std::cmp::Ordering;
#[derive(Debug, Eq, Copy, Clone)]
struct Baz(usize);
impl PartialEq for Baz {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
fn ne(&self, other: &Self) -> bool {
self.0.ne(&other.0)
}
}
impl PartialOrd for Baz {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
fn lt(&self, other: &Self) -> bool {
self.0.lt(&other.0)
}
fn le(&self, other: &Self) -> bool {
self.0.le(&other.0)
}
fn gt(&self, other: &Self) -> bool {
self.0.gt(&other.0)
}
fn ge(&self, other: &Self) -> bool {
self.0.ge(&other.0)
}
}
impl Ord for Baz {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
fn max(self, other: Self) -> Self
where
Self: Sized,
{
Self(self.0.max(other.0))
}
fn min(self, other: Self) -> Self
where
Self: Sized,
{
Self(self.0.min(other.0))
}
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
{
Self(self.0.clamp(min.0, max.0))
}
}
fn main() {
Baz(1);
}
Playground
As far as I know, clamp for integers is safe and should work just fine, but Rust gives me the error
error[E0658]: use of unstable library feature 'clamp'
--> src/main.rs:57:5
|
57 | / fn clamp(self, min: Self, max: Self) -> Self
58 | | where
59 | | Self: Sized,
60 | | {
61 | | Self(self.0.clamp(min.0, max.0))
62 | | }
| |_____^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44095
error[E0658]: use of unstable library feature 'clamp'
--> src/main.rs:61:21
|
61 | Self(self.0.clamp(min.0, max.0))
| ^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44095
How can I solve this? I'm using Rust 1.41.
As far as I know, clamp for integers is safe and should work just fine, but Rust gives me the error
That's because the Ord::clamp method is unstable — the compiler isn't lying to you. However, that's a method with a default implementation, so you don't need to implement it (and shouldn't, unless you can improve on the default implementation).
Helpfully, there's a section in the documentation for Ord titled How can I implement Ord? which describes exactly what you need to do:
Ord requires that the type also be PartialOrd and Eq (which requires PartialEq).
Then you must define an implementation for cmp(). You may find it useful to use cmp() on your type's fields.
Of special relevance is the fact that Ord can be derived:
This trait can be used with #[derive]. When derived on structs, it will produce a lexicographic ordering based on the top-to-bottom declaration order of the struct's members. When derived on enums, variants are ordered by their top-to-bottom declaration order.
Your entire code can likely be
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
struct Baz(usize);
See also:
How do I implement Ord for a struct?
Implementing Ord for a type is awkward?

Rust function which takes function with arg a function

I want to write a generic function count_calls which calls a function f which takes a function pointer (lambda) where count_calls counts how often function f called the given lambda function.
I struggle with the approach (Playground).
fn count_calls<S, F>(s: S, f: F) -> u32
where
S: Clone,
F: Sized + FnMut(Fn() -> S) -> (),
{
let mut counter: u32 = 0;
f(|| {
counter += 1;
s.clone()
});
counter
}
#[cfg(test)]
mod stackoverflow {
use super::*;
fn f(p: fn() -> i32) {
p();
p();
}
#[test]
fn test() {
let counts = count_calls(3, f);
assert_eq!(counts, 2);
}
}
Here I get the error:
error[E0277]: the size for values of type `(dyn std::ops::Fn() -> S + 'static)` cannot be known at compilation time
--> src/lib.rs:1:1
|
1 | / fn count_calls<S, F>(s: S, f: F) -> u32
2 | | where
3 | | S: Clone,
4 | | F: Sized + FnMut(Fn() -> S) -> (),
... |
12 | | counter
13 | | }
| |_^ doesn't have a size known at compile-time
|
= help: within `((dyn std::ops::Fn() -> S + 'static),)`, the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> S + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `((dyn std::ops::Fn() -> S + 'static),)`
= note: required by `std::ops::FnMut`
Does someone know how to fix this?
[Edit]
I think using Box<Fn()->S> might be a solution. But I would prefer a stack only solution, if possible.
The error "the size for values of type (dyn std::ops::Fn() -> S + 'static) cannot be known at compilation time" is caused by your trait bound for F:
F: Sized + FnMut(Fn() -> S) -> ()
This is equivalent to F: Sized + FnMut(dyn Fn() -> S). This means that the closure F would take a trait object (dyn Fn() -> S) by value. But trait objects are unsized and cannot be passed by value (yet).
One solution would be to pass the trait object by reference or in a Box. The answer by rodrigo explains and discusses these solutions.
Can we avoid trait objects and dynamic dispatch?
Not properly, I think.
Non solutions
One idea would be to add another type parameter to count_calls:
fn count_calls<S, F, G>(s: S, f: F) -> u32
where
S: Clone,
F: Sized + FnMut(G),
G: Fn() -> S,
However, this doesn't work:
error[E0308]: mismatched types
--> src/lib.rs:9:7
|
9 | f(|| {
| _______^
10 | | counter += 1;
11 | | s.clone()
12 | | });
| |_____^ expected type parameter, found closure
|
= note: expected type `G`
found type `[closure#src/lib.rs:9:7: 12:6 counter:_, s:_]`
The problem here is that type arguments of count_calls are chosen by the caller of count_calls. But we actually want G to always be the type of our own closure. So that doesn't work.
What we want is a generic closure (where we can choose it's type parameters). Something similar is possible, but restricted to lifetime parameters. It's called HRTBs and looks like F: for<'a> Fn(&'a u32). But it doesn't help here because we need a type parameter and for<T> doesn't exist (yet?).
Sub-optimal, nightly solution
One solution would be to not use a closure, but a type with a known name which implements FnMut. Sadly, you can't implement the Fn* traits for your own type on stable yet. On nightly, this works.
struct CallCounter<S> {
counter: u32,
s: S,
}
impl<S: Clone> FnOnce<()> for CallCounter<S> {
type Output = S;
extern "rust-call" fn call_once(self, _: ()) -> Self::Output {
// No point in incrementing the counter here
self.s
}
}
impl<S: Clone> FnMut<()> for CallCounter<S> {
extern "rust-call" fn call_mut(&mut self, _: ()) -> Self::Output {
self.counter += 1;
self.s.clone()
}
}
fn count_calls<S, F>(s: S, mut f: F) -> u32
where
S: Clone,
F: Sized + FnMut(&mut CallCounter<S>), // <----
{
let mut counter = CallCounter {
counter: 0,
s,
};
f(&mut counter); // <-------
counter.counter
}
Unfortunately, now you have this strange type in your public interface (which should be implementation detail).
Apart from that, I can't think of any real solution (only other super verbose solutions with plenty of disadvantages). The developments in the type system corner (in particular in regards to GATs and HKTs) could solve this properly in the future. However, I think there are still a few different features lacking; in particular, I don't think that GATs as proposed would already solve this.
So if this is a real life problem which needs to be solved right now, I would:
step back and rethink the problem in a bigger scope to maybe avoid this Rust limitation, or
just use dynamic dispatch.
This is the simplest code that I managed to get working (playground):
fn count_calls<S, F>(s: S, mut f: F) -> u32
where
S: Clone,
F: FnMut(&mut dyn FnMut() -> S) -> (),
{
let mut counter: u32 = 0;
f(&mut || {
counter += 1;
s.clone()
});
counter
}
#[cfg(test)]
mod stackoverflow {
use super::*;
fn f(p: &mut dyn FnMut() -> i32) {
p();
p();
}
#[test]
fn test() {
let counts = count_calls(3, f);
assert_eq!(counts, 2);
}
}
The key change is that the function argument for F is changed from Fn() -> S into &mut dyn FnMut() -> S. You need a reference because you are using dynamic dispatching. Also you need FnMut because you are capturing counter and changing it inside, and a Fn will not allow it.
Note that you cannot use Box<FnMut() -> S. It will not allow capturing a reference to counter because boxed functions must be 'static.
If you find that changing your Fn to FnMut is undesirable (because you are changing your public API) you could go back to F: FnMut(&mut dyn Fn() -> S) -> () by defining counter as a Cell<u32>:
fn count_calls<S, F>(s: S, mut f: F) -> u32
where
S: Clone,
F: FnMut(&dyn Fn() -> S) -> (),
{
let counter: Cell<u32> = Cell::new(0);
f(&|| {
counter.set(counter.get() + 1);
s.clone()
});
counter.into_inner()
}

Is there a way to implement a trait on top of another trait? [duplicate]

This question already has answers here:
I implemented a trait for another trait but cannot call methods from both traits
(3 answers)
Closed 5 years ago.
I am trying to create a base trait that will implement other operator traits (Add, Subtract, Multiply, Divide, etc...) for me.
This fails to compile, it looks like an issued with Sized, but even when Measurement is set to require Sized it does not work. Is this even possible?
use std::ops::Add;
#[derive(Copy, Clone, Debug)]
struct Unit {
value: f64,
}
impl Unit {
fn new(value: f64) -> Unit {
Unit { value: value }
}
}
trait Measurement: Sized {
fn get_value(&self) -> f64;
fn from_value(value: f64) -> Self;
}
impl Measurement for Unit {
fn get_value(&self) -> f64 {
self.value
}
fn from_value(value: f64) -> Self {
Unit::new(value)
}
}
// This explicit implementation works
/*
impl Add for Unit {
type Output = Unit;
fn add(self, rhs: Unit) -> Unit {
let a = self.get_value();
let b = rhs.get_value();
Unit::from_value(a + b)
}
}
*/
// This trait implementation does not
impl Add for Measurement {
type Output = Self;
fn add(self, rhs: Self) -> Self {
let a = self.get_value();
let b = rhs.get_value();
Self::from_value(a + b)
}
}
fn main() {
let a = Unit::new(1.5);
let b = Unit::new(2.0);
let c = a + b;
println!("{}", c.get_value());
}
(playground)
error[E0277]: the trait bound `Measurement + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:42:6
|
42 | impl Add for Measurement {
| ^^^ `Measurement + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Measurement + 'static`
error[E0038]: the trait `Measurement` cannot be made into an object
--> src/main.rs:42:6
|
42 | impl Add for Measurement {
| ^^^ the trait `Measurement` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
error[E0038]: the trait `Measurement` cannot be made into an object
--> src/main.rs:43:5
|
43 | type Output = Self;
| ^^^^^^^^^^^^^^^^^^^ the trait `Measurement` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
error[E0038]: the trait `Measurement` cannot be made into an object
--> src/main.rs:45:5
|
45 | fn add(self, rhs: Self) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Measurement` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
The issue is not with Sized. The syntax you're looking for is:
impl<T: Measurement> Add for T { ... }
instead of:
impl Add for Measurement { ... }
Because the right-hand side of the for must be an object, not a trait, however a type parameter constrained to a trait (i.e. a T required to be Measurement) is valid.
Now your code still won't compile. You will get the following:
error: type parameter T must be used as the type parameter for some
local type (e.g. MyStruct<T>); only traits defined in the current
crate can be implemented for a type parameter [E0210]
The issue here is of a totally different kind. I'm not sure it's related to the question any more but I'll still explain what's going on. When you write an impl for Add to any T which is Measurement, you open the possibility that a type would already implement Add on its own, and would also implement Measurement elsewhere. Imagine if you wanted to implement Measurement on u8 (which is silly but possible): which impl should Rust choose for Add? The original std impl or your Measurement impl? (in-depth discussion about this issue)
Right now Rust plainly forbids an impl if it is not at least 1) your own trait or 2) your own type (where "own" formally means, in the crate you're writing your impl). This is why you can write impl Add for Unit: because you own Unit.
The easiest solution would be to give up and implement Add independently for each type you're planning to make Unit. Say your crate defines Inches and Centimeter, each one would have its own Add impl. If the code is insultingly similar, and you feel you broke DRY, leverage macros. Here is how the std crate does it:
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Add for $t {
type Output = $t;
#[inline]
fn add(self, other: $t) -> $t { self + other }
}
forward_ref_binop! { impl Add, add for $t, $t }
)*)
}
You cannot implement a trait for a trait, you implement a trait only for types.
But you can implement a trait for a generic type that implement a certain traits (trait bounds).
Something like this:
impl<T : Measurement> Add<T> for T {
type Output = T;
fn add(self, rhs: Self) -> T {
let a = self.get_value();
let b = rhs.get_value();
T::from_value(a + b)
}
}
Unfortunately you can do this only for traits defined in your crate (its called coherence), so you cannot do that for the std Add trait because it's defined in the std crate, not in yours.
I think you might need to define some macros to do what you want to do.
Here's a working version with macros, as suggested:
use std::ops::Add;
#[derive(Copy, Clone, Debug)]
struct Unit {
value: f64,
}
impl Unit {
fn new(value: f64) -> Unit {
Unit { value: value }
}
}
trait Measurement: Sized {
fn get_value(&self) -> f64;
fn from_value(value: f64) -> Self;
}
impl Measurement for Unit {
fn get_value(&self) -> f64 {
self.value
}
fn from_value(value: f64) -> Self {
Unit::new(value)
}
}
macro_rules! add_impl {
($($t:ty)*) => ($(
impl Add for $t {
type Output = $t;
fn add(self, other: $t) -> $t {
let a = self.get_value();
let b = other.get_value();
let r = a + b;
Self::from_value(r)
}
}
)*)
}
add_impl! { Unit }
fn main() {
let a = Unit::new(1.5);
let b = Unit::new(2.0);
let c = a + b;
println!("{}", c.get_value());
}

Resources