HNHacker News
TopNewBestAskShowJobs

rvrb

297 karma · joined March 14, 2021

submissionscomments
rvrb··on We rewrote the Ghostty GTK application
I haven't worked with GTK, but what you are describing here sounds reminiscent of what we have been dealing with trying to build Godot bindings in Zig with a nice API. the project is in mid-flight, but Godot:

  - has tons of OOP concepts: classes, virtual methods, properties, signals, etc
  - a C API to work with all of those concepts, define your own objects, properties, and so on
  - manages the lifetimes of any engine objects (you can attach userdata to any of them)
  - a whole tree of reference counted objects
it's a huge headache trying to figure out how to tie it into Zig idioms in a way that is an optimal API (specifically, dealing with lifetimes). we've come pretty far, but I am wondering if you have any additional insights or code snippets I should look at.

working on this problem produced this library, which I am not proud of: https://github.com/gdzig/oopz

here's a snippet that kind of demonstrates the state of the API at the moment: https://github.com/gdzig/gdzig/blob/master/example/src/Signa...

also.. now I want to attempt to write a Ghostty frontend as a Godot extension

rvrb··on I made a real-time C/C++/Rust build visualizer
here, I'll copy the first paragraph of TFA for you:

> Many software projects take a long time to compile. Sometimes that’s just due to the sheer amount of code, like in the LLVM project. But often a build is slower than it should be for dumb, fixable reasons.

rvrb··on Partially Matching Zig Enums
it can narrow the payload: https://zigbin.io/7cb79d

I think the post would be more helpful if it had a concrete use case. let's say a contrived bytecode VM:

  dispatch: switch (instruction) {
      inline .load, .load0, .load1, .load2, .load3 => |_, tag| {
          const slot = switch (tag) {
              .load => self.read(u8),
              else => @intFromEnum(tag) - @intFromEnum(.load0),
          };
          self.push(self.locals[slot]);
          continue :dispatch self.read(Instruction);
      },
      // ...
  }
"because comptime", this is effectively the same runtime performance as the common:

  dispatch: switch (instruction) {
      .load => {
          self.push(self.locals[self.read(u8)]);
          continue :dispatch self.read(Instruction);
      },
      .load0 => {
          self.push(self.locals[0]);
          continue :dispatch self.read(Instruction);
      },
      .load1 => {
          self.push(self.locals[1]);
          continue :dispatch self.read(Instruction);
      },
      .load2 => {
          self.push(self.locals[2]);
          continue :dispatch self.read(Instruction);
      },
      .load3 => {
          self.push(self.locals[3]);
          continue :dispatch self.read(Instruction);
      },
      // ...
  }
and this is in a situation where this level of performance optimization is actually valuable to spend time on. it's nice that Zig lets you achieve it while reusing the logic.
rvrb··on Partially Matching Zig Enums
I did not realize you could inline anything other than an `else` branch! This is a very cool use for that.
rvrb··on Resizable structs in Zig
> I think you're misinterpreting OP's excitement here. The technique isn't novel but the ergonomics are.

This, of course, but I also consciously made the decision to write for an audience less familiar with the language and concepts being discussed. That excitement can translate to engaging a less disgruntled and more curious reader than the OP.

rvrb··on Resizable structs in Zig
I assure you, I am not the one who appears to be reacting in a hair trigger hypersensitive manner in this thread :)
rvrb··on Resizable structs in Zig
You have raised a good discussion point or two, but I am not inclined to engage with them due to the tone you've created with the rest of your comment.

Would it be productive to jump into a thread on a Ruby article and puff your feathers about how you've always been able to do this in Perl, and also in Python 4 you can do XYZ? I don't think so.

For whatever reason, inevitably in threads on systems languages, someone comes in and postures themselves defensively like this. You might want to reflect on that.

rvrb··on Resizable structs in Zig
oh, man! you made my day with this comment. those days are long behind me. we were young, dumb, and inebriated. if you're looking for the bands we were trying to sound like, there was a resurgence of this surf/girl group sound in the early 2010s. look for bands like Shannon and the Clams, Hunx and His Punx, Nobunny, Harlem, Ty Segall, Thee Oh Sees.. basically anyone on the now defunct Burger Records
rvrb··on Resizable structs in Zig
I've entertained further expanding this API to expose a comptime generated struct of pointers. From the Connection use-case detailed in the article, it would look something like this:

  pub fn getPtrs(self: Self) struct {
      client: *Client,
      host: []u8,
      read_buffer: []u8,
      write_buffer: []u8,
  } {
      return .{
          client: self.get(.client),
          host: self.get(.host),
          read_buffer: self.get(.read_buffer),
          write_buffer: self.get(.write_buffer),
      }
  }
I haven't done this because I'm not yet convinced it's worth the added complexity
rvrb··on Resizable structs in Zig
I think there may be room to expand this implementation to support such a use case. Right now it enforces an `.auto` layout of the struct provided in order to ensure alignment, but its easy to imagine supporting an `extern struct` with a defined layout.

Conceivably, an implementation of this `ResizableStruct` that uses an array buffer as backing rather than a heap allocation, and supports the defined layout of an extern struct, could be used to work across the ABI

rvrb··on Resizable structs in Zig
I would describe this approach as 'intrusive' - you're storing the lengths of the arrays behind the pointer, enforcing a certain layout of the memory being allocated.

Because the solution outlined in the article stores the lengths alongside the pointer, instead of behind it, there is room for it to work across an ABI (though it currently does not). It's more like a slice in this way.

You could in theory implement your opaque approach using this as a utility to avoid the headache of alignment calculations. For this reason, I think that makes the approach outlined in the article more suitable as a candidate for inclusion in the standard library.

rvrb··on Resizable structs in Zig
I am the author of this post, let me know if you have any questions or feedback :)
rvrb··on The Color Doesn't Matter
I wrote this in response to other discussions around Hacker News:

https://news.ycombinator.com/item?id=44545949

https://news.ycombinator.com/item?id=44551318

← PreviousPage 2 of 2