User-provided virtual overload equivalent in Rust


#1

Suppose a C++ library exposes a class like this:

struct Foo
{
  // data members...
  virtual void foo(int x) = 0;
  // other functions...
}

A user of said library would subclass Foo, implement foo() and use that. How could a similar thing be best done in Rust? Please keep in mind that the Foo class might contain non-virtual functions too as well as data members, PIMPL implementation, etc…


#2

Rust is centered around composition instead of inheritance, so there is not real Rust version of that pattern. You will have to chose a more problem specific solution instead. I remember that I had about the same problems when I started with Rust, but I had to let go of the inheritance based thought model, because it will simply not work well. There are, on the other hand, some talk about supporting virtual structs in the future, so it may be possible in some future 1.x version of Rust.

What you can do now is, for example, replacing Foo with one or more traits if it doesn’t have to directly access stored data in its predefined methods. You can also add more “virtual” methods for data access, but they will be public if the trait is public. You can embed Foo in the child struct and make it available through Deref or some other way.

There are other patterns, but this is what I can come up with off the top of my head.


#3

Hmm, okay, you’re probably right about more problem-specific soluion.
In the actual situation, Foo is a thing that sometimes needs to write data into a stream (a special kind of stream, doesn’t matter). So maybe I could instead make Foo accept an object implementing the std::io::Write trait … would that be considered a more Rust-style design?


#4

I guess it would. You could also make your own special write trait. It’s hard to say without more knowledge of the problem, but you can always try a number of solutions and see which one works best.


#5

The same problem occurs in Go. This blog post explains a way to solve it in Go in a somewhat lean way. See the section titled “Inner Pattern”. I guess the same approach can possibly be applied in Rust.


#6

Yeah, that’s kind of what I meant :slight_smile: Good find. I’m sure you can look at some Go solutions and see how they are structured.