Replies: 2 comments
-
For context, a small snippet from the top of the current high-level mfem-rs/crates/mfem/src/lib.rs Lines 5 to 15 in 2c0964d And also a small snippet from the bottom of my (now stale 😅) Lines 54 to 60 in 2c0964d The custom traits came into existence because I didn't know about the built-in niceties around That's just a long-winded way to say: I'm totally on board with trying the "Deref Approach" from your suggestions above! I also encountered the problem of needing both mfem-rs/crates/mfem/src/lib.rs Lines 271 to 277 in 2c0964d Based on details of the "Deref Approach" that you describe, this seems unavoidable. On the other hand, it doesn't seem too bad, especially if boilerplate code can mostly be eliminated by using macros as you're doing in your prototype. TBH I have very mixed feelings about macros, having written some horrific stuff... 🤪 I think it's probably better to start by hand-rolling all the code, discovering which patterns are boilerplate-y, and then refactoring with macros when the code has stabilized. |
Beta Was this translation helpful? Give feedback.
-
Another thing: I have a strong bias against hand-written For example, I prefer having C++ boilerplate like this: mfem-rs/crates/mfem-sys/include/wrapper.hpp Lines 141 to 147 in 2c0964d Over having Rust boilerplate that uses mfem-rs/crates/mfem-sys/examples/ex1.rs Lines 232 to 238 in ca54baf The reason is that the C++ code is completely safe, in the sense that it is type-checked. If I mess it up, the compiler will catch me. On the other hand, with the Rust code that uses If the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
IMHO, the main question is how to handle the subclass relationships. The other difficulty is that several functions return pointers to internal data structures, these require only a (non owning) thin wrapper around the pointer with a lifetime to track the dependency. So there are two classes of C++ “values”: owning values and references.
For subclasses, there is a variety of possibilities.
impl T
andimpl T + 'a
). The problem is that they have to be implemented for each subclass (one may want to think to a for of transitive system to minimize boilerplate) and they will have to be brought into scope. Constructors cannot be part of the trait (they many not have a uniform interface across subclasses). If several subclasses may populate a single variable, they will ahve to be treated asdyn Trait
.Deref
: the nice thing is that it is applied transitively by the compiler (so ifA
is a subclass ofB
andB
ofC
,C
methods are accessible fromA
without having to do anything). Also several subclasses may be converted to the base class and be handled as a reference to the base class. For this, we need two types of values, sayT
for owning values andAT
for references, withT
deref toAT
. IfT
is a subclass ofU
, then theDeref
s are as follows:T → AT → AU
andU → AU
. I have adopted the second approach in my attempt and it works well (although having, say,Mesh
andAMesh
is a bit ugly) but now is the time to revisit that.Note that Autocxx implements
AsRef
(but notAsMut
) when it detects a subclass relationship (this doesn't work for abstract classes).To use
Deref
for subclasses, given the signature ofDeref::deref
, references have to be handled as Rust references&'a AT
. This may be dangerous if C++ mutates the pointer “under our feet” as it is UB. There is an ongoing “discussion” to have more safety using aCppRef<T>
type. It is actually already present in autocxx but not enabled by default.What do you think?
Beta Was this translation helpful? Give feedback.
All reactions