Zig / C++ Interop

Dev “Frankenstitches” Zig and C++ with dummy parts; PTSD and nitpicks ensue

TLDR: A dev makes Zig and C++ share data using opaque stand-ins that match size and alignment, checked at build time. Comments split between Obj‑C++ trauma, ABI caution that size isn't behavior, and pragmatic “use the C rules,” showing a simple way to mix languages without exposing internals.

Today’s spicy thread: a developer makes Zig and C++ play nice by stuffing “dummy” stand‑ins into each other’s data—think cardboard cutouts that match the real thing’s size and weight. The trick, dubbed SIZED_OPAQUE, lets both sides reserve the right amount of space and check it at build time, then move the real data around with pointer gymnastics. Even Zig’s HTTP client, which changes size depending on optimization mode, gets slotted in like luggage. Clever? Absolutely. Calm? Not even a little.

The comments explode into three camps. First up, the trauma squad: swiftcoder cracks a joke that this “reawakens Objective‑C++ nightmares,” and the PTSD meme parade begins, complete with “never again” vibes and flashbacks to fragile language mashups like Objective‑C++. Then the skeptics: jcelerier warns that ABI (application binary interface—the rules for how data is passed around) isn’t just about size; a floaty two‑number struct might ride in special registers, while a same‑size byte blob won’t, meaning “same size” ≠ “same behavior.” Meanwhile, the pragmatists show up with receipts: enricozb says Rust folks do this too, using cbindgen, admitting “it’s a bit ugly” but workable. pyrolistical tries to chill the room with, “It’s just both using the C ABI, right?”

Verdict: a bold hack with a side of nostalgia, skepticism, and comedy. The vibe: use it, but keep your safety goggles on.

Key Points

  • The article presents an interop method where Zig and C++ embed each other’s types using opaque types defined by size and alignment, avoiding full type definitions.
  • A C macro (SIZED_OPAQUE) defines opaque structs with specified size/alignment and exposes constants for compile-time verification.
  • Both Zig and C++ verify correctness at compile time: Zig via @sizeOf/@alignOf/@compileError and C++ via static_assert.
  • Examples include embedding C++ std::shared_ptr<Foo> in Zig and storing Zig’s std.http.Client in C++, with sizes selected per optimization mode via ZIG_OPTIMIZE_* macros.
  • Interop usage relies on passing pointers and C++ helper functions to move/access objects (e.g., shared_ptr), avoiding unsafe raw copying across language boundaries.

Hottest takes

"This has reawakened the nightmares about Objective-C++" — swiftcoder
"Aren't there ABI cases where a 'same-size' blob wouldn't be passed the same way?" — jcelerier
"We have an 'opaque sized type'… It’s a bit ugly" — enricozb
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.