How could I achieve a C++ virtual function in Rust? [duplicate] - struct

I'm trying to implement something in Rust that works like a C++ virtual function in a class, I would have a base struct with data, then I would keep some functions undefined, like the following example:
class A {
int stuff;
public:
virtual void foo(int a, int b) = 0;
void function_that_calls_foo() { /*...*/ foo(1, 2); /*...*/ }
}
class B: public A { void foo(int a, int b) { /* ... */ } }
I was trying to implement it using function pointers, but without much success. I could use a trait with A's functions, and implement A on the other class, but I would lose the struct's data. What's the best (fastest?) way to implement this kind of thing in Rust?
struct A {
...
}
impl A {
fn function_that_calls_foo(&self) {
...
self.foo(a, b);
...
}
}
struct B {
a: A;
}
impl B {
fn xxx(&self) {
a.function_that_calls_foo(1, 2);
}
fn foo(&self, a: i32, b: i32) {...}
}

keep some functions undefined
I'm adding the implicit "and have some functions that call that to-be-defined function".
As E_net4 says, use a trait:
trait Foo {
fn foo(&self, a: i32, b: i32) -> i32;
fn function_that_calls_foo(&self) {
println!("{}", self.foo(1, 2));
}
}
You can then implement the trait for Base:
struct Base {
stuff: i32,
}
impl Foo for Base {
fn foo(&self, a: i32, b: i32) -> i32 {
self.stuff + a + b
}
}
And as Matthieu M. says, Rust doesn't have inheritance, so use composition:
struct Base {
stuff: i32,
}
impl Base {
fn reusable(&self) -> i32 {
self.stuff + 1
}
}
struct Alpha {
base: Base,
modifier: i32,
}
impl Foo for Alpha {
fn foo(&self, a: i32, b: i32) -> i32 {
(self.base.reusable() + a + b) * self.modifier
}
}
You can combine the two concepts as well, by taking a generic that is constrained by a type parameter.
I'll strongly second Dietrich Epp's point. Using a new language should involve checking out new paradigms. Inheritance for the purposes of code reuse is not usually a great idea, even in languages that support it. Instead, create smaller building blocks and combine them together.

Related

Late type in Rust

I'm working with two crates: A and B. I control both. I'd like to create a struct in A that has a field whose type is known only to B (i.e., A is independent of B, but B is dependent on A).
crate_a:
#[derive(Clone)]
pub struct Thing {
pub foo: i32,
pub bar: *const i32,
}
impl Thing {
fn new(x: i32) -> Self {
Thing { foo: x, bar: &0 }
}
}
crate_b:
struct Value {};
fn func1() {
let mut x = A::Thing::new(1);
let y = Value {};
x.bar = &y as *const Value as *const i32;
...
}
fn func2() {
...
let y = unsafe { &*(x.bar as *const Value) };
...
}
This works, but it doesn't feel very "rusty". Is there a cleaner way to do this? I thought about using a trait object, but ran into issues with Clone.
Note: My reason for splitting these out is that the dependencies in B make compilation very slow. Value above is actually from llvm_sys. I'd rather not leak that into A, which has no other dependency on llvm.
The standard way to implement something like this is with generics, which are kind of like type variables: they can be "assigned" a particular type, possibly within some constraints. This is how the standard library can provide types like Vec that work with types that you declare in your crate.
Basically, generics allow Thing to be defined in terms of "some unknown type that will become known later when this type is actually used."
Given the example in your code, it looks like Thing's bar field may or may not be set, which suggests that the built-in Option enum should be used. All you have to do is put a type parameter on Thing and pass that through to Option, like so:
pub mod A {
#[derive(Clone)]
pub struct Thing<T> {
pub foo: i32,
pub bar: Option<T>,
}
impl<T> Thing<T> {
pub fn new(x: i32) -> Self {
Thing { foo: x, bar: None }
}
}
}
pub mod B {
use crate::A;
struct Value;
fn func1() {
let mut x = A::Thing::new(1);
let y = Value;
x.bar = Some(y);
// ...
}
fn func2(x: &A::Thing<Value>) {
// ...
let y: &Value = x.bar.as_ref().unwrap();
// ...
}
}
(Playground)
Here, the x in B::func1() has the type Thing<Value>. You can see with this syntax how Value is substituted for T, which makes the bar field Option<Value>.
If Thing's bar isn't actually supposed to be optional, just write pub bar: T instead, and accept a T in Thing::new() to initialize it:
pub mod A {
#[derive(Clone)]
pub struct Thing<T> {
pub foo: i32,
pub bar: T,
}
impl<T> Thing<T> {
pub fn new(x: i32, y: T) -> Self {
Thing { foo: x, bar: y }
}
}
}
pub mod B {
use crate::A;
struct Value;
fn func1() {
let mut x = A::Thing::new(1, Value);
// ...
}
fn func2(x: &A::Thing<Value>) {
// ...
let y: &Value = &x.bar;
// ...
}
}
(Playground)
Note that the definition of Thing in both of these cases doesn't actually require that T implement Clone; however, Thing<T> will only implement Clone if T also does. #[derive(Clone)] will generate an implementation like:
impl<T> Clone for Thing<T> where T: Clone { /* ... */ }
This can allow your type to be more flexible -- it can now be used in contexts that don't require T to implement Clone, while also being cloneable when T does implement Clone. You get the best of both worlds this way.

How to write a generic function in Rust that can accept any struct that implements a specific property?

I am trying to understand generics in Rust and have attempted to write a generic function that can multiple any struct that has the property foo by 10. When I use this code, I get the error, no field foo on type T.
struct A {
foo: i8,
bar: String,
}
struct B {
foo: i8,
}
fn go<T>(v: T) {
v.foo * 10
}
fn main() {
let a = A {foo: 1, bar: "bar".to_string()};
let b = B {foo: 2};
println!("{:?},{:?}", go(a), go(b))
}
How can I write a generic function that can accept any struct that implements a foo: i8 property?
Rust doesn't have properties in the way that JavaScript does, so you need to do things a little differently. You'll want to use a trait to expose the foo functionality as a method, and then implement that trait for A and B:
trait Foo {
fn foo(&self) -> i8;
}
struct A {
foo: i8,
bar: String,
}
impl Foo for A {
fn foo(&self) -> i8 {
self.foo
}
}
struct B {
foo: i8,
}
impl Foo for B {
fn foo(&self) -> i8 {
self.foo
}
}
fn go<T: Foo>(v: T) -> i8 {
v.foo() * 10
}
fn main() {
let a = A {
foo: 1,
bar: "bar".to_string(),
};
let b = B { foo: 2 };
println!("{:?},{:?}", go(a), go(b))
}
(Note that I also made go return a value above.)
This provides a Foo trait that exposes foo as a method, implements it for A and B, and then makes go require T to implement Foo. That's the easiest and most straightforward way to accomplish this goal.

Is there a safe, ergonomic way to change a phantom type in a complex struct?

Suppose we define a generic struct, with many fields, representing a type-safe state machine using a phantom type:
struct Foo<State> {
a: A,
b: B,
c: C,
//...
state: PhantomData<State>,
}
We can then write a type-safe state transition:
impl Foo<SourceState> {
fn transition(self, extra: X) -> Foo<DestinationState> {
let Foo {a, b, c, state: _} = self;
// do lots of stuff
Foo { a, b, c, state: PhantomData }
}
}
But we need to awkwardly unpack every field and re-pack in in a different structure.
We could also use mem::transmute, although my understanding is that different monomorphizations of the same struct are not guaranteed to have the same memory layout.
I hoped that Foo { state: PhantomData, ..self } would work; alas, it fails to compile.
Is there any canonical, ergonomic, safe way to write this ?
There is no way to do that in a straight forward manner, because they are 2 different types: that's the whole point of your code, actually. To simplify it, I'd do that in 2 steps, with a generic transition being the 2nd one:
use core::marker::PhantomData;
struct Foo<State> {
a: i32,
b: i32,
c: i32,
//...
state: PhantomData<State>,
}
struct SourceState;
struct DestinationState;
impl<Src> Foo<Src> {
fn transition<Dest>(self) -> Foo<Dest> {
let Foo {a, b, c, state: _} = self;
Foo { a, b, c, state: PhantomData }
}
}
impl Foo<SourceState> {
fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
// Do whatever you want with self
self.transition()
}
}
Alternatively, you can abstract the fact that you have a state:
mod stateful {
use core::marker::PhantomData;
pub struct Stateful<T, State> {
pub data: T,
state: PhantomData<State>,
}
impl<T, SrcState> Stateful<T, SrcState> {
pub fn transform<DestState>(self) -> Stateful<T, DestState> {
let Stateful { data, state: _ } = self;
Stateful {
data,
state: Default::default(),
}
}
}
}
struct Data {
a: i32,
b: i32,
c: i32,
}
struct SourceState;
struct DestinationState;
type Foo<State> = stateful::Stateful<Data, State>;
impl Foo<SourceState> {
fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
// Do whatever you want with self.data
self.transform()
}
}

How can I implement the Display trait for multiple different types in the same way? [duplicate]

I have two structs and a trait:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
I would like to implement T for both structs using x.
Is there a way to write something like
impl T for A, B {
fn double(&self) -> u32 {
/* ... */
}
}
I would like to not use macros if possible.
The only way to implement a trait once for many concrete types is to implement a trait for all types already implementing another trait.
For example, you can implement a marker trait Xed and then:
impl<T> Double for T
where
T: Xed,
{
fn double(&self) {
/* ... */
}
}
However, Rust has principled generics. The only thing that you know about T in the previous implementation is that T implements the Xed trait, and therefore the only associated types/functions you can use are those coming from Xed.
A trait cannot expose a field/attribute, only associated types, constants and functions, so Xed would need a getter for x (which need not be called x).
If you wish to rely on syntactic (and not semantic) properties of the code, then use macros.
Creating a macro also solves your problem:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
macro_rules! impl_T {
(for $($t:ty),+) => {
$(impl T for $t {
fn double(&self) -> u32 {
self.x * 2
}
})*
}
}
impl_T!(for A, B);
fn main() {}
Using the duplicate_item attribute macro you can do the following:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
This will expand to two identical implementations for the two structs.
I know you said you didn't want to use macros, but I interpret that as meaning you don't want to roll your own macro, so I think this is a good compromise.
You could also use duplicate_item to avoid repeating your struct definitions:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
struct name {
x: u32,
}
Or go all-out if you for some reason need two identical structs with identical implements (at this point we should begin questioning why we need 2 structs at all :D):
use duplicate::duplicate;
duplicate!{
[ name; [A]; [B] ]
pub struct name {
x: u32,
}
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
}
Notice the use of the duplicate function-like macro this time to duplicate struct and implement at the same time.
Since the internals of your structs are the same / share common components, you should extract them into a common struct and embed the common part back into the parent structs. The common struct would have the "complicated" implementation of the trait and then the parent struct's trait implementations would delegate to the common implementation:
trait T {
fn double(&self) -> u32;
}
struct A {
common: Common,
}
impl T for A {
fn double(&self) -> u32 {
self.common.double()
}
}
struct B {
common: Common,
}
impl T for B {
fn double(&self) -> u32 {
self.common.double()
}
}
struct Common {
x: u32,
}
impl T for Common {
fn double(&self) -> u32 {
self.x * 2
}
}
Any nicer code will require changes to the language. Two possible paths:
Fields in traits
Delegation

Duplicate trait method implementation in Rust [duplicate]

I have two structs and a trait:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
I would like to implement T for both structs using x.
Is there a way to write something like
impl T for A, B {
fn double(&self) -> u32 {
/* ... */
}
}
I would like to not use macros if possible.
The only way to implement a trait once for many concrete types is to implement a trait for all types already implementing another trait.
For example, you can implement a marker trait Xed and then:
impl<T> Double for T
where
T: Xed,
{
fn double(&self) {
/* ... */
}
}
However, Rust has principled generics. The only thing that you know about T in the previous implementation is that T implements the Xed trait, and therefore the only associated types/functions you can use are those coming from Xed.
A trait cannot expose a field/attribute, only associated types, constants and functions, so Xed would need a getter for x (which need not be called x).
If you wish to rely on syntactic (and not semantic) properties of the code, then use macros.
Creating a macro also solves your problem:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
macro_rules! impl_T {
(for $($t:ty),+) => {
$(impl T for $t {
fn double(&self) -> u32 {
self.x * 2
}
})*
}
}
impl_T!(for A, B);
fn main() {}
Using the duplicate_item attribute macro you can do the following:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
This will expand to two identical implementations for the two structs.
I know you said you didn't want to use macros, but I interpret that as meaning you don't want to roll your own macro, so I think this is a good compromise.
You could also use duplicate_item to avoid repeating your struct definitions:
use duplicate::duplicate_item;
#[duplicate_item(name; [A]; [B])]
struct name {
x: u32,
}
Or go all-out if you for some reason need two identical structs with identical implements (at this point we should begin questioning why we need 2 structs at all :D):
use duplicate::duplicate;
duplicate!{
[ name; [A]; [B] ]
pub struct name {
x: u32,
}
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
}
Notice the use of the duplicate function-like macro this time to duplicate struct and implement at the same time.
Since the internals of your structs are the same / share common components, you should extract them into a common struct and embed the common part back into the parent structs. The common struct would have the "complicated" implementation of the trait and then the parent struct's trait implementations would delegate to the common implementation:
trait T {
fn double(&self) -> u32;
}
struct A {
common: Common,
}
impl T for A {
fn double(&self) -> u32 {
self.common.double()
}
}
struct B {
common: Common,
}
impl T for B {
fn double(&self) -> u32 {
self.common.double()
}
}
struct Common {
x: u32,
}
impl T for Common {
fn double(&self) -> u32 {
self.x * 2
}
}
Any nicer code will require changes to the language. Two possible paths:
Fields in traits
Delegation

Resources