Yes. OOP with struct inheritance is fundamentally problematic. Both from theoretical standpoint and practical standpoint.
Consider the following simple example:
class Foo {
virtual int x2(int x) {
return x + x;
}
virtual int x3(int x) {
return x2(x) + x;
}
};
class Bar : public Foo {
virtual int x2(int x) {
counter++;
return Foo::x2(x);
}
};
Here class Foo have two functions: x2 and x3 (multiplication by 2 and 3) and it's descendant can count number of times x2 or x3 was called.
Suppose someone later found out that x3 is too slow and improved it:
class Foo {
public:
virtual int x2(int x) {
return x + x;
}
virtual int x3(int x) {
return x + x + x;
}
};
Behavior of the x2 and x3 is the same… yet some totally unrelated code in another module is now broken.
When you are using OOP with implementation inheritance you have to specify not only what each and every function if used, but also when is used, too. And when it's not used, also.
Even most OOP advocates accept that this is the issue. And solution offered is simple: avoid use implementation inheritance, use interface inheritance instead. And offer default implementations for more complicated functions in these interfaces (where they become part of the interface, not implementation).
Coincidentally (yeah, right) that's the type of OOP which can be implemented easily in Rust with help of traits.
And it's not an anti-pattern, it's used in Rust everywhere.
OOP is also the reason why GUI is always buggy and laggy. These hidden dependencies introduced via common implementation is probably source of more bugs than anything else in programming.
Sure, many years ago, when 640KiB was typical memory size of a typical computer they also allowed to write quite compact code. But today it no longer works: because contemporary GUI applications are so large and complex people usually try to not rely on these hidden dependencies but try to encapsulate required work in every single method. The end result is code which does the same thing again and again. Hundreds or thousands of times. Any savings which were possible at some point in the past are dwarfed by cost of that “defensive GUI programming”.
GUI remains tough nut to crack, though: we already know that traditional approach to it leads to fragile and slow code, but it's not yet clear how to simplify things and yet keep them reliable.
But it's not surprising Rust is trying to achieve that instead of bringing “traditional OOP” back (fully or half-way like Go does): it's just not the Rust way to accept half-backed solution if there's hope of doing things better.