-
Notifications
You must be signed in to change notification settings - Fork 232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a doc comparing UniFFI with diplomat #1146
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this is a good idea, but I think there might be some misunderstandings about how diplomat handles modules; left some comments.
docs/diplomat-and-macros.md
Outdated
## How the type universe is constructed for the macro approach. | ||
|
||
In both diplomat and [#416](https://github.com/mozilla/uniffi-rs/pull/416), the approach taken | ||
is that the generation process wants a path to the Rust source file that contains the module in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diplomat takes in a whole crate, not just a module. there may be multiple #[diplomat::bridge]
tagged modules in the crate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there may be multiple #[diplomat::bridge] tagged modules in the crate
@mhammond @badboy I wonder how much of a difference this would make to a use-case like Glean, if you could e.g. have one #[diplomat::bridge]
declaration per metric type but the tool knows how to find them all and expose them as a single API surface when generating the bindings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is certainly worth experimenting with, especially if we can avoid the "module" limitation - eg, if all types needed [uniffi::magic]
then maybe there's actually no reason to insist on a wrapping module? Regardless, I've tried to capture this idea in the doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in the 416 approach that would still have not worked, because we hash all input to put that into the generated function names as a way to prevent use of the wrong version of a library.
A single #[diplomat::bridge]
invocation cannot know all input and thus can't generate one hash.
Of course this is a limitation we built ourselves, so maybe could be lifted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-reading quickly how diplomat works that same hashing could be applied to only the limited bridged module while still giving the same benefits.
Given that diplomat-tool
parses the same code, it would come up with the same hash and know what functions to call in the foreign language code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the reason we have the module wrapper is mostly for convenience, because we need to look at imports as well sometimes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, thanks for clarifying - and while that's interesting context for this discussion, I don't think a discussion of the hashing needs to go into that document. LMK if you disagree though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving that out sounds right to me.
It's a thing we will need to consider if we try the macro approach again, but not necessary to discuss in comparison.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-reading quickly how diplomat works that same hashing could be applied to only the limited bridged module
while still giving the same benefits.
Good point, and in retrospect this thing about including a hash of the component in the name of the generated function probably deserved its own separate design doc. A summary of what's in my head based on the above, in case some of the details aren't obvious:
The main goal of naming our FFI functions like component_<hash>_do_the_thing
instead of just component_do_the_thing
is to guard against undefined behaviours if foreign-language bindings for version X of the interface are accidentally used with a .so
for version Y of the crate. That is: if the details of how to call one of the FFI functions change, then we want the generated name of that function to change.
We don't necessarily have to achieve that by using a single <hash>
of the whole API surface. If we split the FFI into several independent macro invocations, then as long as they're self-contained then they could all safely use their own individual hash.
|
||
In the short term, the best we can probably do is to enumerate the perceived problems | ||
with the UDL file and try to make them more ergonomic - for example, avoiding repetition of | ||
`[Throws=SomeError]` would remove alot of noise, and some strategy for generating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diplomat just treats documentation as "yet another backend", which works reasonably well, since the architecture of a diplomat backend is just "here's the type structure, you know what to expect on the FFI layer, do what you want".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By contrast, the only reason that we don't already have documentation as yet-another-backend in UniFFI, is that the off-the-shelf parser that we use for the IDL throws away comments by default :-(
docs/diplomat-and-macros.md
Outdated
|
||
(There may even be a future where these 2 tools converge - that seems like a lot of work, but | ||
might also provide a large payoff - more on this later) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think a difference not really covered in this document is the style of actual interface. UniFFI basically seems to be serializing types across FFI with this cool FFIConverter scheme, whereas Diplomat uses raw repr(C)
so backends do not need much ceremony to read things. Both are valid approaches, but it's an interesting difference likely borne out of the choice of languages to prioritize (Diplomat cares heavily about C++)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, and I think there may be some broader philosophical differences as well that feed into some of the technical differences. For example, I get the impression that UniFFI is happier to eat some performance overhead in the bindings, and that this comes from our initial focus on targeting managed languages. (As you say, both valid approaches, but an interesting difference).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As Ryan notes later, I think this is a reflection of expedience and initial use-cases, but not necessarily a key difference between the tools at a high level - I think UniFFI could support "native" repr(C)
types in some cases.
If you still think this is important to communicate after seeing my updated version, please give me a rough idea of what it should say and where :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mhammond thanks for writing this up, and for looping me in! I'll try to chew on this a bit over the coming days as I have a little downtime, but some initial thoughts below.
docs/diplomat-and-macros.md
Outdated
|
||
(There may even be a future where these 2 tools converge - that seems like a lot of work, but | ||
might also provide a large payoff - more on this later) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, and I think there may be some broader philosophical differences as well that feed into some of the technical differences. For example, I get the impression that UniFFI is happier to eat some performance overhead in the bindings, and that this comes from our initial focus on targeting managed languages. (As you say, both valid approaches, but an interesting difference).
docs/diplomat-and-macros.md
Outdated
(on disk as a `.rs` file) and the foreign bindings. | ||
|
||
**What's good about this** is that the entire type system is known when generating both the rust code | ||
and the foreign binding. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may not be obvious why "the entire type system is known when generating" is a good thing, I wonder if it's worth saying a few more words here about how it e.g. allows additional safety assurances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the point I had in mind was simply that the foreign bindings need to know the names and types of struct elements so it can recreate the same struct on the other side. But I've tried to capture that in the new version.
docs/diplomat-and-macros.md
Outdated
could be used together. | ||
|
||
Sadly, that looks like alot of work, so someone would probably need to find a compelling | ||
actual use-case to perform this work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or just find it a really interesting technical challenge I guess... 😅
docs/diplomat-and-macros.md
Outdated
a world where you can use diplomat to describe your type universe, but use UniFFI's foreign | ||
generation code to generate the Kotlin bindings. Similarly, a world where you use UniFFI | ||
and UDL files to describe your type universe, but then use diplomat to generate | ||
the NodeJS bindings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This plays a little bit into the discussions around having bindings generators live in separate crates, ref #299.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking a bit more seriously about this, I don't think that there's realistically much value in having a kind of two-way interoperability between UniFFI bits and Diplomat bits. It would require the projects to converge on a great many details of how the FFI layer works, and I don't think there are sufficiently many quick wins to fuel that kind of work. For example, it would almost certainly be quicker for Diplomat to gain a Kotlin backend by writing one from scratch than by trying to iterate the UniFFI Kotlin backend towards something that works for both.
However, what I could see happening in future is UniFFI becoming a kind of higher-level wrapper around Diplomat. I can imagine a Diplomat backend for UniFFI that converts a .udl
file into a bridge module and then uses the Diplomat toolchain to generate bindings from it, keeping some of the additional affordances/conveniences we've built for our specific use-cases (e.g. around megazording).
An interesting thought experiment, anyway 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I did get a bit carried away - I've tried to tone this down a little in the new version.
|
||
In the short term, the best we can probably do is to enumerate the perceived problems | ||
with the UDL file and try to make them more ergonomic - for example, avoiding repetition of | ||
`[Throws=SomeError]` would remove alot of noise, and some strategy for generating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By contrast, the only reason that we don't already have documentation as yet-another-backend in UniFFI, is that the off-the-shelf parser that we use for the IDL throws away comments by default :-(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to both of you for your considered comments. I've made some significant changes in a version I'm about to push, so I'd love continuing to get feedback on the new version. It would also be great if you could "resolve" any comments which you think are suitably represented in the new version, just so I can keep track of what I should consider in future iterations.
docs/diplomat-and-macros.md
Outdated
|
||
(There may even be a future where these 2 tools converge - that seems like a lot of work, but | ||
might also provide a large payoff - more on this later) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As Ryan notes later, I think this is a reflection of expedience and initial use-cases, but not necessarily a key difference between the tools at a high level - I think UniFFI could support "native" repr(C)
types in some cases.
If you still think this is important to communicate after seeing my updated version, please give me a rough idea of what it should say and where :)
docs/diplomat-and-macros.md
Outdated
(on disk as a `.rs` file) and the foreign bindings. | ||
|
||
**What's good about this** is that the entire type system is known when generating both the rust code | ||
and the foreign binding. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the point I had in mind was simply that the foreign bindings need to know the names and types of struct elements so it can recreate the same struct on the other side. But I've tried to capture that in the new version.
docs/diplomat-and-macros.md
Outdated
## How the type universe is constructed for the macro approach. | ||
|
||
In both diplomat and [#416](https://github.com/mozilla/uniffi-rs/pull/416), the approach taken | ||
is that the generation process wants a path to the Rust source file that contains the module in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is certainly worth experimenting with, especially if we can avoid the "module" limitation - eg, if all types needed [uniffi::magic]
then maybe there's actually no reason to insist on a wrapping module? Regardless, I've tried to capture this idea in the doc.
docs/diplomat-and-macros.md
Outdated
a world where you can use diplomat to describe your type universe, but use UniFFI's foreign | ||
generation code to generate the Kotlin bindings. Similarly, a world where you use UniFFI | ||
and UDL files to describe your type universe, but then use diplomat to generate | ||
the NodeJS bindings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I did get a bit carried away - I've tried to tone this down a little in the new version.
docs/diplomat-and-macros.md
Outdated
|
||
Might be enough for the generation of the Rust scaffolding. However, the problems are in the | ||
foreign bindings, because, eg, those foreign bindings do not know the names and types of the | ||
struct elements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate on this one? If we can use these macros as the source for scaffolding code, why couldn't we generate the bindings code as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope I cleared this up in a86e949 - lmk if I need more about this.
|
||
So while we haven't exactly reduced the duplication, we have removed the UDL. | ||
We probably also haven't helped with documentation, because the natural location for | ||
the documentation of `MyFFIType` is probably at the *actual* implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section is some serious food for thought.
For one, as @rfk points out, we're currently duplicating the struct/function definitions in the UDL. The way I see it: both projects have made a similar design decision. @Manishearth describes it as "we do not want changes far away to change the FFI API". I would maybe reword that to "the FFI should be fully defined in one place". For UniFFI, that place is the UDL. For diplomat, it's the ffi module. (Multiple ffi modules complicates this picture a bit, but doesn't fundamentally change things).
However, there is one difference: in some cases you only need code inside the ffi module. This has the potential to reduce duplication. For example, it would be very natural to move our Store
definitions inside the ffi module. Also, since types defined inside the ffi module are visible to the rest of the rust code, so we could move types like Login
, EncrytpedLogin
, CreditCard
, Address
, etc. into the ffi module. I think external data types would still need duplicate definitions, but maybe that's it.
One potential issue with this is that it couples the library with the FFI code. But this doesn't seem to be a problem for our components. As @MarkH points out, our Rust APIs exists purely to service the FFIs.
It really makes me wonder about switching from a UDL-based approach to a macro based approach. At the start, maybe each consumer would simply refactor their current UDL file to a macro. This shouldn't be much work, maybe we could even automate it. After that, we have the ability to do to small refactors that eliminate the unneeded duplication.
BTW, this also could solve some documentation issues since a) we can actually see docstrings when using syn and b) if there's only 1 place where a type is defined then it's clear where to put the docstrings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a brief note in a86e949 which doesn't capture all of this comment, but does briefly say why we should consider this more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems good!
docs/diplomat-and-macros.md
Outdated
## UniFFI's experience with the macro approach. | ||
|
||
Ryan tried this same macro approach for UniFFI in [#416](https://github.com/mozilla/uniffi-rs/pull/416) - | ||
but we struck **what's bad about this** - at least for UniFFI's use-cases: the context in which the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: something's missing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! But I can't see what's missing in this line - which probably means I should reword it :) Can you please let me know what is unclear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the "but we struck" seems to be an incomplete sentence and probably also should have a newline after it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC you want this sentence to treat the **what's bad about this**
as a kind of inline link to suggest "but we struck the bad things noted here". It might be clearer as an actual link :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(That is to say, I think this would read more clearly if you make the **what's bad about this**
a kind of sub-heading in the same style as the UniFFI section above, and reference it more explicitly in the "UniFFI's experience" part).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah! i see
from the FFI to change the FFI. This was born of experience in tools like `cbindgen`. | ||
|
||
For Uniffi, all use-cases needed by Mozilla don't share this design goal, primarily because the | ||
FFI is the primary consumer of the crate. The Rust API exists purely to service the FFI. It's not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, this explains a lot the design decisions :)
Thanks for writing this up! Regarding the request for my experience: In my #416 comment I mentioned "In the current implementation a lot of errors are hidden", unfortunately I can't remember further details. Maybe we uniffi-devs should get together soon again and make some high-level plans where to take UniFFI in the next months. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of great discussion here, thanks for driving it!
docs/diplomat-and-macros.md
Outdated
for example, [this diplomat ffi module](https://github.com/unicode-org/icu4x/blob/7d9f89fcd7df4567e17ddd8c46810b0db287436a/ffi/diplomat/src/pluralrules.rs#L50-L51) | ||
uses types from a [different ffi module](https://github.com/unicode-org/icu4x/blob/7d9f89fcd7df4567e17ddd8c46810b0db287436a/ffi/diplomat/src/locale.rs#L19). | ||
|
||
It also offers better control over the stability of the API, because where the FFI is defined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I don't really understand what's "better" about using a macro than a separate interface-definition file in this regard. IIUC, in UniFFI the API is stable as long as the .udl
doesn't change, while in Diplomat the API is stable as long as the contents of hte macro block don't change.
(Making this claim doesn't bother me, I just don't get it and wonder if I'm missing something).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried to clarify this, but I didn't intend this to mean "better than UniFFI", I meant it to mean "better than allowing any type in the crate to define the FFI"
IOW, I'm trying to say "diplomat's view is that forcing MyFFIType
to be declared inside the ffi
module is better than allowing it to exist outside the module, because what might be considered an "incidental" change to that type might accidentally change the FFI"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha, I see, thanks for clarifying 👍🏻
docs/diplomat-and-macros.md
Outdated
## UniFFI's experience with the macro approach. | ||
|
||
Ryan tried this same macro approach for UniFFI in [#416](https://github.com/mozilla/uniffi-rs/pull/416) - | ||
but we struck **what's bad about this** - at least for UniFFI's use-cases: the context in which the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(That is to say, I think this would read more clearly if you make the **what's bad about this**
a kind of sub-heading in the same style as the UniFFI section above, and reference it more explicitly in the "UniFFI's experience" part).
FFI is the primary consumer of the crate. The Rust API exists purely to service the FFI. It's not | ||
really possible to accidentally change the API, because every API change made will be in service | ||
of exposing that change over the FFI. The test suites written in the foreign languages are | ||
considered canonical. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think this helps answer my question about about API stability in UniFFI vs Diplomat. I still feel like the .udl
serves a similar purpose in the UniFFI world, but because of the way the .udl
kind of maps directly onto the underlying Rust code, I can see an argument that changes in a UniFFI component are more likely to change the FFI surface than in Diplomat.
They won't change to FFI surface by stealth, because you'll have to update the .udl
file...but changing the .udl
file is likely to be the simplest way to accommodate a change in the underlying Rust code. In Diplomat you might instead write some adapter code in the FFI module in order to avoid changing the FFI surface, because there's an obvious place to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I think we agree that UniFFI's use of the .udl file and Diplomat's decision to restrict where types are exposed do serve the same purpose in that regard. The broader point I'm trying to make though is that application-services would prefer to not have those guards in place - ie, it would probably prefer a world where the UDL file didn't exist and nor did any limitation about where these types could be defined.
|
||
But in both cases, for our problematic example above, this process never sees the layout of the | ||
`MyFFIType` struct, so that layout can't be communicated to the foreign bindings. | ||
As noted above, this is considered a feature for diplomat, but a limitation for UniFFI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this work in Diplomat, does the FFI allow you to pass it around as a pointer but not construct one for yourself on the foreign-language side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No - diplomat doesn't have that problem because the struct definition must appear inside the module, so the foreign bindings, which parse that module, do know the struct elements. This is the same as we discovered in #416 - that forcing all type definitions into the single ffi module would technically work, but the impact that would have on how our code is organized made it less appealing than the status quo.
I added a few words here to try and make that clearer.
docs/diplomat-and-macros.md
Outdated
} | ||
``` | ||
|
||
maybe can made to work, so long as we are happy to help UniFFI discover where such annotations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe can made to work, so long as we are happy to help UniFFI discover where such annotations | |
maybe can be made to work, so long as we are happy to help UniFFI discover where such annotations |
} | ||
``` | ||
|
||
So while we haven't exactly reduced the duplication, we have removed the UDL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I think the toy example is the worst-case for highlighting the duplication here because the two duplicate declarations are separated by just 7 lines of text. In a real-world crate I would expect the duplication to not feel quite so bad because the source struct and its redeclaration would be further apart.
(That doesn't help with some of the other contra points raised here though)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect the duplication to not feel quite so bad
This is a good point, but from my POV, that can almost make the duplication feel worse - eg, you get a rust compiler error, and it can be hard to work out whether the UDL needs to change or the rust duplicate of that UDL needs to change - eg, making something optional means adding a ?
to the udl and a corresponding Option<>
to the Rust - it can be difficult to work out which one you screwed up :)
``` | ||
|
||
So while we haven't exactly reduced the duplication, we have removed the UDL. | ||
We probably also haven't helped with documentation, because the natural location for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could imagine explicitly telling the macro about the path to the redeclared struct, like:
#[uniffi::declare_imported_type(super::MyFFIType)]
pub struct MyFFIType {
pub a: i32,
pub b: bool,
}
Then if it wanted to, the code processing this declaration could go find the corresponding super::myFFIType
and pull out e.g. its docstring.
I think this would probably be more trouble than it's worth (we don't want to re-implement vast swathes of Rust's name lookup machinery, for example) but it's interesting to think about.
Thanks all - I also added a link to this to the README. I'm going to merge this now - we can always change it later if we think of something else to add or if it becomes outdated in any way. |
I spent some time having a look at diplomat, primarily to see what UniFFI can learn and opportunities to borrow, and felt it is worth sharing more broadly. I'm not sure if this is the best place for such a doc, and whether we should consider adding a link to README.md (I guess we probably should - explicitly noting diplomat exists in our README could well help some users)
I'd love feedback from everyone, but explicitly flagging just a few - in particular, @Manishearth (who I can't actually flag!) to represent the diplomat team, @rfk as the author of the much referenced #416, and @badboy to see if the document accurately describes his experience trying to use glean with the macro approach in #416. There's no hurry whatsoever, so please continue to enjoy your holidays 🎇
rendered version here