1

I have the following simplified code:

use std::collections::BinaryHeap;
use std::rc::Rc;

struct JobId;
struct Coord;
struct TimeStep;

pub trait HasJob {
    fn id(&self) -> JobId;
    fn start(&self) -> Coord;
    fn end(&self) -> Coord;
    fn earliest_start(&self) -> TimeStep;
    fn latest_finish(&self) -> TimeStep;
}

type JobPtr = Rc<HasJob>;

// a concrete class that implements the above trait
// and other basic traits like Eq, Hash, Ord, etc
pub struct Job {}
// another class that implements the HasJob trait
pub struct JobPrime {}

fn main() {
    // this line raises a compiler error
    let heap: BinaryHeap<JobPtr> = BinaryHeap::with_capacity(10);
}

The basic idea is to use the (unique) ids for ordering.

The heap initialization causes the following error:

error[E0277]: the trait bound `HasJob: std::cmp::Ord` is not satisfied
  --> src/main.rs:24:36
   |
24 |     let heap: BinaryHeap<JobPtr> = BinaryHeap::with_capacity(10);
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `HasJob`
   |
   = note: required because of the requirements on the impl of `std::cmp::Ord` for `std::rc::Rc<HasJob>`
   = note: required by `<std::collections::BinaryHeap<T>>::with_capacity`

I've just started trying my hand at Rust and have an OOP/C++/Java background. The intention is to use the HasJob trait as an "interface" and use that to induce type erasure/dynamic dispatch w.r.t generic collections/containers - A common OOP pattern.

If I understand correctly, the generic parameter of BinaryHeap has the constraint that the concrete type passed to it needs to implement the Ord trait. Attempting to extend the original trait with required trait like so...

pub trait HasJob: Ord + /*others*/

... violates Rust's object safety guarantee and raises this compiler error:

error[E0038]: the trait `HasJob` cannot be made into an object
  --> src/main.rs:16:22
   |
16 |     type JobPtr = Rc<HasJob>;
   |                      ^^^^^^ the trait `HasJob` cannot be made into an object
   |
   = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses

How do I get around the above issue?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
shadeMe
  • 706
  • 1
  • 10
  • 30
  • You might wish to state whether the elements in the binary heap really need to be trait objects, and/or reference-counted. What concrete implementations of `HasJob` do you have? – E_net4 Mar 06 '18 at 19:03
  • 1
    How do you impose an ordering on `JobPtr`s, using only `id`, `start`, `end`, `earliest_start`, and `latest_finish`? – trent Mar 06 '18 at 19:05
  • Basically the same as [How to test for equality between trait objects](https://stackoverflow.com/q/25339603/155423) – Shepmaster Mar 06 '18 at 19:06
  • @E_net4 There is just one concrete impl. of HasJob and it merely returns the values of the corresponding fields. The example code I've posted above is just a toy example I've been using to understand how Rust works. The job objects are shared elsewhere, which is why I've used a ref-counted pointer. For what it's worth, using a regular reference causes the same errors. – shadeMe Mar 06 '18 at 19:16
  • You seem to have exposed an XY problem. :) With only one concrete implementation, you don't need to use trait objects. – E_net4 Mar 06 '18 at 19:18
  • @trentcl The code is largely a toy example, but the basic idea is to use the (unique) ids for ordering. – shadeMe Mar 06 '18 at 19:18
  • @E_net4 Indeed - I do realize that. The point of the exercise was, however, to write the code based on the assumption that there are multiple implementations. As I mentioned before, the code only serves to help me understand how the language works. – shadeMe Mar 06 '18 at 19:21
  • @Shepmaster Apologies, but I don't see how that post relates to my question. Could please clarify? – shadeMe Mar 06 '18 at 19:26
  • @shadeMe [Shepmaster's answer](https://stackoverflow.com/a/49138717/3650362) to the other post applied to your problem: [playground](https://play.rust-lang.org/?gist=f5d899182c7b65145f9de8020c22c4c8&version=stable). To compare `HasJob` trait objects, you have to implement `Ord` *for `HasJob`*, not just for a type that implements `HasJob` (because it isn't possible to compare different types even if they both implement `Ord`.) – trent Mar 06 '18 at 20:01
  • @trentcl Ah, I just noticed that he has added his own answer for trait objects. I didn't realize one could implement super traits for traits that way. Marked as duplicate, thanks! – shadeMe Mar 06 '18 at 20:40

0 Answers0