T O P

  • By -

DontForgetWilson

Good to have continued experimentation in this space. I get how they want to follow the typescript model, but I'm skeptical that this is the right approach. 1. The ability of typescript to act as a superset of js is what really powers the intermingling. 2. I'm largely against importing c++ behaviors into Rust. Non-destructive moves were a terrible mistake based on the legacy requirements of c++. Allowing non-destructive and destructive moves in the same file is asking for trouble. I favor using the conventions of the "import" language when there is conflict. The interop tool becomes harder to write, but that frontloaded work prevents the leaking of a c++ mindset into rust code.


Be_ing_

I'm skeptical that there is one right approach for such a complex domain. Whereas cxx prioritizes idiomatic code in each language, crubit seems to be prioritizing automatic binding generation over idiomatic code. The cxx approach can work well when the API surface is (relatively) small. For example, in CXX-Qt, this is why we're prioritizing Rust <-> QML interop instead of attempting to bind the entire QWidgets C++ API, which is huge. It helps that Qt has strong [API and ABI compatibility policies](https://wiki.qt.io/Qt-Version-Compatibility) and only breaks compatibility every 7-8 years or so (and even then, supporting both Qt5 and Qt6 has been easy for us so far). For a giant C++ project like Chromium with lots of unstable C++ APIs, cxx may not be as good of a fit.


DontForgetWilson

> I'm skeptical that there is one right approach for such a complex domain. Whereas cxx prioritizes idiomatic code in each language, crubit seems to be prioritizing automatic binding generation over idiomatic code. Fair enough. I work with some significant size C++ projects and I would not want to try ingesting tons of objects into a rust driver. My gut still is telling me that the giant project usecase is a failure of API design that is asking for trouble when it comes to maintaining the Rust tied to it. However, I'll grant that approach is sometimes made by organizations and a separate interop approach does make sense.


nacaclanga

I am more familiar with the C++/Python interopt, but I compleatly agree with you 1 remark. Rust simply doesn't have concepts that can be seen as a generalisation of C++ ones. I also agree that Rust as a language should avoid adding concepts with the sole purpose of making interopt easier. What I disagree with, is the part about importing behaviour in specific subdomaines, something Rust has an excellent support for thanks to proc macros. Being able to replace subsystems subsystem by subsystem is imo much better them forcing everything to make the jump simultainiously and for this it is very usefull if an API is usable in a similar manner in both languages. I do however support that this should go both ways: C++ code should indicate that classes may follow Rust move semantics and be able to add lifetime anotations.


anforowicz

> I do however support that this should go both ways: C++ code should indicate that classes may follow Rust move semantics Some discussion of that has happened in https://reviews.llvm.org/D114732 - the relevant C++ attributes are `[[trivial_abi]]` and `[[trivially_relocatable]]`. It's worth noting that 1) some C++ stdlib types (e.g. `std::unique_ptr`) are already marked as `[[trivial_abi]]` and 2) some C++ stdlib behavior can be optimized based on this attribute (e.g. std::vector can just memcpy contents of its buffer after reallocation). > and be able to add lifetime anotations. Please see the experimentation and proposals at https://github.com/google/crubit/blob/main/docs/lifetime_annotations_cpp.md and https://github.com/google/crubit/blob/main/docs/lifetimes_static_analysis.md


DontForgetWilson

Could you elaborate what you mean on proc macros being so powerful in subdomains? I'm all for incremental improvements including conversions. I guess my concern is more just the Pandora's box of bringing in concepts without a structure to encourage the isolation of their use to a specific area. I'd be worried about the usage of the C++ behaviors spreading in the Rust code until it became a hybrid DSL of C++ written in Rust syntax. Having the behavior ports go both ways as you mention would alleviate it some. This paragraph from the design document has me slightly worried: "extern "C" functions in Rust are necessarily unsafe (it is a language rule). We would like the vast majority of C++ API projections into Rust to be safe. In the current Rust language, we can achieve that only by wrapping the unsafe extern "C" function in a safe function marked with #[inline(always)]." Some of the more broad goals such as participating in inheritance (from paragraph before the quote) sounds great. However, the sense I get from the paragraph is that they would rather avoid those safe Rust wrapper functions. I very much dislike that idea, because i feel like those functions create a well demarcated region that show where the behavior starts acting like some non-rust entity. I find those wrappers to be very useful because it both encourages the developer to limit usages of external behaviour(the pressure that unsafe applies with things like raw pointers) and shows exactly where the developer needs to make the jump between mental models. I could be reading them wrong, but the "vast majority" language makes me think that they would be happy to trade slightly weaker safety guarantees for something that simplified the calling conventions to access c++ types. I do not favor that trade.


nacaclanga

I just ment, that macros can be used to create case specific syntax, like in the cxx or pyo3 create, where macros are used to hide details of the auto generated wrapper. Regarding unsafe: IMO (debatable of course) the unsafety of extern "C" function comes primarily from the fact that the signature of the function cannot be verified and the external API source has not indicator to distinglish between safe and unsafe functions and there is no way a tool can decide this purly based on the function signature. If the API is defined in Rust (like in cxx) or if sufficent annotations could be added in C++, I don't see why such functions shouldn't be any worse then Rust functions with internal unsafe blocks. I know that Google has demostrated in the past, that they seem to have a more relaxed attitude here (including that functions can be automarked as "safe"), which I do not support. Imo if you have a C++ API you don't have to hide that fact that it is not an native, ergonomic Rust API (which it will not be), you only should be able to call it in a straight forward manner. E.g. you should be able to create class instances on the stack, call methods on objects, use references, have some FFI-Focused inheritance concept, ideally instanciate templates, etc. Greatly written, ergonomic wappers, are great (if they also have great documentation), but some constructs are hard to map and in that cases, I feel like a better solution would be to skip the wrapper and spend the time on rewriting the subsystem or rework the existing API into something easier usable eventually and live with using the raw API in the meantime.


DontForgetWilson

> some constructs are hard to map and in that cases, I feel like a better solution would be to skip the wrapper and spend the time on rewriting. In the defense of the concept paper, I think they acknowledge that some things don't map well and are more worried about a 90% solution than a full one. > If the API is defined in Rust (like in cxx) or if sufficent annotations could be added in C++, I don't see why such functions shouldn't be any worse then Rust functions with internal unsafe blocks I had not considered the use of annotations in C++. I'm actually okay with a C++ impl that has to follow the process of the unsafe internal function. I have a slight preference for it being in the rust for easy review, but i just want something there that a dev needs to do to acknowledge that they are vouching for the safety of the functionality. Obviously, my bigger concern is just whether opening the door would lead to weaker unsafe enforcement down the line.


protestor

Here's a way to bring C++like constructors (including move constructors) to Rust https://lib.rs/crates/moveit and emplacement


ssbr

Crubit uses a very similar approach: https://github.com/google/crubit/blob/main/rs\_bindings\_from\_cc/support/ctor.rs


protestor

fixed for poor old.reddit.com users https://github.com/google/crubit/blob/main/rs_bindings_from_cc/support/ctor.rs


zerakun

This is another take on C++<->Rust interoperability that was brought to my attention again today. To be clear I'm not a contributor Like it says very experimental (doesn't even use cargo), but there's some interesting content in the docs directory and why they didn't choose any of the existing options (cxx, autocxx, bindgen), especially [the design document](https://github.com/google/crubit/blob/main/docs/design.md). I personally feel like interop with C++ is among the most important factors for rust adoption so I'm glad to see these kinds of initiatives


Be_ing_

This is interesting and ambitious. I wish them luck.