Function overloading trick - compiler cannot choose which function to call - rust

Rust has no function overloading: you cannot define multiple functions with the same name but with different arguments.
However, I discovered the following trick which makes it look like there is function overloading. Notice how in main() I can call example.apply(...) with different types:
struct Example;
trait Apply<T, R> {
fn apply(&self, value: T) -> R;
}
impl Apply<i32, i32> for Example {
fn apply(&self, value: i32) -> i32 {
value * 2
}
}
impl Apply<&str, String> for Example {
fn apply(&self, value: &str) -> String {
format!("Hello, {}", value)
}
}
fn main() {
let example = Example;
// Looks like function overloading!
let one = example.apply(12);
let two = example.apply("World");
println!("{}", one);
println!("{}", two);
}
Now I would like to make two different versions of the Apply trait: one for values which are Copy and one for values which are not Copy:
struct Example;
struct NotCopy(i32);
// For types which are Copy
trait ApplyCopy<T: Copy, R> {
fn apply(&self, value: T) -> R;
}
// For types which are not Copy
trait ApplyRef<T, R> {
fn apply(&self, value: &T) -> R;
}
impl ApplyCopy<i32, i32> for Example {
fn apply(&self, value: i32) -> i32 {
value * 2
}
}
impl ApplyRef<NotCopy, String> for Example {
fn apply(&self, value: &NotCopy) -> String {
format!("NotCopy({})", value.0)
}
}
However, when I try to use this I get errors:
fn main() {
let example = Example;
let one = example.apply(12); // Error: multiple `apply` found
let two = example.apply(&NotCopy(34)); // Error: multiple `apply` found
println!("{}", one);
println!("{}", two);
}
One of the error messages:
error[E0034]: multiple applicable items in scope
--> src/main.rs:30:23
|
30 | let one = example.apply(12); // Error: multiple `apply` found
| ^^^^^ multiple `apply` found
|
note: candidate #1 is defined in an impl of the trait `ApplyCopy` for the type `Example`
--> src/main.rs:16:5
|
16 | fn apply(&self, value: i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `ApplyRef` for the type `Example`
--> src/main.rs:22:5
|
22 | fn apply(&self, value: &NotCopy) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #1
|
30 | let one = ApplyCopy::apply(&example, 12); // Error: multiple `apply` found
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #2
|
30 | let one = ApplyRef::apply(&example, 12); // Error: multiple `apply` found
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The compiler complains that it does not know which apply function to call. I expected it to be able to make a choice: an i32 is not a reference and is Copy, so the apply of trait ApplyCopy is the only one that can be called, and &NotCopy(34) is a reference and since NotCopy is not Copy, only the apply of ApplyRef can be called.
Is this a limitation of the Rust compiler or am I missing something?

Is this a limitation of the Rust compiler or am I missing something?
While there is compiler magic & special casing around them, at a fundamental level a reference is still a proper type, so any T could be an &Q under the covers, and reference types can implement traits.
While NotCopy is not Copy, &NotCopy is Copy. So &NotCopy matches both cases.

Related

How to wrap up functions using NodeIndex in petgraph

Newbie question: I want to use the petgraph rust crate. The graph should be a part of the struct MyGraph. For this, I need to wrap some functions to make them acessible from outside:
use petgraph::graph::DiGraph;
use petgraph::adj::NodeIndex;
#[derive(Default)]
struct MyNode {}
#[derive(Default)]
struct MyGraph {
g: DiGraph<MyNode,()>
}
impl MyGraph {
pub fn add_node(&mut self, node: MyNode) -> NodeIndex {
self.g.add_node(node) // does not compile: return value is u32 != NodeIndex
}
pub fn update_edge(&mut self, a: NodeIndex, b: NodeIndex) {
self.g.update_edge(a, b, ()); // does not compile: a: NodeIndex expected, got u32
}
}
fn main() {
let mut my_graph=MyGraph::default();
let node1=my_graph.add_node(MyNode::default());
let node2=my_graph.add_node(MyNode::default());
my_graph.update_edge(node1,node2);
}
The rust compiler however complains the an u32 is returned by the self.g.add_node() function, which is not the case if you call the function directly (and it's documented to return a NodeIndex). The smae problem applies to the self.g.update_edge() function. What would be the correct parameter type to use here???
A return type NodeIndex did not work as well. The (partial) compile error message:
...
error[E0308]: arguments to this function are incorrect
--> src\main.rs:17:16
|
17 | self.g.update_edge(a, b, ());
| ^^^^^^^^^^^
|
note: expected struct `NodeIndex`, found `u32`
--> src\main.rs:17:28
|
17 | self.g.update_edge(a, b, ());
| ^
= note: expected struct `NodeIndex`
found type `u32`
...
What I am doing wrong here?
You're importing petgraph::adj::NodeIndex, which is an alias for u32, but what you need to import is petgraph::graph::NodeIndex, which is a different struct.

How to pass reference of Into to another function?

I have a function that accepts a type Into<A>, how do you call into it, assuming I have a Vec of Into<A>?
Here is some sample code which fails to compile:
struct A {}
struct B {}
impl From<B> for A {
fn from(value: B) -> A {
A {}
}
}
impl From<&B> for A {
fn from(value: &B) -> A {
A {}
}
}
fn do_once<H: Into<A>>(item: H) {
println!("do_once");
}
fn do_many<J: Into<A>>(items: Vec<J>) {
let item = &items[0];
do_once(item);
// In the real code, we iterate here over all items.
}
Error:
error[E0277]: the trait bound `A: From<&J>` is not satisfied
--> src\main.rs:28:5
|
22 | fn do_once<H: Into<A>>(item: H) {
| ------- required by this bound in `do_once`
...
28 | do_once(item);
| ^^^^^^^ the trait `From<&J>` is not implemented for `A`
|
= note: required because of the requirements on the impl of `Into<A>` for `&J`
I think the problem is that I am passing an &Into<A>, not an Into<A>.
Is there any solution other than changing do_once to accept &H instead of H? In my real world case, I would like to avoid changing that API.
Yes, just move the trait bound so &J is Into<A> instead of J:
fn do_many<J>(items: Vec<J>)
where
for<'a> &'a J: Into<A>
{
let item = &items[0];
do_once(item);
// In the real code, we iterate here over all items.
}
Playground link

How to solve "expected struct, found type parameter" on assignment?

Just started working with Rust a couple of days ago. I'm porting some C++ code right now, and this question seems to be the reverse of the common "expected struct, got type" sort. This code involves two classes, a container class A and a client class B.
use std::vec::Vec;
struct A<T:FooTrait> {
children: Vec<*mut T>
}
impl <T:FooTrait> A<T> {
fn insert(&mut self, val: &mut T) -> Handle<T> {
self.children.push(val);
return Handle{owner: self};
}
}
struct B {
handle: Handle<B>
}
trait FooTrait {
fn set_handle<T:FooTrait>(&mut self, h: Handle<T>);
}
impl FooTrait for B {
fn set_handle<B:FooTrait>(&mut self, h: Handle<B>) {
self.handle = h; // <-- Here is the problem
}
}
struct Handle<T:FooTrait> {
owner: *mut A<T>
}
impl <T:FooTrait> Default for Handle<T> {
fn default()->Handle<T> {
Handle {
owner: std::ptr::null_mut()
}
}
}
fn main() {
let mut foo = A::<B> { children: Default::default() };
let mut b = B{handle: Default::default()};
b.handle = foo.insert(&mut b);
}
Getting the error:
error[E0308]: mismatched types
--> src/main.rs:23:23
|
22 | fn set_handle<B:FooTrait>(&mut self, h: Handle<B>) {
| - this type parameter
23 | self.handle = h;
| ^ expected struct `B`, found type parameter `B`
|
= note: expected struct `Handle<B>` (struct `B`)
found struct `Handle<B>` (type parameter `B`)
Simplified version (playground):
use std::marker::PhantomData;
struct B {
handle: PhantomData<B>,
}
trait FooTrait {
fn set_handle<T: FooTrait>(&mut self, h: PhantomData<T>);
}
impl FooTrait for B {
fn set_handle<BType: FooTrait>(&mut self, h: PhantomData<BType>) {
self.handle = h;
}
}
Note that I've changed the name of the type parameter in set_handle. Now the error is more clear:
error[E0308]: mismatched types
--> src/lib.rs:13:23
|
12 | fn set_handle<BType: FooTrait>(&mut self, h: PhantomData<BType>) {
| ----- this type parameter
13 | self.handle = h;
| ^ expected struct `B`, found type parameter `BType`
|
= note: expected struct `std::marker::PhantomData<B>`
found struct `std::marker::PhantomData<BType>`
In your case, the error is essentially the same, since the generic parameter is a new type, which shadowed the global struct B.
Now, what to do? It depends on what do you want to get.
If the struct B definition is correct and set_handle need to handle only Bs, just remove the generic parameter from set_handle (playground):
trait FooTrait {
fn set_handle(&mut self, h: PhantomData<B>);
}
impl FooTrait for B {
fn set_handle(&mut self, h: PhantomData<B>) {
self.handle = h;
}
}
If the struct B definition is correct, but set_handle must be able to use different handler types depending on Self, use an associated type (playground):
trait FooTrait {
type T: FooTrait;
fn set_handle(&mut self, h: PhantomData<Self::T>);
}
impl FooTrait for B {
type T = B;
fn set_handle(&mut self, h: PhantomData<B>) {
self.handle = h;
}
}
Now the implementation block will choose what kind of argument (handler, in your case) it will get.
If the set_handle definition is correct, i.e. the caller can choose the type of handler, then struct B must be generic, too. However, in this case you essentially can't use the trait-based approach, since the trait has to be generic too, and you will not be able to simply use it in any generic bound without providing parameters (which has to be bound too, ad infinitum).
There are two different B here. The original B you defined in struct B, and the second <B:FooTrait> type parameter. The second is shadowing the first. Here is how the compiler sees it:
impl FooTrait for B {
fn set_handle<AnyFoo:FooTrait>(&mut self, h: Handle<AnyFoo>) {
self.handle = h; // <-- Here is the problem
}
}
The way you've defined things, FooTrait::set_handle is supposed to work with any type that implements FooTrait, but the handle field of B can only store a Handle<B>. You need to rethink what you want FooTrait to do and how B satisfies it.

Pass a Struct<'a>::method as a `for<'a> Fn(&Foo<'a>)` for use in a closure

In my tests I had a helper function that runs a given method on differently configured objects, with a simplified version looking like this:
fn run_method<F>(f: F)
where
F: Fn(&Foo),
{
let to_test = vec![0i32];
to_test
.iter()
.map(|param| {
let foo = Foo(*param);
f(&foo);
})
.for_each(drop);
}
// run_method(Foo::run);
This worked fine until I added references to the tested struct, making it "lifetime-annotated" (for lack of a proper term, I mean Foo<'a>).
Now I get an error indicating, I think, that Rust doesn't want to accept a Foo::method as a function that can be used with any given lifetime (i.e. F: for<'a> Fn(&Foo<'a>)), as required by the closure:
error[E0631]: type mismatch in function arguments
--> src/main.rs:54:5
|
3 | fn run(&self) {
| ------------- found signature of `for<'r> fn(&'r Foo<'_>) -> _`
...
54 | run_method(Foo::run);
| ^^^^^^^^^^ expected signature of `for<'r, 's> fn(&'r Foo<'s>) -> _`
|
note: required by `run_method`
--> src/main.rs:44:1
|
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `for<'r, 's> <for<'t0> fn(&'t0 Foo<'_>) {Foo::<'_>::run} as std::ops::FnOnce<(&'r Foo<'s>,)>>::Output == ()`
--> src/main.rs:54:5
|
54 | run_method(Foo::run);
| ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `run_method`
--> src/main.rs:44:1
|
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I can work around the problem by avoiding closures (though I don't really understand how 'a gets constrained to be local to run_method - isn't the lifetime parameter supposed to be chosen by the caller?):
fn run_method<'a, F>(f: F)
where
F: Fn(&Foo<'a>),
{
let to_test = vec![&0i32];
for param in to_test {
let foo = Foo(param);
f(&foo);
}
}
Can I fix this without rewriting? If not - is there a reason why this shouldn't work?
Complete code:
struct Foo<'a>(&'a i32);
impl<'a> Foo<'a> {
fn run(&self) {
println!("Hello {}", self.0);
}
}
fn run_method<F>(f: F)
where
F: Fn(&Foo),
{
//same as F: for<'a> Fn(&Foo<'a>) {
let to_test = vec![0i32];
to_test
.iter()
.map(|param| {
let foo = Foo(param);
f(&foo);
})
.for_each(drop);
}
fn main() {
run_method(Foo::run);
}
// This works:
// fn run_method<'a, F>(f: F)
// where
// F: Fn(&Foo<'a>),
// {
// let to_test = vec![&0i32];
// for param in to_test {
// let foo = Foo(param);
// f(&foo);
// }
// }
// The lifetime-less version:
// struct Foo(i32);
// impl Foo {
// fn run(&self) {
// println!("Hello {}", self.0);
// }
// }
//
// fn run_parser_method<F>(f: F)
// where
// F: Fn(&Foo),
// {
// let to_test = vec![0i32];
// to_test
// .iter()
// .map(|param| {
// let foo = Foo(*param);
// f(&foo);
// })
// .for_each(drop);
// }
//
// fn main() {
// run_parser_method(Foo::run);
// }
playground
An overview of other questions about the same error code:
Expected bound lifetime parameter, found concrete lifetime is about mismatch between trait definition and implementation (trait { fn handle<'a>(); } vs impl<'a> { fn handle() {} })
Function references: expected bound lifetime parameter , found concrete lifetime [E0271] as well as Expected bound lifetime parameter, found concrete lifetime [E0271] is about a closure |args| {...} without explicit type annotations (|args: &[&str]|) not being accepted as a Fn(&[&str]) -> (); the answers don't explain why (the latter hints that it was not implemented in 2015)
Type mismatch "bound lifetime parameter" vs "concrete lifetime" when filling a collection from a closure is again about a closure without explicit type annotations specifying that it accepts a reference (let mut insert = |k| seq.insert(k); (1..10).cycle().take_while(insert)), which masks a more useful "borrowed data cannot be stored outside of its closure" error.
I can work around the problem by avoiding closures (though I don't really understand how 'a gets constrained to be local to run_method - isn't the lifetime parameter supposed to be chosen by the caller?)
It is. But when you rewrite it without closures, you have also put the reference inside the vec! invocation, so it is no longer constructed at runtime. Instead, the compiler can infer that to_test has type Vec<&'static i32>, and as 'static outlives any caller-chosen lifetime, there's no violation.
This fails to compile as you expect:
let to_test = vec![0i32];
for param in to_test.iter() {
let foo = Foo(param);
f(&foo);
}
is there a reason why this shouldn't work?
Yes, because the type of run is constrained by the type of Foo. More specifically, you have a lifetime decided by the caller (implicitly, in the type for Foo), so you have to construct a Foo of that lifetime to invoke the given run reference on it.
Can I fix this without rewriting?
That depends.
If all your test values are literals, you can make 'static references.
If you're able and willing to rewrite run, it's possible to make it unconstrained by the type of Foo
impl<'a> Foo<'a> {
fn run<'s>(_self: &Foo<'s>) {
println!("Hello {}", _self.0);
}
}
But then it doesn't need to go in an impl block at all.
I think the solution provided in the comments is your best bet, because given that you don't care about your concrete Foo<'a> type, there's no need to give the method reference for that type.

Is there a way to tell the compiler that nobody will implement a trait for a reference to a generic type?

Here is toy code that demonstrates the problem:
trait Foo {}
trait Boo<T> {
fn f() -> T;
}
impl<T> Boo<T> for i32
where
T: Foo,
{
fn f() -> T {
unimplemented!();
}
}
impl<'a, T> Boo<&'a T> for i32
where
T: Foo,
{
fn f() -> T {
unimplemented!();
}
}
I want to have two generic implementations of trait Boo, but it doesn't compile:
error[E0119]: conflicting implementations of trait `Boo<&_>` for type `i32`:
--> src/main.rs:16:1
|
7 | / impl<T> Boo<T> for i32
8 | | where
9 | | T: Foo,
10 | | {
... |
13 | | }
14 | | }
| |_- first implementation here
15 |
16 | / impl<'a, T> Boo<&'a T> for i32
17 | | where
18 | | T: Foo,
19 | | {
... |
22 | | }
23 | | }
| |_^ conflicting implementation for `i32`
|
= note: downstream crates may implement trait `Foo` for type `&_`
I do not plan to make this part of functionality to other crates. I tried:
moving this code to binary crate that obviously can not be used from other crates
moving this to a private mod
marking the trait as pub(crate)
all with no success.
Is there anyway to give the compiler a hint that it should not care that anybody will implement Foo for any reference?
Maybe my toy example is not the best, so here is the real code.
It's used for integration with the C part of my program, so it's a little
complicated.
impl<T: MyTrait> MyFrom<Option<T>> for *mut c_void {
fn my_from(x: Option<T>) -> Self {
match x {
Some(x) => <T>::alloc_heap_for(x),
None => ptr::null_mut(),
}
}
}
impl<'a, T: MyTrait> MyFrom<Option<&'a T>> for *mut c_void {
fn my_from(x: Option<&'a T>) -> Self {
match x {
Some(x) => x as *const T as *mut c_void,
None => ptr::null_mut(),
}
}
}
The conflict here doesn't have anything to do with the reference-ness of the latter implementation. The issue is that, in the first implementation, T can be any type, including reference types. Suppose you make the following function call:
let x: i32 = 10;
let result: &u8 = x.f();
At this point, the type resolver needs to figure out what function is being called. It finds a conflicting implementation:
impl Boo<&u8> for i32 via Boo<T> (T == &u8),
impl Boo<&u8> for i32 via Boo<&T> (T == u8),
You'd have exactly the same issue if you used a concrete type in the latter implementation:
// This will fail to compile
impl<T> Boo<T> for i32 { ... }
impl Boo<String> for i32 { ... }
This conflict means that the compiler can't allow these two implementations to coexist.
The specific thing you're looking to do here is called "specialization"; it refers to a proposal for a set of rules that says that overlapping implementations like this are allowed to exist if one of them is unambiguously more "specific" than the other, in which case the compiler will pick the more specific implementation. This is tracked as RFC #1210.

Resources