Yeah this is correct. You don't want to pass these values around "by value" but, you should be able to "embed them" and pass "pointers to them". It's a middle-ground between a completely opaque type which you would also pass around by address, but, with the added benefit that you allocate your own storage for it.
I sort of mentioned this in the blog but this is good clarification.
> if you want to pass a shared_ptr to Zig, you need to pass a pointer to the shared pointer
Yes. For example consider this function to add two 2D points, which accepts and returns all variables entirely in xmm registers: https://gcc.godbolt.org/z/hPGKrh6W4 (surprisingly, gcc generates some fairly odd assembly code here)
This idea about communicating size/alignment is actually something we're doing on the port of RediSearch to Rust [0]. We have an "opaque sized type" which is declared on the Rust-side, and has its size & alignment communicated to the C-side via cbindgen. The C-side has no visibility into the fields, but it can still allocate it on the stack.
It's a bit ugly due to cbindgen not supporting const-generic expressions and macro-expansion being nightly-only. It seems like this will be a generally useful mechanism to be able to use values which are not traditionally FFI-safe across FFI boundaries.
Yeah, this isn't quite C++ interop on its own. It's C++ interop via C, which is an incredibly pertinent qualifier. Since we go through C, opaque pointers are needed for everything, we can't stack allocate C++ values, we need to write extern C wrappers for everything we want to do (like calling member fns), and we don't get any compile-time type/safety checking, due to the opaque pointers.
Direct C++ interop is doable, by embedding Clang into Zig and using its AST, but this is significantly more work and it needs to be done in the Zig compiler. As a Zig user, going through C is about as good as you can do, probably.
It's a bit more than your typical "interop via C". With a "sized opaque" type you actually can stack allocate C++ values in Zig (and vice versa stack allocate Zig values in C++), i.e.
How so? Having written Objective-C and C++ separately but never written Objective-C++ before, I don't understand what's the hate it. Some of my favorite Mac apps from a decade ago were written in Objective-C++. I think Chrome still has some parts in Objective-C++.
I don't think anyone who could help it wrote software in Objective-C++ directly.
It was an unholy welding of the two languages that mostly let Objective-C apps adopt some libraries from the broader C++ ecosystem. Plus the occasional cross-platform C++ codebase used it as a thin shim to provide a Cocoa-based UI...
> When you want to embed a type, you need its definition, but you don’t actually need the full definition. You just need the size/alignment.
Aren't there ABI cases where e.g.
would be passed in e.g. fp registers whereas would not?Yeah this is correct. You don't want to pass these values around "by value" but, you should be able to "embed them" and pass "pointers to them". It's a middle-ground between a completely opaque type which you would also pass around by address, but, with the added benefit that you allocate your own storage for it.
I sort of mentioned this in the blog but this is good clarification.
> if you want to pass a shared_ptr to Zig, you need to pass a pointer to the shared pointer
For lore, I believe this GitHub thread is where I first learned about the how types of the same size/alignment can still have different ABIs :) https://github.com/microsoft/win32metadata/issues/623#issuec...
Yes. For example consider this function to add two 2D points, which accepts and returns all variables entirely in xmm registers: https://gcc.godbolt.org/z/hPGKrh6W4 (surprisingly, gcc generates some fairly odd assembly code here)
It's fixed if you pass -fno-trapping-math. There could be junk in the upper half of the registers that causes a floating-point exception.
Oh, that explains the seemingly useless movs. Thank you! I simply thought that it was a bug, since clang did not emit them.
This idea about communicating size/alignment is actually something we're doing on the port of RediSearch to Rust [0]. We have an "opaque sized type" which is declared on the Rust-side, and has its size & alignment communicated to the C-side via cbindgen. The C-side has no visibility into the fields, but it can still allocate it on the stack.
It's a bit ugly due to cbindgen not supporting const-generic expressions and macro-expansion being nightly-only. It seems like this will be a generally useful mechanism to be able to use values which are not traditionally FFI-safe across FFI boundaries.
[0]: https://github.com/RediSearch/RediSearch/blob/cfd364fa2a47eb...
It’s just both using c abi right?
Yeah, this isn't quite C++ interop on its own. It's C++ interop via C, which is an incredibly pertinent qualifier. Since we go through C, opaque pointers are needed for everything, we can't stack allocate C++ values, we need to write extern C wrappers for everything we want to do (like calling member fns), and we don't get any compile-time type/safety checking, due to the opaque pointers.
Direct C++ interop is doable, by embedding Clang into Zig and using its AST, but this is significantly more work and it needs to be done in the Zig compiler. As a Zig user, going through C is about as good as you can do, probably.
It's a bit more than your typical "interop via C". With a "sized opaque" type you actually can stack allocate C++ values in Zig (and vice versa stack allocate Zig values in C++), i.e.
fn stackExample() void {
Seems like it. And the sizes are all hard-coded, which means you are probably wedded very tightly to a particular C++ compiler.
This has reawakened the nightmares about Objective-C++
How so? Having written Objective-C and C++ separately but never written Objective-C++ before, I don't understand what's the hate it. Some of my favorite Mac apps from a decade ago were written in Objective-C++. I think Chrome still has some parts in Objective-C++.
I don't think anyone who could help it wrote software in Objective-C++ directly.
It was an unholy welding of the two languages that mostly let Objective-C apps adopt some libraries from the broader C++ ecosystem. Plus the occasional cross-platform C++ codebase used it as a thin shim to provide a Cocoa-based UI...
It is still around, even if documentation is only on archives.
Objective C++ was great.
Rename a file to .mm and start using Objective C APIs. Very good interop