To what extent does rust compiler auto match generic constraint? - rust

Consider the following code for binary tree
#[derive(Debug)]
struct Binary_Tree_Node<T: PartialOrd + Clone> {
left: Binary_Tree<T>,
value: T,
right: Binary_Tree<T>
}
#[derive(Debug)]
struct Binary_Tree<T: PartialOrd + Clone> {
node: Option<Box<Binary_Tree_Node<T>>>
}
impl <T: PartialOrd + Clone>Binary_Tree<T> {
fn new(value_to_insert: T) -> Binary_Tree<T> {
Binary_Tree{node:
Some(
Box::new(
Binary_Tree_Node{
left: Binary_Tree{node: None},
value: value_to_insert,
right: Binary_Tree{node: None}
}
)
)
}
}
fn map<F, U>(&self, f: F) -> Option<U>
where F: FnOnce(&Binary_Tree_Node<T>) -> U {
self.node.as_ref().map(|node| f(&**node))
// equivalent
//self.node.as_ref().map(|node| f(node))
}
}
let mut test1 = Binary_Tree::new(10);
println!("{:#?}", test1.map(|node| node.value < 2));
This line confuses me
self.node.as_ref().map(|node| f(node))
as I expect rust to throw compiler error
self.node is of type Option<Box<Binary_Tree_Node<T>>>
self.node.as_ref() is of type Option<&Box<Binary_Tree_Node<T>>>
node in self.node.as_ref().map(|node| f(node)) is of type &Box<Binary_Tree_Node<T>>
&Box<Binary_Tree_Node<T>> is not equivalent to the generic constraint &Binary_Tree_Node<T>
The question is why both self.node.as_ref().map(|node| f(&**node)) and self.node.as_ref().map(|node| f(node)) work?

This is a "Deref coercion", see nomicon Coercions:
Coercion is allowed between the following types:
[...]
Deref coercion: Expression &x of type &T to &*x of type &U if T derefs to U (i.e. T: Deref<Target=U>)
Box<T> implements Deref<Target=T>, so &Box<T> coerces automatically to &T like you'd have written &*node.
(I'm not sure what the & in "Expression &x" part is for, because we don't have a & at coercion site and it still works - could be a typo or a bug)
Also works from &String to &str: Playground
fn foo<T>(_v: T) {}
fn main() {
{
let v: &Box<i32> = &Box::new(5i32);
foo::<&i32>(v);
foo::<&i32>(&*v);
}
{
let v: &String = &String::from("abc");
foo::<&str>(v);
foo::<&str>(&*v);
}
}

Related

Implementing Index/overloading the [] operator for a sparse vector

This is literally the same question as this C++ question, but in Rust.
Suppose I have a "sparse vector" type that stores filled entries in a map of some kind. Unfilled entries are some kind of default value, like 0.
use std::ops::{Index, IndexMut};
use std::collections::BTreeMap;
use num_traits::Float;
struct SparseVector<T: Float, const N: usize>(BTreeMap<usize, T>);
// Returning a ref is easy when a value is present.
impl<T: Float, const N: usize> IndexMut<usize> for SparseVector<T, N> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.0.entry(index).or_insert(T::zero())
}
}
// What to return when we hit the default?
impl<T: Float, const N: usize> Index<usize> for SparseVector<T, N> {
type Output = T;
fn index(&self, index: usize) -> &T {
match self.0.get(&index) {
Some(value) => t,
None => ???
}
}
}
To implement Index on this type, I need to return a &T. For filled entries, that's just a reference to the value. How do I return a ref to the default?
I obviously can't return a &0 for lifetime reasons.
I can't necessarily store the default in a const field of the struct impl. It might not come from a const function.
I'm trying to avoid storing the default value on every instance of the type. It's literally the same value, why must it be allocated on every instance, etc.
The C++ answer is to return an instance of a wrapper type that dereferences to a &T. But in Rust, a Deref<Target = &T> cannot be substituted for &T, as far as I know.
How can I implement Index (override the [] operator) on this type?
You cannot.
There were some discussions around extending the Index and Deref traits to support situations similar to that (https://github.com/rust-lang/rfcs/issues/997), but today you cannot.
This particular case is even more problematic because it requires GAT: the trait will have to be defined like:
pub trait IndexGat<I> {
type Output<'a>: Deref
where
Self: 'a;
fn index(&self, index: I) -> Self::Output<'_>;
}
impl<I, T: Index> IndexGat<I> for T {
type Output<'a> = &'a <Self as Index>::Output
where
Self: 'a;
fn index(&self, index: I) -> Self::Output<'_> { <Self as Index>::index(self, index) }
}
So you can implement it:
impl<T, const N: usize> IndexGat<usize> for SparseVector<T, N> {
type Output<'a> = Wrapper<'a, T>;
where
Self: 'a;
fn index(&self, index: usize) -> Self::Output<'_> { ... }
}
pub enum Wrapper<'a, T> {
Default(T),
Ref(&'a T),
}
impl<T> Deref for Wrapper<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Default(v) => v,
Self::Ref(v) => *v,
}
}
}
So it cannot be done until GATs are stabilized.
The best thing you can do is just to use a regular method get() (or at(), or whatever).

Lifetimes for generalizing trait implementation from &T to AsRef<T>

I have some problems generalizing a trait working for &str to other string types (e.g. Rc<str>, Box<str>,String).
First of all my example function should work for:
assert_eq!(count("ababbc", 'a'), 2); // already working
assert_eq!(count(Rc::from("ababbc"), 'a'), 2); // todo
assert_eq!(count("ababbc".to_string(), 'a'), 2); // todo
This is the working code, which makes the first test run:
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A, I>
where
I: Iterator<Item = A>,
A: Atom,
{
fn atoms(&self) -> I;
}
impl<'a> Atoms<char, std::str::Chars<'a>> for &'a str {
fn atoms(&self) -> std::str::Chars<'a> {
self.chars()
}
}
pub fn count<I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A>,
T: Atoms<A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
To make the next tests run, I changed the signature of count and Atoms in following way:
pub trait Atoms<'a, A, I>
where
I: Iterator<Item = A> + 'a,
A: Atom,
{
fn atoms<'b>(&'b self) -> I
where
'b: 'a;
}
impl<'a, S> Atoms<'a, char, std::str::Chars<'a>> for S
where
S: AsRef<str> + 'a,
{
fn atoms<'b>(&'b self) -> std::str::Chars<'b>
where
'b: 'a,
{
self.as_ref().chars()
}
}
but now the function count does not compile any more:
pub fn count<'a, I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A> + 'a,
T: Atoms<'a, A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
Playground-Link
The compiler error is: the parameter type 'T' may not live long enough ... consider adding an explicit lifetime bound...: 'T: 'a'. This is not completely understandable for me, so I tried to apply the help T: Atoms<'a, A, I> + 'a. Now the error is: 'pattern' does not live long enough ... 'pattern' dropped here while still borrowed.
Since the latter error also occurs without implementations of Atoms and by just replacing the function body by pattern.atoms();return 1; I suspect that the type signature of Atoms is not suitable for my purpose.
Has anybody a hint what could be wrong with the type signature of Atoms or count?
trait Atoms<'a, A, I> where I: Iterator<Item = A> + 'a ...
By writing this, you're requiring the iterator to outlive the lifetime 'a. Since 'a is part of the trait's generic parameters, it must be a lifetime that extends before you start using (implicitly) <String as Atoms<'a, char, std::str::Chars>>::atoms. This directly contradicts the idea of returning a new iterator object, since that object did not exist before the call to atoms().
Unfortunately, I'm not sure how to rewrite this so that it will work, without generic associated types (a feature not yet stabilized), but I hope that at least this explanation of the problem helps.
I hope I clarify at least some parts of the problem. After doing some internet research on HRTBs and GATs I come to the conclusion that my problem is hardly solvable with stable rust.
The main problem is that one cannot
have a trait with different lifetime signature than its implementations
keep lifetimes generic in a trait for later instantiation in the implementation
limit the upper bound of a results lifetime if it is owned
I tried several approaches to but most evolve to fail:
at compiling the implementation (because the implementations lifetimes conflict with those of the trait)
at compiling the caller of the trait because a compiling implementation limits the lifetimes in a way, that no object can satisfy them.
At last I found two solutions:
Implement the trait for references
the function atoms(self) does now expect Self and not &Self
Atoms<A,I> is implemented for &'a str and &'a S where S:AsRef<str>
This gives us control of the lifetimes of the self objects ('a) and strips the lifetime completely from the trait.
The disadvantage of this approach is that we have to pass references to our count function even for smart references.
Playground-Link
use std::fmt::Display;
use std::fmt::Debug;
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A, I>
where
I: Iterator<Item = A>,
A: Atom,
{
fn atoms(self) -> I;
}
impl<'a> Atoms<char, std::str::Chars<'a>> for &'a str {
fn atoms(self) -> std::str::Chars<'a> {
self.chars()
}
}
impl<'a, S> Atoms<char, std::str::Chars<'a>> for &'a S
where
S: AsRef<str>,
{
fn atoms(self) -> std::str::Chars<'a> {
self.as_ref().chars()
}
}
pub fn count<I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A>,
T: Atoms<A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
#[test]
fn test_example() {
assert_eq!(count("ababbc", 'a'), 2);
assert_eq!(count(&"ababbc".to_string(), 'a'), 2);
assert_eq!(count(&Rc::from("ababbc"), 'a'), 2);
}
}
Switch to Generic Associated Types (unstable)
reduce the generic type Atoms<A,I> to an type Atoms<A> with an generic associated type I<'a> (which is instantiable at implementations)
now the function count can refer to the lifetime of I like this fn atoms<'a>(&'a self) -> Self::I<'a>
and all implementations just have to define how the want to map the lifetime 'a to their own lifetime (for example to Chars<'a>)
In this case we have all lifetime constraints in the trait, the implementation can consider to map this lifetime or ignore it. The trait, the implementation and the call site are concise and do not require references or helper lifetimes.
The disadvantage of this solution is that it is unstable, I do not know whether this means that runtime failures would probably occur or that api could change (or both). You will have to activate #![feature(generic_associated_types)] to let it run.
Playground-Link
use std::{fmt::Display, str::Chars};
use std::{fmt::Debug, rc::Rc};
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A>
where
A: Atom,
{
type I<'a>: Iterator<Item = A>;
fn atoms<'a>(&'a self) -> Self::I<'a>;
}
impl Atoms<char> for str
{
type I<'a> = Chars<'a>;
fn atoms<'a>(&'a self) -> Chars<'a> {
self.chars()
}
}
impl <S> Atoms<char> for S
where
S: AsRef<str>,
{
type I<'a> = Chars<'a>;
fn atoms<'a>(&'a self) -> Chars<'a> {
self.as_ref().chars()
}
}
pub fn count<A, S>(pattern: S, item: A) -> usize
where
A: Atom,
S: Atoms<A>,
{
pattern.atoms().filter(|i| *i == item).count()
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
#[test]
fn test_example() {
assert_eq!(count("ababbc", 'a'), 2);
assert_eq!(count("ababbc".to_string(), 'a'), 2);
assert_eq!(count(Rc::from("ababbc"), 'a'), 2);
}
}

Strange behavior of HRTBs

I have this code:
use std::fmt::Debug;
struct S<A>
where
for<'a> A: Debug + 'a,
{
f: Box<Fn(A) -> i32>,
}
impl<A> S<A>
where
for<'a> A: Debug + 'a,
{
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A>
where
for<'a> A: Debug + 'a,
{
S::<A> { f }
}
fn helper() {
let x = create::<&i32>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
let x = helper();
}
It's failed to compile:
error[E0310]: the parameter type `A` may not live long enough
In code 2, I changed Fn(A) -> i32 to Fn(&A) -> i32, the code works.
...
f: Box<Fn(&A) -> i32>,
...
Since A is argument of Fn trait, it's a type that has Higher-Rank lifetime. It shouldn't be affected by the lifetime of struct S<A> .
But why can't code 1 be compiled?
How can I workaround it for borrow or non-borrow type A?
There is no easy way to make helper work in current Rust, even if you remove all the for<'a> A: Debug + 'a, bounds (which only further restricts what types A can be, whereas you want to allow more).
This is as simple as I can make your example:
struct S<A> {
f: Box<Fn(A) -> i32>,
}
impl<A> S<A> {
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A> {
S { f }
}
fn helper() {
let x = create(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
The reason it doesn't work is that A "comes from the outside", and Rust can't infer that you want for<'a> S<&'a A>, it can't even talk about such a type.
Note that if let arg = 333; is placed above let x, this example does compile (because it infers a reference to arg specifically, not a for<'a>).
The closest you can get today is with an associated type on a trait with a lifetime parameter, e.g.:
// Emulating `type Type<'a>` by moving `'a` to the trait.
trait Apply<'a> {
type Type;
}
struct Plain<T>(std::marker::PhantomData<T>);
impl<'a, T> Apply<'a> for Plain<T> {
type Type = T;
}
struct Ref<T: ?Sized>(std::marker::PhantomData<T>);
impl<'a, T: ?Sized + 'a> Apply<'a> for Ref<T> {
type Type = &'a T;
}
struct S<A: for<'a> Apply<'a>> {
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
}
impl<A: for<'a> Apply<'a>> S<A> {
fn call<'a>(&self, a: <A as Apply<'a>>::Type) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A: for<'a> Apply<'a>>(
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
) -> S<A> {
S { f }
}
fn helper() {
let x = create::<Ref<i32>>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
However, it turns out that this encoding hits https://github.com/rust-lang/rust/issues/52812, so it's not actually usable at the moment (and I'm not aware of an workaround).

How do I write a function that allows me to convert a type T into any Box<B> if Box<T> can be coerced into Box<B>?

I'm trying to write an extension trait that allows me to move any value of type T into any Box<B>, where Box<T> can be coerced into Box<B>. My first attempt is the following:
trait IntoBox<B: ?Sized> {
fn into_box(self) -> Box<B>;
}
impl<T, B: ?Sized> IntoBox<B> for T
where
Box<T>: Into<Box<B>>,
{
fn into_box(self) -> Box<B> {
Box::new(self).into()
}
}
fn main() {
// Ok
let _: Box<u32> = 42.into_box();
// Error: the trait bound `std::boxed::Box<std::fmt::Display>:
// std::convert::From<std::boxed::Box<&str>>` is not satisfied
let _: Box<std::fmt::Display> = "Hello World".into_box();
}
This code works for regular boxes, but not trait objects. I suspect Into is the wrong bound here. What should I use instead?
Edit: As explained in the answer to this question, this problem can be solved with respect to any number of concrete types T by providing a blanket impl for T: Unsize<U>. However this does not work in the generic case because the impls would be conflicting:
impl<T, B> IntoBox<B> for T
where
Box<T>: Into<Box<B>>,
{
fn into_box(self) -> Box<B> {
Box::new(self).into()
}
}
impl<T, B: ?Sized> IntoBox<B> for T
where
B: std::marker::Unsize<T>
{
fn into_box(self) -> Box<B> {
Box::new(self)
}
}

How do I alias the type of self in a struct method?

If I have a small struct Test:
struct Test<T> { a: T }
And I wish, in a method of Test to refer to its full type:
impl<T> Test<T> {
fn new(a: T) -> Test<T> {
type X = Test::<T>;
println!("{}", std::intrinsics::type_id::<X>());
Test { a: a }
}
}
This fails with expected ident, found <, and the following fail too:
type X = Test;: wrong number of type arguments: expected 1, found 0 [E0243]
type X = Test<T>;: can't use type parameters from outer function; try using a local type parameter instead with a note use of undeclared type name T
Actually, it makes sense that the former two are rejected; the latter however is slightly more mysterious.
This came about in trying to implement an offset_of! macro: offset_of($T:ty, $field:ident); the macro works rather well, however ty does not accept Test<T> (but accept a parameter-less alias).
Is there any way to either:
craft an alias to the type of self, even in generics?
or, alternatively, make it so that the macro accepts Test<T> as a "type" argument?
Note: I would prefer a solution to the former, if possible, as aliases are really handy.
For reference, here is the offset_of macro I crafted:
macro_rules! offset_of(
($T:ty, $field:ident) => {
unsafe {
let exemplar: $T = std::mem::uninitialized();
let base: *const u8 = std::mem::transmute(&exemplar);
let attr: *const u8 = std::mem::transmute(&exemplar.$field);
std::mem::forget(exemplar);
(attr as isize) - (base as isize)
}
}
);
I may be misunderstanding you, but there already is an alias for the type of self — Self:
#![feature(core)]
struct Test<T> { a: T }
impl<T> Test<T> {
fn new(a: T) -> Test<T>
where T: 'static
{
println!("{}", unsafe { std::intrinsics::type_id::<Self>() });
Test { a: a }
}
}
fn main() {}
I had to add the feature gates, make T 'static to satisfy type_id, and add an unsafe block. I hope that none of that seems suspicious. This seems to work with your alias, as well:
macro_rules! offset_of(
($T:ty, $field:ident) => {
unsafe {
let exemplar: $T = std::mem::uninitialized();
let base: *const u8 = std::mem::transmute(&exemplar);
let attr: *const u8 = std::mem::transmute(&exemplar.$field);
(attr as isize) - (base as isize)
}
}
);
struct Test<T> { a: T, b: T, c: T }
impl<T> Test<T> {
fn new(a: T) -> Test<T>
where T: Copy
{
println!("{}", offset_of!(Self, a));
println!("{}", offset_of!(Self, b));
println!("{}", offset_of!(Self, c));
Test { a: a, b: a, c: a }
}
}
fn main() {
Test::new(1u16);
}

Resources