HNNewShowAskJobs
Built with Tanstack Start
Zig / C++ Interop(tuple.app)
109 points by simonklee 4 days ago | 15 comments
  • jcelerier3 days ago

    > 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.

        struct foo { float X, Y; }
    
    would be passed in e.g. fp registers whereas

        struct { char[8]; }
    
    would not?
    • marler89973 days ago |parent

      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...

    • threeducks3 days ago |parent

      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)

      • anematode3 days ago |parent

        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.

        • threeducks3 days ago |parent

          Oh, that explains the seemingly useless movs. Thank you! I simply thought that it was a bug, since clang did not emit them.

  • enricozb3 days ago

    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...

  • pyrolistical3 days ago

    It’s just both using c abi right?

    • Jeaye3 days ago |parent

      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.

      • marler89973 days ago |parent

        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 {

            var some_cpp_type: c.SomeCppType = undefined;
            c.some_cpp_type_ctor(&some_cpp_type);
            defer c.some_cpp_type_dtor(&some_cpp_type);
        
            // ...
        
        }
    • swiftcoder3 days ago |parent

      Seems like it. And the sizes are all hard-coded, which means you are probably wedded very tightly to a particular C++ compiler.

  • swiftcoder3 days ago

    This has reawakened the nightmares about Objective-C++

    • kccqzy3 days ago |parent

      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++.

      • swiftcoder3 days ago |parent

        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...

        • pjmlp2 days ago |parent

          It is still around, even if documentation is only on archives.

    • nly3 days ago |parent

      Objective C++ was great.

      Rename a file to .mm and start using Objective C APIs. Very good interop