I would like to know if my code is idiomatic, and if it has pitfall that I wasn't expected. This is a re-wrote of the NVI (Non-virtual interface) from C++. It allows to explicitly specify the customization point of an algorithm.
First, the C++ implementation:
class Base {
public:
// the entry point of the algorithm
// this function isn't virtual, it's not a customization point
void foo {
common_part();
custom_behavior();
}
private:
// this isn't a virtual function, so this isn't a customization point either
void common_part() { /* ... */ }
// pure virtual function -> it must be overrided in a child class
// this is the customization point
virtual void custom_behavior() = 0;
};
class Implementation: public Base {
private:
// implements the custom behavior for this specific class
void custom_behavior() { /* ... */ }
}
The function foo()
is the only function in the public API of the class
. common_part()
is private, and should not be overridable by the child class Implementation
. custom_behavior
is also private, and must be overriden in the child class.
How do I do the same in Rust? Base
describes an interface, so I think it should be the trait, while Implementation
would be a struct implementing this trait.
- How do I prevent
foo()
andcommon_part()
from being overwritten inImplementation
? - How do I prevent a user of
Base
to callcommon_part()
orcustom_behavior()
?
I have no idea how to do (1).
For (2), we need to emulate the priv
keyword since all functions in a trait (unlike everything else in Rust) are public by default, and not private. So far the best idea I had was to create a private module, and add the private function in it:
// public trait
pub trait Base: private::BaseDetails {
fn foo(&self) {
self.common_part();
self.custom_behavior();
}
}
// private module
mod private {
// public trait in a private module
pub trait BaseDetails {
fn common_part(&self) { /* ... */ }
fn custom_behavior(&self)
}
}
struct Implementation;
impl Base for Implementation{} // nothing to do
impl private::BaseDetails for Implementation {
fn custom_behavior(&self) { /* ... */ }
}
- Is this idea valid?
- Does it correctly prevent user of the trait Base to use
common_part()
andcustom_behavior()
? - Can all structs implements
private::BaseDetails
? Or do the moduleprivate
must be apub mod
? If so, does it still prevent user of the trait Base to usecommon_part()
andcustom_behavior()
? - How can we do (1) and have non-customization points in a Trait?