That's why I wrote "limited version of". Rust's "associated constants" are a subset of C++'s class variables feature. Namely you can only have variables qualified "const" i.e. constants.
>Rust also doesn't have classes in any recognizable sense
What? If you have instantiatable abstract data types with associated methods you have a "class". Calling them "structs" does not change that. There are classes defined with "struct" in C++ and D too.
Oh and calling an interface a "trait" does not change its fundamental nature either.
Rust clearly is an OOP language.
In any case, this point is been argued at length for every language, including Rust.
That is, I think the essence of "OOP", OOP-as-used, not any theoretical OOP, is function name resolution depending on type. That and syntax. So first, you write x.tree_foo() instead of tree_foo(x) which is purely syntactic. And then you shorten x.tree_foo() to x.foo(), because x is a tree, which is a great semantic help.
According to this definition, Haskell and C are not "OOP", which matches common understanding.
[obj doStuff: foo withBar: bar]
gets desugared into objc_msgSend(obj, NSSelectorFromString(@“doStuff:withBar:”), foo, bar)Traits just provide a single level of indirection and if you want to do anything more complex you'll need to use composition to achieve it.
let a = Foo; Foo::bar(&a); // if bar takes &self
Plus, there is no concept of inheritance. I don't see how that meets any definition of OOP unless you make the definition so weak as to be meaningless.
So if I just take C's structs and add the ability to associate structs with functions using a "struct.function" notation, I now have classes? If so, a class isn't a very powerful concept, is it?
Here's an easy way to see the difference between traits and interfaces, and simultaneously see why some people find OOP completely inadequate for their purposes.
Imagine you're implementing several different types that all need to be able to be added. You've got integers, floats, mathematical vectors, and possibly other types. All of them should support an `add` method. But you should only be able add objects of the same type: an integer to an integer, a float to a float, and a vector to a vector. This incredibly simple idea, to my mind almost the simplest thing a person might want to do with a type system, cannot be expressed in most OOP languages using an interface with an `add` method.
But it can easily be expressed using traits (or using Haskell's type classes).
And this is why I never understood why anyone bothers with OOP.
What you're talking about has nothing to do with neither.
Any language that has generics can have self types or whatever you want to call them. It's a matter of whether the language has a strong static typesystem and most FP-style languages have these and a minority of OOP-style languages has them too.
The reason why I use C++ has nothing to do with a preference for OOP. It's because all the widely used alternatives have terrible performance.
I hate dealing with C++ projects. I hate dealing with memory leaks and segfaults. But that doesn't stop me from creating more of them and working on existing ones.
All of that because the resulting memory footprint and performance are worth it.
Traits are a form of ad hoc polymorphism and behave closer to Haskell's typeclasses than they do to interfaces and subtype polymorphism.