in Rust, methods should be object safe(nora.codes)
nora.codes
in Rust, methods should be object safe
https://nora.codes/post/methods-should-be-object-safe/
10 comments
Rust-specific nomenclature aside, I think it's useful in technical discussions to distinguish between (object) methods, class methods, and functions if your working language supports any combination of the three.
The word "method" is baked into the official Rust docs[0], and while I personally find the definition in the docs to be satisfying, I don't think the author's argument for narrowing that definition down is unreasonable or (more importantly) unworthy of discussion.
The word "method" is baked into the official Rust docs[0], and while I personally find the definition in the docs to be satisfying, I don't think the author's argument for narrowing that definition down is unreasonable or (more importantly) unworthy of discussion.
[0] https://doc.rust-lang.org/rust-by-example/fn/methods.html> Methods are loosely the same as functions that take a '&self', and only because your brain had that word for it, not because it's a good word.
Isn't this just true of any word with increased specificity? Why call it a square when we already have rectangle?
I'm not really seeing how understanding method vs. function is "highly technical". At least, not more technical than, I don't know, writing Rust code in the first place?
Isn't this just true of any word with increased specificity? Why call it a square when we already have rectangle?
I'm not really seeing how understanding method vs. function is "highly technical". At least, not more technical than, I don't know, writing Rust code in the first place?
It’s just not a particularly useful distinction IMO. I have worked in C++, C#, Ruby, and Rust over the past 25 years of programming and outside of academic contexts I have never had a discussion with coworkers that hinged upon whether or not a particular function is, was, or ought to be a method.
In academic circles, there’s some meaningful distinctions to be made. In software engineering I’ve yet to find a place where having a very specific name mattered or reduced communication burden.
In academic circles, there’s some meaningful distinctions to be made. In software engineering I’ve yet to find a place where having a very specific name mattered or reduced communication burden.
I write Java daily. I find a lot of value in marking functions as static to make clear that they are not methods. There is a lot less cognitive overhead wondering if they only operate on their arguments or if they drag in their closure and the rest of the universe.
This might be your experiences, but I've never worked with people who called member functions methods in C++. I've seen C# programmers who had never worked with C++ call them that, but in the C++ teams I can't recall an instance of that, even for multi lingual engineers
Though I do tend to work with teams where the average age is higher than the industry average, that might be warping my anecdotal experiences
I have had situations where the distinction matters, and they aren't academic either, but in API design, especially for libraries
Though I do tend to work with teams where the average age is higher than the industry average, that might be warping my anecdotal experiences
I have had situations where the distinction matters, and they aren't academic either, but in API design, especially for libraries
I’ve had a similar experience, but if someone called a method a function or vice versa, it’s never been unclear what they meant. And it’s never been something that people would have felt the need to correct someone on.
I am aware of the distinction and I (probably?) instinctively use the two terms “correctly” the majority of the time. But if I just picked one or the other and used that word 100% of the time I would wager there would be zero confusion, except amongst pedants.
For what it’s worth, I say this as an avowed pedant.
I am aware of the distinction and I (probably?) instinctively use the two terms “correctly” the majority of the time. But if I just picked one or the other and used that word 100% of the time I would wager there would be zero confusion, except amongst pedants.
For what it’s worth, I say this as an avowed pedant.
> I have never had a discussion with coworkers that hinged upon whether or not a particular function is, was, or ought to be a method
Because _you_ haven’t means the entire industry is wrong?
Because _you_ haven’t means the entire industry is wrong?
I’m not saying the industry is wrong. The two words have clear and distinct meaning.
My point is only that fretting over the distinction between the words serves nearly zero utility in day to day software engineering. It’s like “less than” vs. “fewer”. Each has a correct use, but nobody is confused when you use the wrong one. Many confuse the two, to the point that it’s becoming less and less wrong to use one when the other should be used. “Method” and “function” are similar.
In twenty years, nobody is going to care that they once had a distinctive purpose because that distinction serves little utility.
My point is only that fretting over the distinction between the words serves nearly zero utility in day to day software engineering. It’s like “less than” vs. “fewer”. Each has a correct use, but nobody is confused when you use the wrong one. Many confuse the two, to the point that it’s becoming less and less wrong to use one when the other should be used. “Method” and “function” are similar.
In twenty years, nobody is going to care that they once had a distinctive purpose because that distinction serves little utility.
“People will know what I mean, so why bother being correct or specific” is a flimsy argument, to me, as to why a person shouldn’t care about using correct and precise language. Nor does it really challenge the need for correct and precise language in the first place.
Small children say things incorrectly and we still understand them. Should we all talk like that?
Small children say things incorrectly and we still understand them. Should we all talk like that?
Language is fluid and changes over time. Pedantically clinging to distinctions that no longer serve useful purposes doesn’t stop this from happening.
If a clear separation in meaning between the two words was useful, their distinct use would become more closely adhered to over time. If not, people will start to blend and confuse the two. Of those options, the latter has happened and will likely continue happening with or without your objections.
That this has happened is pretty clear evidence that the distinction hasn’t been worth maintaining.
> Small children say things incorrectly and we still understand them. Should we all talk like that?
Fully grown, articulate adults say things “incorrectly” all the time and nobody bats an eye. The sentence “Hey, where you going?” is missing an entire verb and every one of us has said and heard that sentence (or one like it) hundreds of times without anyone noticing or caring.
If a clear separation in meaning between the two words was useful, their distinct use would become more closely adhered to over time. If not, people will start to blend and confuse the two. Of those options, the latter has happened and will likely continue happening with or without your objections.
That this has happened is pretty clear evidence that the distinction hasn’t been worth maintaining.
> Small children say things incorrectly and we still understand them. Should we all talk like that?
Fully grown, articulate adults say things “incorrectly” all the time and nobody bats an eye. The sentence “Hey, where you going?” is missing an entire verb and every one of us has said and heard that sentence (or one like it) hundreds of times without anyone noticing or caring.
Yes, exactly. Language is fluid and the value of preciseness depends entirely on context. As in, when discussing language design (like we’re doing in this blog post and these comments), method vs function is important. Because of the context.
So, when you’re talking to your coworkers about…whatever… the context probably makes method vs function insignificant. Unless you work in language design, in which case your take is just pretty blatantly awful.
So, when you’re talking to your coworkers about…whatever… the context probably makes method vs function insignificant. Unless you work in language design, in which case your take is just pretty blatantly awful.
It is a nice read!
I am not super familiar with the definition of "object-safe" (I read the docs but the definition is not completely trivial for me).
Does it work to say that an "object-safe" method mutates the object? That's what happens when you take `&mut self`, right?
But if I understood this correctly, I guess it means that a function without side-effect in Java should not really count as a method? Because in Java I call it a method whether it has a side-effect or not. Which corresponds exactly to the definition of `method` in the Rust docs, I think [1]. In C++, I would think that this is the difference between a const (no side-effect) and a non-const (side-effect) method.
[1]: https://doc.rust-lang.org/reference/items/associated-items.h...
I am not super familiar with the definition of "object-safe" (I read the docs but the definition is not completely trivial for me).
Does it work to say that an "object-safe" method mutates the object? That's what happens when you take `&mut self`, right?
But if I understood this correctly, I guess it means that a function without side-effect in Java should not really count as a method? Because in Java I call it a method whether it has a side-effect or not. Which corresponds exactly to the definition of `method` in the Rust docs, I think [1]. In C++, I would think that this is the difference between a const (no side-effect) and a non-const (side-effect) method.
[1]: https://doc.rust-lang.org/reference/items/associated-items.h...
It has to do with type erasure and knowing how big a type is in memory, not mutation. With traits, you can erase the implementing type and get back a vtable of a trait's method - called a trait object.
A trait is object-safe as long as no trait method returns the implementing type (like T::clone() -> T). Once it's a trait object, T is no longer known and the compiler doesn't know how much memory to allocate on the stack or heap, which makes it impossible to use. That's why trait objects have to be boxed or behind references - all pointers have a known size.
A trait is object-safe as long as no trait method returns the implementing type (like T::clone() -> T). Once it's a trait object, T is no longer known and the compiler doesn't know how much memory to allocate on the stack or heap, which makes it impossible to use. That's why trait objects have to be boxed or behind references - all pointers have a known size.
> A trait is object-safe as long as no trait method returns the implementing type (like T::clone() -> T)
That, and much more: https://doc.rust-lang.org/reference/items/traits.html#object... .
That, and much more: https://doc.rust-lang.org/reference/items/traits.html#object... .
This is the shortest, clearest explanation I've yet seen of object safety. Thanks.
Not every trait can be made into a trait object. Traits that are "object safe" can be made into a trait object. Nothing to do with mutation, or side effects.
hmm... so there are object-safe methods and non-object-safe methods, and you can make a `Vec<YourType>` as long as `YourType` does not implement any non-object-safe methods?
> there are object-safe methods and non-object-safe methods
Yes. In the reference, below the definition, there is a list of examples of:
> you can make a `Vec<YourType>` as long as `YourType` does not implement any non-object-safe methods?
It is traits that are object safe, not concrete types.
You cannot make a `Vec<YourTrait>`, you have to make a `Vec<T> where T: YourTrait` or a `Vec<Box<dyn YourTrait>>` or similar.
You only need object safety if you're passing around values dynamically cast to a trait. That's not a required programming pattern.
Yes. In the reference, below the definition, there is a list of examples of:
- Traits that are object-safe with object-safe methods
- Traits that are object-safe with non-dispatchable methods
- Traits that are not object-safe
https://doc.rust-lang.org/reference/items/traits.html#object...> you can make a `Vec<YourType>` as long as `YourType` does not implement any non-object-safe methods?
It is traits that are object safe, not concrete types.
You cannot make a `Vec<YourTrait>`, you have to make a `Vec<T> where T: YourTrait` or a `Vec<Box<dyn YourTrait>>` or similar.
You only need object safety if you're passing around values dynamically cast to a trait. That's not a required programming pattern.
> You only need object safety if you're passing around values dynamically cast to a trait. That's not a required programming pattern.
Yep. In 3+ years of writing rust full time, I’ve still never used `dyn Trait` in any of its forms. A vec where every item is independently heap allocated? Why? And yikes! That would perform terribly.
Yep. In 3+ years of writing rust full time, I’ve still never used `dyn Trait` in any of its forms. A vec where every item is independently heap allocated? Why? And yikes! That would perform terribly.
> A vec where every item is independently heap allocated?
Just because that's the example given (by someone who's trying to understand the concept, no less) doesn't mean that that's the only thing that the language feature is usable for.
Trait objects (read: runtime polymorphism) have their pros and cons just as generics (read: parametric polymorphism) have theirs. Not everything can be known at compile time, and that's perfectly okay.
Just because that's the example given (by someone who's trying to understand the concept, no less) doesn't mean that that's the only thing that the language feature is usable for.
Trait objects (read: runtime polymorphism) have their pros and cons just as generics (read: parametric polymorphism) have theirs. Not everything can be known at compile time, and that's perfectly okay.
Its a pointer with a vtable, it wont make a difference in like 99.99% of cases. You very very likely use them because a lot of libraries use them, Box<dyn Error + Send + Sync> is very common.
I used to care so much about this stuff then I learned to not give a sh*t and Arc<dyn Trait> to get stuff done. If you use a service oriented architecture with interfaces to reduce coupling this is the way.
I used to care so much about this stuff then I learned to not give a sh*t and Arc<dyn Trait> to get stuff done. If you use a service oriented architecture with interfaces to reduce coupling this is the way.
You have likely used dyn result, possibly without realising it, if you have used anyhow
I mean if you know all the concrete types ahead of time you can put them in an enum.
It kind of makes me we wish there was a keyword that would grab all implementations of that trait being compiled and do the same thing though. At least for a statically linked codebase it could figure out all the sizes of the implementations
It kind of makes me we wish there was a keyword that would grab all implementations of that trait being compiled and do the same thing though. At least for a statically linked codebase it could figure out all the sizes of the implementations
That would be lovely, but it would give you “spooky action at a distance” where some large struct adding an impl for some trait would change the size of a data structure in another unrelated part of the program.
But it would be nice if there was some unification of the idea of an enum where every variant implements a trait and &dyn Trait. Basically, an enum made up of a set of named structs where each struct implements a specific trait could be a lovely concept.
But it would be nice if there was some unification of the idea of an enum where every variant implements a trait and &dyn Trait. Basically, an enum made up of a set of named structs where each struct implements a specific trait could be a lovely concept.
Yes, except that you need a layer of indirection to make a trait object, so like Vec<Box<YourTrait>> or similar.
You might be confusing types and traits (typeclasses) here; it's not about `YourType` but rather when you want to make a Vec of heterogenous types that share a trait. That's when the question of object safety (and needing a vtable) arises.
Author is correct that Rust is not OOP. It simply has optional dispatch (which does not an OOP language make). I'm sure many of my fellow rustaceans will agree that the lack of OOP is one of the most competitive features of Rust.
Let's be precise about what definition of OOP we're each using.
In college, I (and I'm sure many others here) learned that OOP was about "abstraction, encapsulation, inheritance, and polymorphism".
But in practice, looking at the history of programming paradigms in industry, it seems like the real success of OOP was in dragging us away from "it's fine for mutable state to be global and/or scattered willy-nilly throughout your code" and towards "mutable state should be localized, tightly scoped, and/or coupled to the code that will be mutating it". Being generous to the academic definition, we could say that the only pillar of OOP that really mattered was encapsulation.
And by that definition, since Rust abhors global mutable state (but not mutation in general, as a functional language might do), it's not unreasonable to say that Rust, even if it doesn't have "objects" as Java or Smalltalk define them, still hews to the most useful parts of OOP.
In college, I (and I'm sure many others here) learned that OOP was about "abstraction, encapsulation, inheritance, and polymorphism".
But in practice, looking at the history of programming paradigms in industry, it seems like the real success of OOP was in dragging us away from "it's fine for mutable state to be global and/or scattered willy-nilly throughout your code" and towards "mutable state should be localized, tightly scoped, and/or coupled to the code that will be mutating it". Being generous to the academic definition, we could say that the only pillar of OOP that really mattered was encapsulation.
And by that definition, since Rust abhors global mutable state (but not mutation in general, as a functional language might do), it's not unreasonable to say that Rust, even if it doesn't have "objects" as Java or Smalltalk define them, still hews to the most useful parts of OOP.
> "mutable state should be localized, tightly scoped, and/or coupled to the code that will be mutating it
Typical enterprise OOP did the opposite of this, coupling state to unrelated code via inheritance. To quote the creator of Erlang, when you want the banana it gives you the whole forest.
Typical enterprise OOP did the opposite of this, coupling state to unrelated code via inheritance. To quote the creator of Erlang, when you want the banana it gives you the whole forest.
> towards "mutable state should be localized, tightly scoped,
Ironically, the way to do actual encapsulation / localized-mutable-state is to just use stack variables - the C way.
Fields (what OOP added) are leakier and less localized than stack variables.
Ironically, the way to do actual encapsulation / localized-mutable-state is to just use stack variables - the C way.
Fields (what OOP added) are leakier and less localized than stack variables.
C still has fields in structures; you just have to pass a structure as the argument to a function. As long as you're okay with syntax like "self->field" or "self.field" (given a parameter called "self"), you can still kind of do OOP, just that no fields are private.
> no fields are private.
Who needs the private keyword when C has better encapsulation than Java?
Who needs the private keyword when C has better encapsulation than Java?
-- foo.h
typedef struct Bleh Bleh_t;
Bleh_t *construct(int i);
int getFoo(Bleh_t *bleh);
-- main.c
#include "foo.h"
void main() {
Bleh_t *bleh = construct(3);
// int i = bleh->foo;
int i = getFoo(bleh);
}
The commented-out line above will not compile, because the internals of Bleh_t are not exposed.That's true, and many libraries do this. However, it comes at the cost of an unnecessary heap allocation that wouldn't otherwise be necessary if not for this encapsulation. If you want to do this, but allocate on the stack, you have to do something like this:
typedef struct Bleh Bleh_t;
size_t get_bleh_size();
void init_bleh(Bleh_t *, int);
int main(void) {
const size_t bleh_size = get_bleh_size();
Bleh_t *const bleh = alloca(bleh_size);
init_bleh(bleh, 3);
const int i = getFoo(bleh);
}
If you rewrite "init_bleh" to return the pointer it receives as the first parameter, you could hide it behind a macro: #define make_stack_bleh(i) init_bleh(alloca(get_bleh_size()), (i))
Used like this: Bleh *const bleh = make_stack_bleh(x);
One advantage of this approach is that you could change the layout of a Bleh without recompiling the other object files, as your compiled code makes no assumptions about the size or the layout of the struct (i.e. the field offsets into a struct aren't hardcoded into the machine code emitted).> just use stack variables - the C way
The problem is that C doesn't offer any resistance to using globals rather than stack variables, which led to much of the mess that the OOP revolution of the 80s was supposed to address. For every C program that eschews globals, you have a Toyota Camry, whose control systems famously contained "10,000 global variables" https://news.ycombinator.com/item?id=9643204
The problem is that C doesn't offer any resistance to using globals rather than stack variables, which led to much of the mess that the OOP revolution of the 80s was supposed to address. For every C program that eschews globals, you have a Toyota Camry, whose control systems famously contained "10,000 global variables" https://news.ycombinator.com/item?id=9643204
> The problem is that C doesn't offer any resistance to using globals rather than stack variables
Nor is there any resistance to writing 'public static' on a field anywhere in Java land. If that's a problem, you have to throw out most languages.
Nor is there any resistance to writing 'public static' on a field anywhere in Java land. If that's a problem, you have to throw out most languages.
> In college, I (and I'm sure many others here) learned that OOP was about "abstraction, encapsulation, inheritance, and polymorphism".
This is what I was referring to. A problem that follows is that many of the Go4 patterns solve problems that OOP causes in the first place (obviously many others are universal).
This is what I was referring to. A problem that follows is that many of the Go4 patterns solve problems that OOP causes in the first place (obviously many others are universal).
I always say it differently: OOP is a paradigm. I've done "object oriented programming" in C and in assembly. Might be more correct to say I've done things like polymorphism in C and assembly. By my definition, Rust can do OOP, even without dyn. I tend to take a very low-level view of things, since I was an assembly programmer before I was a C programmer. I think as Rust broadens its footprint, people are going to have to start using dyn more, and as they do, there'll be new patterns becoming idiomatic. The polymorphism-using-enums pattern is reasonable for tight code like embedded systems, but painful for applications generally.
FYI: https://docs.rs/enum_dispatch
This doesn't work for every case of dynamic dispatch (it only works for what I call closed and semi-open universes of choices [1]), but it works for many of them. And there can always be a catch-all variant that uses a trait object.
[1] https://sunshowers.io/posts/open-closed-universes/
This doesn't work for every case of dynamic dispatch (it only works for what I call closed and semi-open universes of choices [1]), but it works for many of them. And there can always be a catch-all variant that uses a trait object.
[1] https://sunshowers.io/posts/open-closed-universes/
Thanks. I was hoping/dreading that someone had already written such a thing. Hoping, because I have this problem. Dreading, because so much “practical” Rust is macros to make up for missing expressiveness of the language itself.
> The polymorphism-using-enums pattern is reasonable for tight code like embedded systems, but painful for applications generally.
Rust rapidly becomes painful if you try to OOP in it. You would be better off using an OOP language for OOP. It wasn't voted the most loved language because people enjoyed learning lifetimes alongside all the accidental complexity OOP creates.
Dynamic dispatch is mostly seen in two circumstances: the type can't be known at compile time, and reducing code bloat as an optimization step.
Rust rapidly becomes painful if you try to OOP in it. You would be better off using an OOP language for OOP. It wasn't voted the most loved language because people enjoyed learning lifetimes alongside all the accidental complexity OOP creates.
Dynamic dispatch is mostly seen in two circumstances: the type can't be known at compile time, and reducing code bloat as an optimization step.
Complex vs complicated. Complexity is a property of the problem you are trying to solve. If the problem is complex, the solution is complex. Complicated is a property of the implementation. It happens particularly if the abstractions available in the language of choice can’t represent the complexity of the problem. My impression so far is that Rust is powerful enough to do OOP without issue, but, strangely, doing so is frowned upon, and instead developers add needless complexity to avoid using a feature of the language (dyn).
Accidental complexity is an academic term, it means what you refer to as "complicated." Essential complexity would be what you refer to as "complexity." My comment was being precise about it. dyn is avoided because it is typically slower due to the indirection, and because of how its opacity breaks many zero cost abstractions.
I ported the famous Raytracing in a Weeked from C++ OOP into Rust OOP, without any issues, code available on my Github.
Likewise, Microsoft teams not only didn't had any major issues adding COM tooling support for Rust, it is much easier to deal with COM in Rust, than all the C++ frameworks Microsoft has created throughout the years.
Likewise, code available on the official Windows bindings for Rust.
Likewise, Microsoft teams not only didn't had any major issues adding COM tooling support for Rust, it is much easier to deal with COM in Rust, than all the C++ frameworks Microsoft has created throughout the years.
Likewise, code available on the official Windows bindings for Rust.
Rust is OOP. You can pass &self, self, etc. You can dynamic dispatch. It has a lot of great OOP features.
What Rust is not: class-based or inheritance-based (discounting default trait impls).
And this is a nice, modern form of OOP that discards orthogonal and useless design baggage.
What Rust is not: class-based or inheritance-based (discounting default trait impls).
And this is a nice, modern form of OOP that discards orthogonal and useless design baggage.
Only those that never picked a Computer Science book on OOP type systems.
Adhod. I have 18 years of professional experience with OOP, all of it a bloody waste of time. Exhibit: https://youtu.be/ns7jP1-SRvw?si=4NyOYebqtobIkFfC
Apparently not enough to actually understand OOP type theory.
No one that claims to know what OOP is, knows what it means. Because the term is loose and hard to pin down.
If OOP encompasses both Smalltalk AND Rust, it's like saying your definition of X includes a neutron star and giraffe.
By OOP type theory, you mean category theory?
----
Most what people recognize as OOP today is just Class/Inheritance oriented programming, and Rust doesn't belong in that camp, trying to use structural patterns from that kind of OOP in Rust is often a recipe for disaster.
If OOP encompasses both Smalltalk AND Rust, it's like saying your definition of X includes a neutron star and giraffe.
By OOP type theory, you mean category theory?
----
Most what people recognize as OOP today is just Class/Inheritance oriented programming, and Rust doesn't belong in that camp, trying to use structural patterns from that kind of OOP in Rust is often a recipe for disaster.
Not at all, OOP type theory is OOP type theory.
Not what most people on the street think OOP is all, with their anti-Java bias, rather the Computer Science studies of type systems and their application across all forms of OOP in all programming languages ever invented.
Rust has enough features from OOP type systems, regardless of the anti-OOP feeling trying to pretend it doesn't.
Static and dynamic polymorphism, methods, data encapsulation, type dispatch, all there.
Not what most people on the street think OOP is all, with their anti-Java bias, rather the Computer Science studies of type systems and their application across all forms of OOP in all programming languages ever invented.
Rust has enough features from OOP type systems, regardless of the anti-OOP feeling trying to pretend it doesn't.
Static and dynamic polymorphism, methods, data encapsulation, type dispatch, all there.
> Not at all, OOP type theory is OOP type theory.
Tell that to Google. OOP type theory returns mostly Category type theory as results.
What sources do you have on OOP type theory? Our OOP classes were heavy on practical part and less so on theory.
> Rust has enough features from OOP type systems
It's missing inheritance. Without inheritance applying OOP design patterns just fails miserably.
So on one side you have stuff like Java, C++, JS, Ruby, Python and on the other Rust.
> Static and dynamic polymorphism, methods, data encapsulation, type dispatch, all there.
By that definition, Python isn't object oriented (no encapsulation), and C is.
I think it's much more natural to reason about types on what they can do versus some nebulous definition.
I mean any language worth its salt will have encapsulation. It's how you preserve your invariants.
Method is mostly just syntax sugar.
And static/dynamic polymorphism is just a fancy way to say we have function overloading and/or templates and/or vtables (even if using pointer casts).
Tell that to Google. OOP type theory returns mostly Category type theory as results.
What sources do you have on OOP type theory? Our OOP classes were heavy on practical part and less so on theory.
> Rust has enough features from OOP type systems
It's missing inheritance. Without inheritance applying OOP design patterns just fails miserably.
So on one side you have stuff like Java, C++, JS, Ruby, Python and on the other Rust.
> Static and dynamic polymorphism, methods, data encapsulation, type dispatch, all there.
By that definition, Python isn't object oriented (no encapsulation), and C is.
I think it's much more natural to reason about types on what they can do versus some nebulous definition.
I mean any language worth its salt will have encapsulation. It's how you preserve your invariants.
Method is mostly just syntax sugar.
And static/dynamic polymorphism is just a fancy way to say we have function overloading and/or templates and/or vtables (even if using pointer casts).
Search better, look into SIGPLAN and IEEE papers.
Class inheritance is not a requirement for OOP languages.
I listed the OOP traits supported by Rust as a language.
Naturally you have to nitpick it to try to make a point out of nothing.
All high level languages are fancy ways to write machine code.
Class inheritance is not a requirement for OOP languages.
I listed the OOP traits supported by Rust as a language.
Naturally you have to nitpick it to try to make a point out of nothing.
All high level languages are fancy ways to write machine code.
> I listed the OOP traits supported by Rust as a language.
So is the list missing items?
> Naturally you have to nitpick it to try to make a point out of nothing.
What did I nitpick? Does Python have encapsulation beyond gentlemen's agreement?
Can't C have any of the listed behaviors?
So is the list missing items?
> Naturally you have to nitpick it to try to make a point out of nothing.
What did I nitpick? Does Python have encapsulation beyond gentlemen's agreement?
Can't C have any of the listed behaviors?
Python OOP != Rust OOP, but you naturally already knew that.
However, in case you need some help, in regards to Python
Classe inheritance, function and data members, dynamic dispatch, polymorphism, meta-classes.
And even if C doesn't offer direct language support for a OOP type system, that isn't stopping anyone, like the Linux kernel and GNOME/Gtk+.
Or publishing books on the matter,
http://www.freetechbooks.com/object-oriented-programming-wit...
However, in case you need some help, in regards to Python
Classe inheritance, function and data members, dynamic dispatch, polymorphism, meta-classes.
And even if C doesn't offer direct language support for a OOP type system, that isn't stopping anyone, like the Linux kernel and GNOME/Gtk+.
Or publishing books on the matter,
http://www.freetechbooks.com/object-oriented-programming-wit...
> Python OOP != Rust OOP, but you naturally already knew that.
No. Bold of you to assume that. I wasn't aware that one OOP isn't another OOP. I see, so OOP is a fuzzyish definition that you check more checkboxes to satisfy.
If Rust is OOP, and Python is OOP and C is OOP, then the that circles back to my initial claims. A category that is so wide it's effectively useless.
Compare this to sync and async. A precise definition, much greater informational content. You can prove something is pure or not[1]. Compare this to OOP, imprecise, less informational context, impossible to (dis)prove something is OOP or not.
[1]https://www.youtube.com/watch?v=43XaZEn2aLc
No. Bold of you to assume that. I wasn't aware that one OOP isn't another OOP. I see, so OOP is a fuzzyish definition that you check more checkboxes to satisfy.
If Rust is OOP, and Python is OOP and C is OOP, then the that circles back to my initial claims. A category that is so wide it's effectively useless.
Compare this to sync and async. A precise definition, much greater informational content. You can prove something is pure or not[1]. Compare this to OOP, imprecise, less informational context, impossible to (dis)prove something is OOP or not.
[1]https://www.youtube.com/watch?v=43XaZEn2aLc
Come on, it's an automatically generated dependency graphs of `#include`s which is totally useless, but hardly indicative of "a 5 year old being in charge". Absolutely nothing to do with OOP anyway. If you want that look at Java class hierarchies. I found this great art work to illustrate:
https://www.researchgate.net/figure/Class-Association_fig3_2...
https://www.researchgate.net/figure/Class-Association_fig3_2...
People coming to rust attempting to apply typical OOP terms and patterns are likely to hit walls quickly. There’s are some things that of course look familiar. But it’s not where Rust came from, and it’s not what Rust provides.
The word “method” already has a definition in Rust, which includes all intrinsic and trait methods. I feel like ‘dyn’ is relatively rarely useful and defining the term “method” based on what’s compatible with it is a bad idea.
// counter_associated.rs
[...]
let c = Counter::increment(f);
What is `f` here?Just a typo. It's meant to be `c` which is defined on the previous line.
This is a strong reason to, either: Write your examples as Compiler Explorer links (or to some other playground tech, Rust has one to itself but it's easier to remember rust.godbolt.org) so you can see when your example doesn't work
Or, write in Markdown and use tooling to perform tests the same way Rustdoc does, if you wrote what claims to be code, just scoop it up and execute it, if it doesn't compile then we find out before we publish.
I'd say 80% of the time when I write more than one or two lines I write a bug, often it's a minor typo that the compiler would catch but sometimes it's a larger mistake and means I should re-evaluate my entire premise.
Or, write in Markdown and use tooling to perform tests the same way Rustdoc does, if you wrote what claims to be code, just scoop it up and execute it, if it doesn't compile then we find out before we publish.
I'd say 80% of the time when I write more than one or two lines I write a bug, often it's a minor typo that the compiler would catch but sometimes it's a larger mistake and means I should re-evaluate my entire premise.
"Object-safe" really ought to be called "dyn-safe".
dangmale(1)
> I think we should use “method”, in Rust
Just don't. Object-oriented programming is a 1980s buzzword. Let's help industry catch up.
I don't care if people call them functions or methods in daily speech. I even do that sometimes, depending on whom I'm talking to.
But let's not make up a highly technical definition of what a Rust method is.
Methods are loosely the same as functions that take a '&self', and only because your brain had that word for it, not because it's a good word.