I am currently going through the Rust Documentation to understand inherent implementations. What is the "nominal type" and what are they referring to when then they say "associable items to the implementing type"?
Is there a related analog to this in C or C++?
Well, that's the language reference. Learning Rust with that is certainly possible, but a little bit like trying to learn English by reading a dictionary. Have you tried the Rust Book?
Anyway, as the first paragraph states, the "nominal type" is, well:
impl /* --> */ Point /* <-- this is the "nominal type" */ {
fn log(&self) { ... }
}
It's the type which is the subject of the inherent impl
. An "associable item" is an item (like a fn
, const
, or type
) which is associated with the nominal type.
If you had the paragraph:
Let's talk about Raymond. His hair is brown. He knows how to dance.
That would be roughly equivalent to:
struct Raymond; // introduce the Raymond type.
impl Raymond { // associate some items with Raymond.
const HAIR: Colour = Colour::Brown;
fn dance(&mut self) { ... }
}
fn main() {
let mut ray = Raymond;
println!("Raymond's hair is {}", Raymond::HAIR);
ray.dance();
}
(As an aside: the pronouns in the paragraph (like "he" or "him") would become self
or Self
in the impl
.)
The impl
is associating those items with the nominal type. Notice how HAIR
is "inside" of the Raymond
type. You could also write the above code as:
struct Raymond;
const RAYMOND_HAIR: Colour = Colour::Brown;
fn raymond_dance(ray: &mut Raymond) { ... }
fn main() {
let mut ray = Raymond;
println!("Raymond's hair is {}", RAYMOND_HAIR);
raymond_dance(&mut ray);
}
Here, there're no inherent impl
s, so the RAYMOND_HAIR
and raymond_dance
items aren't associated with the Raymond
type directly. There's no fundamental difference between the two, other than convenience.
As for tying this back to C++... that's tricky since Rust distinguishes between inherent and non-inherent impl
s and C++... doesn't. The closest analogue would be to say that they're like the parts of a struct
body that aren't fields and aren't overriding methods in a base class.
An inherent implementation is the equivalent of creating a class in a OOP language. The difference in Rust is that data is separated from implementation:
/* Data */
struct Foo {
// all data there
//...
}
/* Inherent implementation */
impl Foo {
fn bar(&self) {
//...
}
}
foo.bar()
.The inherent implementation is called like that as opposed to trait implementation:
/* Trait implementation */
impl Debug for Foo {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
//...
}
}
The equivalent in C++ could be:
struct Debug {
virtual std::string fmt() = 0;
}
class Foo: public Debug {
// all data there
//...
public:
/* Equivalent of inherent implementation */
void bar() {
//...
}
/* Equivalent of trait implementation:
implementation of base class */
std::string fmt() {
//...
}
}
In C++, you cannot separate "inherent implementation" from "trait implementation" (I put those between quotes, because those terms do not make sense in C++, of course).
Note that unlike in C++, in Rust the methods are not really different that a free function. You can call the bar
method like this:
Foo::bar(foo);
and if you define this function:
fn qux(f: &Foo) {
//...
}
it will have the same signature as Foo::bar
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With