Hacker News new | past | comments | ask | show | jobs | submit | unclad5968's comments login

The same way the OOP compilers implement them, with v-tables. Basically the compiler makes a table of function pointers so calls can be resolved (not sure resolved is the correct term) at runtime.

In Zig or any other C like language without "interfaces", you would implement the V-table by hand, which is a common idiom in Zig.


do you have an example of what that would look like ?

I'm a bit confused about when you would construct this table and how one would use it


Basically you have something like

    typedef struct Writer {
      int (*method_one)(const char*, int);
      //...  
    } Writer;



    void takes_a_writer(const Writer *obj)  {
      // somewhere 
      obj->method_one(buff, buff_size);
      // ...
    }


    // a method implementation 
    int method_one_impl(const char *buff, int n) {
      //...
     }


     // somewhere else
     Writer w;
     w.method_one = method_one_impl;

     //...
     takes_a_writer(&w);

It isn't the best example, but should do the job giving you an overview.

Let's say you have an interface 'Reader' with methods 'Read' and 'Close'. In a world where no interfaces exist, every user of a different implementer of this interface would need to know exactly which 'Read' and 'Close' implementations to call, and possibly generate different code for it.

In order to make this mechanism generic, you can instead say, "every implementer of the 'Reader' interface has a pointer as its first field, and that pointer leads to an array of two elements: the first element is a pointer to a 'Read' method, the second to a 'Close' method."

This way, the user of a Reader knows nothing of the internals of each implementation, other than how to find its methods


somethign like this I think. i only dabble in zig/systems stuff so there might be better/more idiomatic ways to write parts

  const std = @import("std");
  
  // base struct
  const Animal = struct {
      // points to the derived struct
      ctx: *anyopaque,
      // points to the vtable of the concrete type
      vtable: *const VTable,
  
      // the vtable interface derived struct must implement
      const VTable = struct {
          make_noise: *const fn (ctx: *anyopaque, loudness: u32) anyerror!void,
      };
  
      // call the derived struct's implementation
      pub fn make_noise(animal: Animal, loudness: u32) anyerror!void {
          return animal.vtable.make_noise(animal.ctx, loudness);
      }
  };
  
  const Dog = struct {
      // extra data
      weight: u32,
  
      // implement the interface
      const vtable = Animal.VTable{
          .make_noise = &make_noise,
      };
  
      pub fn make_noise(ctx: *anyopaque, loudness: u32) anyerror!void {
          const dog: *Dog = @alignCast(@ptrCast(ctx));
          std.debug.print("woof {} {}\n", .{ dog.weight, loudness });
      }
  
      // helper to convert to the base struct
      pub fn _animal(self: *Dog) Animal {
          return Animal{
              .ctx = @ptrCast(self),
              .vtable = &vtable,
          };
      }
  };
  
  const Cat = struct {
      weight: u32,
  
      const vtable = Animal.VTable{
          .make_noise = &make_noise,
      };
  
      pub fn _animal(self: *Cat) Animal {
          return Animal{
              .ctx = @ptrCast(self),
              .vtable = &vtable,
          };
      }
  
      pub fn make_noise(ctx: *anyopaque, loudness: u32) anyerror!void {
          const cat: *Cat = @alignCast(@ptrCast(ctx));
          std.debug.print("meow {} {}\n", .{ cat.weight, loudness });
      }
  };
  
  pub fn main() !void {
      var gpa = std.heap.GeneralPurposeAllocator(.{}){};
      const alloc = gpa.allocator();
  
      // list of base structs
      var animal_list = std.ArrayList(Animal).init(alloc);
      defer {
          for (animal_list.items) |animal| {
              if (animal.vtable == &Dog.vtable) {
                  const dog: *Dog = @alignCast(@ptrCast(animal.ctx));
                  alloc.destroy(dog);
              } else if (animal.vtable == &Cat.vtable) {
                  const cat: *Cat = @alignCast(@ptrCast(animal.ctx));
                  alloc.destroy(cat);
              }
          }
          animal_list.deinit();
      }
  
      for (0..20) |i| {
          if (i % 2 == 0) {
              var dog = try alloc.create(Dog);
              dog.* = Dog{ .weight = @intCast(i) };
              try animal_list.append(dog._animal());
          } else {
              var cat = try alloc.create(Cat);
              cat.* = Cat{ .weight = @intCast(i) };
              try animal_list.append(cat._animal());
          }
      }
  
      // meows and woofs here
      for (animal_list.items) |animal| {
          try animal.make_noise(10);
      }
  }
ive written a couple and still find them mindbendy

You can just used tagged enums and the inline else syntax, like this:

  const Animal = union(enum) {
      cat: Cat,
      dog: Dog,

      pub fn make_noise(self: Animal) void {
          switch (self) {
              inline else => |impl| impl.make_noise(),
          }
      }
  };

iirc there's multiple idioms that are used in different cases. i recall a nice github that laid them all out with use cases but I can't find it

I'm not sure what interface means but virtual table in C++ apparently for inheritance, virtual function, and polymorphism (which is a spell or something

The rest of OOP is lipstick on arrays and arrays of arrays and "structs / records" or software defined arrays.

In my opinion.


Should we stop caring about all the amendments or just the ones you don't like?

> last click attribution comes into play

Thats an extremely generous way to say that they steal referrals from genuine affiliate partners.


I agree it's a problem. I believe the affiliate networks should switch to first-click or multi-click attribution. Problem solved.


Half the time I try to use gemini questions about the c++ std library, it fabricates non-existent types and functions. I'm honestly impressed it was able to solve any of the AoC problems.


I’ve had a side job as an external examiner for CS students for almost a decade now. While LLMs are generally terrible at programming (in my experience) they excel at passing finals. If I were to guess it’s likely a combination of the relatively simple (or perhaps isolated is a better word) tasks coupled with how many times similar problems have been solved before in the available training data. Somewhat ironically the easiest way to spot students who “cheat” is when the code is great. Being an external examiner, meaning that I have a full time job in software development I personally find it sort of silly when students aren’t allowed to use a calculator. I guess changing the way you teach and test is a massive undertaking though, so right now we just pretend LLMs aren’t being used by basically every students. Luckily I’m not part of the “spot the cheater” process, so I can just judge them based on how well they can explain their code.

Anyway, I’m not at all surprised that they can handle AoC. If anything I would worry that AoC will still be a fun project to author when many people solve it with AI. It sure won’t be fun to curate any form of leaderboard.


leetoced/AoC-like problems are probably the easiest class of software related tasks LLMs can do. Using the correct library, the correct way, at the correct version, especially if the library has some level of churn and isn't extremely common, can be a harder task for LLMs than the hardest AoC problems.


Well I guess your book needs a new edition. The type of gui you're referencing is typically referred to as a retained mode gui.


The point is, I don't want people to see "GUI library" and think it's okay to use this for your random phase-of-the moon application that has no good reason to redraw at 2400 fps or whatever the enthusiasts want these days.


Just click on the link and you can easily see it only redraws when something on the screen changes. It's amazing how quickly people will dismiss something these days based on their own made up reasons.


The poster above me explained to me that it's not like that?


Click the link, open the backend tab, and look where it says "Only running UI code when there are animations or input."

Then you won't have to waste cycles deciding which random internet comment from a stranger to believe


If you set up "winit" so it only redraws on events, then you don't trigger an EGUI redraw very often. But if updates that affect the EGUI items are coming in from another source, like the network, you have to explicitly trigger a winit redraw cycle.

Don't know about web. Seems overkill if all you have are GUI widgets. Egui is most useful on top of something more graphical.

Scrolling text is a problem. EGUI isn't good at big text boxes with much offscreen text. That can be worked around.


You don't have to use any of that and you still get lots of nice things like range based for loops, STL containers, algorithms, namespaces, and constexpr.


I learned c++ after c++20 and after several attempts to enjoy rust, c#, go, and C, I always come back to c++ as the most enjoyable language to develop.


Nice! If you blog at all your perspective would be super interesting to hear.


"if you don't let people steal your stuff you're not a real man!"

That was awfully presumptuous and condescending. I think the people advocating we let thieves take our things are the ones who need some updates.

Ad hominem attacks aside, you're presenting a false dichotomy. There is nothing mutually exclusive about analysis and violence.


You made up a fake quote to respond to. What's the point of that?

> There is nothing mutually exclusive about analysis and violence.

Of course not. That's just the hypothetical presented here, though. The post I replied to argued that it is better to be both stupid and violent rather than smart when it comes to protecting dignity. Of course there are cases where it's smart to be violent (and stupid to use analysis, for that matter).


> MoonBit is still in beta-preview. Introducing forks at this point could risk destabilizing the project. We aim to reach a more mature and stable status before welcoming community contributions.

> We want to safeguard against large cloud vendors leveraging our work for commercial purposes in a way that could undermine our efforts.

Normally I don't like the "technically not open source" comments, but this isn't even remotely open source.

The language looks like rust with some interesting type/generic fun added in. Not sure I like the syntax but it looks like a very expressive language.


GP is right. If the words public static keep you from learning how to program you were never going to learn anyway. If I introduce someone to soccer and they quit because they couldn't figure out how to put their shoes on, chances are they werent going to learn how to play no matter what.


I think the converse(?) to this though is that the words public static are inconsequential.

Sure, if you are incapable of learning what a couple adjectives mean you won't go far, but that holds for much more than software.

Rather it's not important that the ball is big and blue so much as that you can kick it across the field - learning what the ball means can come later, but it's just unimportant noise (to start).

Java is pretty bad at this, though, insisting on specifying unimportant details up front rather than allowing for qualification. This is OK for a large monolithic application with complex requirements and a litany of edge cases, but inappropriate for many smaller use cases.


Did you know that the first thing John Wooden did with incoming freshman collegiate basketball players at the most prestigious program in the country was teach them how to properly put on their socks?


Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: