4 ms·
I disagree. Rust has managed to have great interoperability, but hasn't made the sacrifice of backwards compatibility that has plagued C++. C++ is also ever so
by ilovecaching 8y ago
I disagree. Rust has managed to have great interoperability, but hasn't made the sacrifice of backwards compatibility that has plagued C++. C++ is also ever so slightly different, and surprising things can happen trying to compile C using a C++ compiler. Rust makes the interface explicit, which is easier to reason about.
- ridiculous_fish 8y agoI'm not super-familiar with Rust's C interop - it it really that good? Does it support preprocessor macros? Can it inline C functions from header files? Does it know about function attributes like pure? If you believe that C++ "sacrificed" for backwards compatibility (and I agree), well what was that sacrifice for anyways, if not better compatibility?
- ilovecaching 8y agoIt is easy in the sense that Rust can match the ABI and calling convention of C with a single annotation or keyword. No, Rust can't use C macros, because it's calling through an ABI that is connected by the linker. The preprocessor has long since run. This is also why pure and inlining are separate issues. It is a much better interop story to use this type of FFI. As I've previously said, C++ compilers are usually not 100% compatible with their C counterparts, and will actually change the semantics of attributes and make different decisions about inlining. It is far better to use a C compiler to get machine code that matches the intended semantics, and call over a well formed ABI that to take the subset language approach. Not to mention that using C libraries from C++ adds a different convention for memory management in the middle of what should be RAII code, which almost always leads to memory leaks. By using the Rust FFI, Rust will at least make sure you are treating unsafe code in a controlled manner.
- pjmlp 8y agoWhile it is nice that Rust offers such FFI, it isn't specific of Rust. Like in any other language with similar feature, it is still a pain to manage in large APIs.
- ridiculous_fish 8y agoSo Rust's C interop is limited to implementing the platform calling conventions? It's nice that Rust can do that but this is NOT better, it's a significant limitation. A deliberate, defensible one, but a limitation none-the-less. Here's a real example. If you write C, you'll probably make a system call, and then check errno. You might also write to errno, e.g. save and restore. errno is implemented differently on every platform, but a C program can include errno.h, and use it portably. C++ can do the same thing: include errno.h and you're done. But Rust can't read the C header, so it must literally special-case every OS [1]. errno is just one thing, but there's a long tail: different platforms have different types and size and function names and signatures, especially the ancient system-y stuff. "Rust is better than C++ at C interop" is an absurd take. The point of Rust is to displace this stuff, not be the best at integrating with it. 1: https://github.com/rust-lang/rust/blob/7cb3ee453b829a513749eb49e6cbe7fe4da527b1/src/libstd/sys/unix/os.rs#L28 https://github.com/rust-lang/rust/blob/7cb3ee453b829a513749e...
- nicoburns 8y ago> errno is implemented differently on every platform, > But Rust can't read the C header, so it must literally special-case every OS [1]. That's a bit of an odd point. You're saying that the C standard library implementation of errno is different on each platform, but abstracted in the standard library so that C programs can just import it and run a portable function. ...and then you complain that Rust does the same...
- qznc 8y agoI'd say there are roughly three classes of C compatibility: Tier 1 is C++ and ObjC, where you can use C headers nearly directly. Tier 2 is where you have to create (and maintain) bindings, but you can map practically everything. Here is Rust, D, Nim, Go, etc. More work than tier 1 is necessary but no loss of performance (except maybe inlining and macros). There are distinctions within this class depending on how well macros etc can be mapped, but usually people map to the ABI instead of the API. Tier 3 is where you cannot map directly and inefficient adapters must be made. This is for example Java, which does not have struct or size_t. Also nearly all scripting languages (Python, Ruby, Lua, etc).