Stream: show and tell

Topic: Roc TigerBeetle Client


view this post on Zulip Bryce Miller (Jun 18 2026 at 23:15):

Here's a preview of something I'm working on:

app [main!] { pf: platform "../platform/main.roc" }

import pf.Stdout
import pf.TigerBeetle as Tb

# Requires a local TigerBeetle running on 127.0.0.1:3000 (cluster 0):
#   tigerbeetle format --cluster=0 --replica=0 --replica-count=1 0_0.tigerbeetle
#   tigerbeetle start --addresses=3000 0_0.tigerbeetle

main! : List(Str) => Try({}, [Exit(I32)])
main! = |_args| {
    # Two valid accounts plus one invalid (id 0) to show both result paths.
    accounts = [
        Tb.Account.init({ id: 1, ledger: 700 }).code(10),
        Tb.Account.init({ id: 2, ledger: 700 }).code(10),
        Tb.Account.init({ id: 0, ledger: 700 }).code(10),
    ]

    Stdout.line!("Creating ${accounts.len().to_str()} accounts...")

    results = Tb.create_accounts!(accounts)

    for { status, timestamp } in results {
        msg = match status {
            Created => "  created (timestamp=${timestamp.to_str()})"
            Exists => "  exists (timestamp=${timestamp.to_str()})"
            IdMustNotBeZero => "  error: id must not be zero"
            LedgerMustNotBeZero => "  error: ledger must not be zero"
            CodeMustNotBeZero => "  error: code must not be zero"
            _ => "  error: other"
        }
        Stdout.line!(msg)
    }

    Ok({})
}

output:
Screenshot 2026-06-18 at 7.13.52 PM.png

view this post on Zulip Luke Boswell (Jun 18 2026 at 23:19):

Is this embedded in tigerbeetle? like a plugin script?

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:21):

No. I started with your Zig platform template and linked in the Tigerbeetle C client. Tigerbeetle is running as a separate process.

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:23):

So I guess basically the same way the Official tigerbeetle clients for Node, Go, etc work except that mine is nowhere near feature complete :sweat_smile:

view this post on Zulip Luke Boswell (Jun 18 2026 at 23:27):

What API did you go with for crossing over to the host from the platform? Any issues with roc glue?

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:30):

The only issue with Roc glue is one place where it's using the old pre 0.16 IO. There is some marshaling required for the tigerbeetle account struct because Roc orders the fields differently.

I had Claude do a basic semaphore thing since the tb client is async and runs on a separate thread. I need to review that to a) understand it fully and b) find opportunities for optimizations/cleanup.

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:34):

WIP here for the curious https://github.com/sandprickle/roc-tigerbeetle-demo

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:37):

Bryce Miller said:

I need to review that to a) understand it fully and b) find opportunities for optimizations/cleanup.

For example, seems like there's got to be a better way to handle this :sweat_smile:

  // Roc reorders record fields, so marshal field-by-field rather than reinterpret.
    const tb_accounts = gpa.alloc(tb.Account, n) catch fatal("out of memory");
    defer gpa.free(tb_accounts);
    for (roc_accounts, tb_accounts) |src, *dst| {
        dst.* = .{
            .id = src.id,
            .debits_pending = src.debits_pending,
            .debits_posted = src.debits_posted,
            .credits_pending = src.credits_pending,
            .credits_posted = src.credits_posted,
            .user_data_128 = src.user_data_128,
            .user_data_64 = src.user_data_64,
            .user_data_32 = src.user_data_32,
            .reserved = 0,
            .ledger = src.ledger,
            .code = src.code,
            .flags = src.flags,
            .timestamp = src.timestamp,
        };
    }

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:38):

At minimum pre-allocate a buffer

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:39):

Very open to suggestions on anything and everything here

view this post on Zulip Bryce Miller (Jun 18 2026 at 23:55):

I guess maybe a couple allocations per batch isn't terrible necessarily.

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:08):

Bryce Miller said:

There is some marshaling required for the tigerbeetle account struct because Roc orders the fields differently.

oh yeah I meant to change this so that nominal records try to order the fields sorted by alignment (just like today) and then by declaration order (as opposed to alphabetical like today). would that fix the mismatch?

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:09):

this is very cool @Bryce Miller! :smiley:

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:13):

Richard Feldman said:

Bryce Miller said:

There is some marshaling required for the tigerbeetle account struct because Roc orders the fields differently.

oh yeah I meant to change this so that nominal records try to order the fields sorted by alignment (just like today) and then by declaration order (as opposed to alphabetical like today). would that fix the mismatch?

Hmm lemme confirm the layout

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:16):

Based on the generated header file it looks like that maybe wouldn't fix the issue since the struct has a u64 at the very end. Unless I'm reading this C wrong which is very possible :sweat_smile:

typedef struct tb_account_t {
    tb_uint128_t id;
    tb_uint128_t debits_pending;
    tb_uint128_t debits_posted;
    tb_uint128_t credits_pending;
    tb_uint128_t credits_posted;
    tb_uint128_t user_data_128;
    uint64_t user_data_64;
    uint32_t user_data_32;
    uint32_t reserved;
    uint32_t ledger;
    uint16_t code;
    uint16_t flags;
    uint64_t timestamp;
} tb_account_t;

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:16):

hmm interesting

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:18):

so the reason I'd want to sort by alignment is to avoid wasted space due to alignment padding (and I wouldn't want to just follow the order specified and insert alignment padding, because then end users would be on the hook for manually ordering their fields correctly to avoid unwanted padding, which would be super annoying)

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:18):

but in this case it looks like there wouldn't be any alignment padding

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:18):

because it goes u64, then 2x u32, then 1x u32 followed by 2x u16, and finally the u64 at the end

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:19):

so I'd see no downside with keeping a field ordering like that exactly as-is :thumbs_up:

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:19):

we'd just maybe need a fancier reorder-to-avoid-padding algorithm to support that, but it's probably worth it

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:19):

for scenarios like this

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:20):

I was going to say that I think your design choice makes perfect sense, but if it were possible to get declaration ordering when it doesn't mess with padding that would be cool.

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:21):

What is wrong with our existing order by alphabetical (after alignment) rule?

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:21):

just that this particular host happens to use a different ordering than that

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:22):

it would be ideal if we could declare a roc type that lines up perfectly with their struct type, because then we wouldn't need to convert between the two

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:22):

we could just pass it directly to/from the host because the bytes in memory would already be exactly what both sides expect

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:22):

so perf would improve

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:23):

I don't have a great intuition for how much of a performance hit the conversion is. On the one hand TB is supposed to be uber fast, but on the other hand we are making a network request. I can't remember whether the TigerBeetle client allows more than one in-flight request. I'm thinking not but I'm not positive?

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:23):

So you're thinking of having Roc accept configurable ordering of record fields, based on what a platform host wants?

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:24):

no, just make it so that if you declare a nominal record, we take the ordering you declared for the fields into account more than we do today

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:24):

ok, just nominal records... that makes sense

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:24):

in super rare situations this can also matter for perf within your Roc program

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:24):

It's kind of cool that you can support such a low-level need with that

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:25):

like if you have a really big record and some sections of it get accessed together whereas other sections don't, it could affect which ones are in cache lines together :stuck_out_tongue:

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:25):

Now we just need support for variable bit width integers, and we'll start eating Zig's lunch :wink:

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:25):

yeah I'll aim to make a PR for it tomorrow

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:26):

(the nominal record field ordering thing - I'll aim for making it possible to have this exact struct work across the boundary)

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:27):

I'm flabergasted by how fast things are landing lately. Or maybe the pace has been this quick for months and I just started paying attention :sweat_smile:

view this post on Zulip Richard Feldman (Jun 19 2026 at 02:27):

PR machine goes brrrrr

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:28):

I feel like its a similar work rate... but instead of enormous PR's with hundreds of commits we're back to more normal sized PR's

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:28):

We're polishing more now, rather than re-wiring whole sections of the compiler internals

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:29):

... and now I've gone and said that, Richard will open a PR with hundreds of commits that makes things 10x faster :sweat_smile:

view this post on Zulip Tobias Steckenborn (Jun 19 2026 at 02:30):

Now there’s one concept with roc that I don’t fully understand yet. Such a lib (for using tigerbeetle if I understand correctly) in theory would need to be used with other platforms not be the platform itself, or not? As in theory you’d want your ?cli app? to use tiger beetle and x and y. Or am I missing something here?

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:34):

I think for something this low-level it has to be platform-specific. But was there a plan to allow package imports in platform Roc code? If so, would that allow platform devs to share an interface between platforms?

At the very least, I'd like to get the Roc api to a point where anyone can just yoink it for their own platform if they need a TigerBeetle client.

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:37):

Isn't the key difference here that TB uses a custom protocol... so not something a generic platform would provide?

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:37):

Or maybe it's just TCP and in theory this could be a Roc package -- with the added responsiblity now of getting all the intermediate parts right

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:38):

Yeah I think that’s exactly right. I don’t think you can implement it using TCP effects like you can for e.g. Postgres

view this post on Zulip Tobias Steckenborn (Jun 19 2026 at 02:39):

Yeah, but that’s the same for example for Redis and the like, right? I‘m just wondering right now each underlying „library“ seems to be done as as platform. That to me seems to lead to fracture of the ecosystem as you by chance would need to find something that has exactly your stack which is unlikely which in turn would be more or less the requirement to also know platform dev :sweat_smile: but might be mistaken here

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:40):

I think their wire, memory, and disk format are all the same bytes so they can just avoid serialization/deserialization

view this post on Zulip Tobias Steckenborn (Jun 19 2026 at 02:40):

Ah okay, so very specific for tigerbeetle

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:42):

Yeah I think so. I suppose it might be different if they published an open protocol for it at some point maybe.

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:45):

same for example for Redis and the like, right?

I think Redis is a TCP socket, with a custom protocol over it... so any Roc platform that provides a TCP primitive will be supportable

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:46):

Speaking of... I guess the next version of basic-cli should drop to TCP and let roc-lang/http implement the HTTP protocol specifics on top right?

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:53):

Seems like it would be possible to create a platform that lets you configure some add ons as part of the build process, so you could decide whether you want your webserver to include sqlite, duckdb, tigerbeetle, or none of them. That might reduce the need to fork platforms and customize them.

Maybe some combination of build flags for the host and a script that adds/removes roc modules from main.roc

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:55):

you can throw all the symbols in the prebuilt host binary, and Roc will just dead code eliminate that when you build -- based on what you actually use

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:55):

Oh ok yeah than this would be really simple

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:56):

It's a bigger maintenance surface though... so I think the trend will be towards standardised interfaces like TCP

view this post on Zulip Luke Boswell (Jun 19 2026 at 02:57):

Certainly to unblock people you can fork a platform, wrap an existing C library (or other Zig/Rust crate etc) and be working in no time... but there is an incentive there to write things in pure Roc

view this post on Zulip Bryce Miller (Jun 19 2026 at 02:59):

Oh wait are you saying that even if I had a webserver platform that included 5 db clients (both roc interfaces and host stuff), my binary would only include what I actually use?

I was more thinking for situations where there isn’t a standardized interface like TCP available

view this post on Zulip Luke Boswell (Jun 19 2026 at 03:00):

my binary would only include what I actually use?

yes

view this post on Zulip Bryce Miller (Jun 19 2026 at 03:01):

Dope!

view this post on Zulip Luke Boswell (Jun 19 2026 at 03:03):

I might be wrong though... worth double checking with @Richard Feldman -- Roc linking DCE's hosted effects from the host if they aren't called by Roc?

view this post on Zulip Richard Feldman (Jun 19 2026 at 03:09):

yeah it's set up to do that

view this post on Zulip Richard Feldman (Jun 19 2026 at 03:09):

I don't think it's been super battle tested, but should be easy enough haha

view this post on Zulip Richard Feldman (Jun 19 2026 at 03:10):

just add some giant dep to the host, don't use it on the Roc side at all, then roc build and see how much (if at all) the output binary size changes :smile:

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:04):

also, just a quick note: for anything where the fundamental ting you need to do is send bytes over a socket (redis, any other database, I assume TigerBeetle too), there is a 100% chance you can write that in pure Roc as a platform-agnostic package :smile:

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:05):

now that said, you may not want to do that - or at least, not at first

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:06):

it's always been part of the plan to have hosts be able to bootstrap the ecosystem - in other words, at first you reuse existing C/Zig/Rust/etc. code in the host to provide that functionality, but then later you want a pure-Roc, platform-agnostic version, which motivates doing that implementation

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:07):

so you can get unblocked quickly by bundling it with the platform, and then unbundle it later

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:08):

as an example, here's a WIP (and not updated to the new compiler) example of a pure-Roc postgres client: https://github.com/agu-z/roc-pg

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:08):

all the platform has to do is to provide the primitive of "send bytes over a socket" and then this platform-agnostic package does all the postgres-specific stuff

view this post on Zulip Richard Feldman (Jun 19 2026 at 17:08):

same strategy would work for any other db

view this post on Zulip Bryce Miller (Jun 19 2026 at 17:36):

Yeah thats a good point. It occurred to me after our earlier conversation that since I have to specify a port when connecting to a TB cluster, it has to be using either TCP or UDP (TCP, as it happens) :sweat_smile:

view this post on Zulip Bryce Miller (Jun 19 2026 at 17:47):

I do shudder at the idea of trying to re-implement the TigerBeetle client logic in any language. I'm very happy to leave that project to somebody else :sweat_smile:. I doubt it would be easier than adding the official client to a platform (which was pretty easy!)

view this post on Zulip Richard Feldman (Jun 19 2026 at 18:08):

I think that's probably true of most databases haha

view this post on Zulip Richard Feldman (Jun 19 2026 at 18:09):

but I also think you'd be surprised! some people shudder at the idea, and other people are excited by it

view this post on Zulip Richard Feldman (Jun 19 2026 at 18:09):

it's not very often you find an excuse to build a real-world byte-level database client that people will actually use, if that sounds like something you'd find interesting! :smiley:

view this post on Zulip Richard Feldman (Jun 19 2026 at 18:10):

see roc-pg for example :smile:

view this post on Zulip Bryce Miller (Jun 19 2026 at 18:21):

Interestingly, I was thinking I might end up wanting to use roc-pg at some point, in which case I might help port it to the new compiler if I have time. After that maybe I’ll eat my words about implementing db clients lol

view this post on Zulip Richard Feldman (Jun 21 2026 at 11:16):

Richard Feldman said:

(the nominal record field ordering thing - I'll aim for making it possible to have this exact struct work across the boundary)

@Bryce Miller this is on main now btw!

view this post on Zulip Bryce Miller (Jun 27 2026 at 01:20):

I believe I've finished wiring up all of the TigerBeetle API. You can clone and try it out here https://github.com/sandprickle/roc-tigerbeetle-demo.

Thanks to the recent record layout changes, I was able to go from 4 allocations per batch to 2 allocations per batch, if I'm counting right: One for the request, and one for the response.

Right now I just block the Roc thread while we wait for the client to respond. I think there might be a little bit of perf we could gain by being async, because even thought the TB client only allows one in-flight request at a time, it can do some prep work on batches while it waits for responses.

I attempted to run some benchmarks to compare this to the Go and Rust clients, but my single-node local cluster was performing very inconsistently. Not sure whether there is actually a good way to benchmark these but I certainly haven't found it if so :sweat_smile:.

view this post on Zulip Richard Feldman (Jun 27 2026 at 01:30):

that sounds like a great start, congrats on getting it working! :smiley:

view this post on Zulip Bryce Miller (Jun 27 2026 at 01:37):

Thanks in no small part to glue and Luke’s templates :grinning:

view this post on Zulip Bryce Miller (Jun 27 2026 at 01:38):

Tigerbeetle wants to be run alongside another database though, so now I’m eyeing my next target :sweat_smile:

view this post on Zulip Richard Feldman (Jun 27 2026 at 01:39):

are there any compiler bugs you still need to work around?

view this post on Zulip Richard Feldman (Jun 27 2026 at 01:39):

I'm running low on non-in-progress bug reports :laughing:

view this post on Zulip Bryce Miller (Jun 27 2026 at 01:43):

Well I think maybe dbg only works in the interpreter? That didn't bother me, but there was a test I inherited from the platform template that only works with the interpreter.

Partway through I needed to remove the 'targets' entry in main.roc, I guess it just knows where to look for the build artifacts now? I almost filed an issue when my main.roc stopped parsing but then I figured it out :sweat_smile:

I'm really not thinking of anything though.

view this post on Zulip Bryce Miller (Jun 27 2026 at 01:45):

Oh! I thought of one! There was one instance where Roc wasn't populating the unnamed fields with 0 and TigerBeetle complained. I want to say it was with a debug build of the Roc compiler but I'd have to double check that. I was able to do a production build and that fixed it.

view this post on Zulip Richard Feldman (Jun 27 2026 at 02:03):

oh interesting

view this post on Zulip Richard Feldman (Jun 27 2026 at 02:04):

there's an innate tradeoff there which is that it takes time to zero them out, but maybe that's best

view this post on Zulip Bryce Miller (Jun 27 2026 at 02:06):

Ah, Is it something I can zero out myself in e.g. TigerBeetle.Account.init()?

view this post on Zulip Richard Feldman (Jun 27 2026 at 02:06):

not at the moment because you can't assign to unassigned fields :laughing:

view this post on Zulip Richard Feldman (Jun 27 2026 at 02:06):

but I'll just change it to zero them out, it's probably better for security

view this post on Zulip Bryce Miller (Jun 27 2026 at 02:07):

Ok that's what I thought but just wanted to make sure I hadn't missed something :sweat_smile:

view this post on Zulip Bryce Miller (Jun 27 2026 at 02:18):

Yeah in this particular case TigerBeetle insists that all reserved fields are set to zero. Totally something I could do today by just removing the underscore on the field though.
I have an unnamed field with type U32 and the value as seen by the host is ._pad0 = { 1, 0, 0, 0 }

view this post on Zulip Richard Feldman (Jun 27 2026 at 02:21):

oh that's a good point

view this post on Zulip Richard Feldman (Jun 27 2026 at 02:22):

yeah I guess that's actually a good idea since that way you can get the perf if that's what you want

view this post on Zulip Bryce Miller (Jun 27 2026 at 02:25):

Yeah I figured it was at least worth consideration. all the other TigerBeetle clients have their reserved fields exposed and you are expected to set them to zero. So it would be par for the course in that regard.

Right now do unnamed fields just contain whatever bytes happen to be there?

view this post on Zulip Bryce Miller (Jun 27 2026 at 02:27):

I have no idea how it works now but I'm wondering if I made a ridiculously large unnamed field would I be able to just read whatever was previously in memory there?

view this post on Zulip Bryce Miller (Jun 27 2026 at 02:27):

*on the host side

view this post on Zulip Richard Feldman (Jun 27 2026 at 03:14):

yeah but the host can already read whatever it wants to haha

view this post on Zulip Richard Feldman (Jun 27 2026 at 03:14):

the host has sudo on your process basically

view this post on Zulip Richard Feldman (Jun 27 2026 at 03:14):

nothing is safe from it

view this post on Zulip Bryce Miller (Jun 27 2026 at 13:17):

That makes sense. I suppose the operating system prevents the host from reading memory from another process.

view this post on Zulip Bryce Miller (Jun 27 2026 at 14:20):

So for values that the application developer will construct, I can use normal record fields with a custom number type such as the following for reserved fields:

    ## 6 byte reserved field that must be 0
    Reserved6 :: (U16, U16, U16).{
        from_numeral : Numeral -> Try(Reserved6, [InvalidNumeral(Str), ..])
        from_numeral = |numeral| match U8.from_numeral(numeral) {
            Ok(0) => Ok(Reserved6.(0, 0, 0))
            _ => Err(InvalidNumeral("reserved must be 0"))
        }
    }

But for values the application developer will never construct, I can keep the reserved fields as _reserved

view this post on Zulip Bryce Miller (Jun 27 2026 at 14:24):

And this feels nice. All tomfoolery is prevented at compile time.

view this post on Zulip Bryce Miller (Jun 28 2026 at 18:21):

Hey I heard you were looking for bug reports so I made one! #9859

view this post on Zulip Bryce Miller (Jun 28 2026 at 18:22):

(looks like field ordering change regressed)

view this post on Zulip Richard Feldman (Jun 28 2026 at 21:07):

oh oops, I forgot to mention this - try adding _ : {} somewhere in the declaration

view this post on Zulip Richard Feldman (Jun 28 2026 at 21:08):

I had to change it so that we no longer to it by default and that's how you opt in

view this post on Zulip Richard Feldman (Jun 28 2026 at 21:10):

the problem was that "would we need to insert padding if we kept this ordering?" can have a different answer if you're building for 32-bit vs 64-bit targets

view this post on Zulip Richard Feldman (Jun 28 2026 at 21:13):

and I started thinking about edge cases related to "what if you're building on a 64-bit machine but targeting 32-bit build" and in the end I decided the least error-prone design is "if you have an unnamed field, we will keep your ordering guaranteed and insert any missing padding as necessary, and if you don't have any unnamed fields then we'll reorder them for you"

view this post on Zulip Bryce Miller (Jun 28 2026 at 21:17):

Ok, so if I have unnamed fields, I’m accepting declaration order and any padding that may result, even if it’s more than the minimum possible due to inefficient ordering. If I don’t have any unnamed fields, I’m guaranteed the minimum possible padding but fields may be reordered. Is that a correct understanding?

view this post on Zulip Richard Feldman (Jun 28 2026 at 22:01):

yep!

view this post on Zulip Bryce Miller (Jun 28 2026 at 22:32):

Got it!


Last updated: Jul 23 2026 at 13:15 UTC