Dynamic languages of course support dynamic linking.
ABI breaks are everywhere in C++... consider a class
class foo {
public:
foo();
void do_something();
private:
int x;
}
and an impl in the dynamic library: #include "foo.h"
foo::foo() {
this->x = 0;
}
void foo::do_something() { std::cout << this->x << std::endl; }
You build a libfoo.so and clients use it, calling `foo f; f.do_something();`, it calls your library and it's great.But as soon as you ship a new version that adds a new field to foo (still source-code compatible):
class foo {
public:
foo();
void do_something();
private:
int x;
int y;
};
With a new function body in your shared object: void foo::do_something() { std::cout << this->x << this->y << std::endl; }
You're hosed. Clients have to recompile, or they get: $ ./main
0, 0
*** stack smashing detected ***: terminated
[1] 2625391 IOT instruction (core dumped) ./main
Because the size information for an instance of foo is only known at compile-time, so the clients aren't allocating enough space on the stack for it (ditto the heap if you're using `new foo();`)The way around this is awkward and involves the pimpl pattern and moving all your constructors out-of-line... but you also need to freeze all virtual methods (even just adding a new one breaks ABI), and avoid using any template-heavy std:: types (not even std::string), since those are often fragile.
Most people just give up and offer an extern "C" API, because that has the added benefit that it's compatible across compilers.
"true" C++ shared libraries are crazy difficult to maintain. It's the reason microsoft invented COM.
Swift goes through crazy lengths to make this work, and it's impressive: https://faultlore.com/blah/swift-abi/#resilient-type-layout
Rust would have to do something like Swift is doing, and that's probably never going to happen.
Can you expand a little?
But it ultimately depends on your situation. People elsewhere on this post are listing weaknesses of Rust that I consider to be strengths and vice versa.
Not really.
> it is an improvement in some aspects and a significant step back in others
Of course. Very few improvements are better in every way. There's always something you can find to like about the old solution. Horses are friendlier than cars. Records allow bigger artwork than CDs. Unlike DVDs (at first anyway) you can write to VHS. Unlike Typescript, Javascript doesn't need a compile step. FORTRAN77 fits nicely on punch cards.
That doesn't mean there's really any serious debate about them being improvements.
I will freely admit that Rust has only average compile time (though it's better than C++ at this point), high complexity, and async Rust is full of footguns. But I could come up with a much longer list of complaints for C.
> we must stamp out memory safety issues at all cost and Rust is the solution
Yeah I think memory safety is actually probably not the most important thing about Rust. Having a modern strong type system is arguably more significant. Memory safety is important too of course - even if you don't care about security memory safety issues are often plain hard to debug bugs.