Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. Y'all knew I was gonna talk about it.

Y'all knew I was gonna talk about it.

Scheduled Pinned Locked Moved The Lounge
testingcomadobedata-structuresbeta-testing
3 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    Jeremy Falcon
    wrote on last edited by
    #1

    So ya know... that Zig thing. As we all know, in a non-GC language, if you wanna return a non-literal string from a function that bad boy needs to go on the heap. And in the lovely land of C that means the caller is responsible for freeing it up yo. Now, Zig doesn't have a concept of a borrow checker like Rust, but what it does enforce is that you use allocators since there's no global one. These allocators keep track of what's going in and out of it. So, it's a tiny bit of overhead, but essentially you get a memory air traffic controller as the trade off. And if the air traffic doesn't like what you just did, it be like no bueno hoss. BEHOLD! This use case. Zig doesn't have localization yet, so I have to interop with C. Ok, cool, which means I'm gonna wrap `snprintf` and return a string from that wrapper... on the heap. Dun dun dun. Plot thickens.

    const c = @cImport({
    @cInclude("locale.h");
    @cInclude("stdio.h");
    });

    // ...

    pub fn formatNumber(ally: std.mem.Allocator, number: u64) ![]u8 {
    // max is 18,446,744,073,709,551,615 (a 20 digit number with 6 commas)
    // but allow up to two chars per separator for anything non-standard
    var buff = [_]u8{0} ** 33; // 32 + 1 for terminator

    // %'8.2f for floats or lld for signed
    \_ = c.setlocale(c.LC\_NUMERIC, "");
    const n = c.snprintf(&buff, 33, "%'llu", number);
    
    const len: usize = @intCast(n);
    const result = buff\[0..len\];
    
    return try ally.dupe(u8, result);
    

    }

    Ok, C interop I already talked about. But, here's the cool part. Notice in the `return` I allocate on the heap with the passed in allocator (the idiomatic way so the caller can choose which allocator they want) by duplicating the stack buffer used during the C interop. Cool cool cool, nothing out of the normal yet! Here's the cool part. In a unit test for it:

    test "formatNumber should work with the max 64-bit unsigned integer size" {
    const ally = std.testing.allocator;
    const result = try formatNumber(ally, 18_446_744_073_709_551_615);
    defer ally.free(result);

    try std.testing.expect(std.mem.eql(u8, result, "18,446,744,073,709,551,615"));
    

    }

    Notice the `defer` line. If I forget it I literally get a compiler error because this particular allocator requires an explicit free (not all do). But, it's a compiler error if you forget it! I mean, don't get me wrong, I'm sure a good linter can handle some of this. But, it's baked right into the compiler to say "nah bruh dat whack". Ed

    D 1 Reply Last reply
    0
    • J Jeremy Falcon

      So ya know... that Zig thing. As we all know, in a non-GC language, if you wanna return a non-literal string from a function that bad boy needs to go on the heap. And in the lovely land of C that means the caller is responsible for freeing it up yo. Now, Zig doesn't have a concept of a borrow checker like Rust, but what it does enforce is that you use allocators since there's no global one. These allocators keep track of what's going in and out of it. So, it's a tiny bit of overhead, but essentially you get a memory air traffic controller as the trade off. And if the air traffic doesn't like what you just did, it be like no bueno hoss. BEHOLD! This use case. Zig doesn't have localization yet, so I have to interop with C. Ok, cool, which means I'm gonna wrap `snprintf` and return a string from that wrapper... on the heap. Dun dun dun. Plot thickens.

      const c = @cImport({
      @cInclude("locale.h");
      @cInclude("stdio.h");
      });

      // ...

      pub fn formatNumber(ally: std.mem.Allocator, number: u64) ![]u8 {
      // max is 18,446,744,073,709,551,615 (a 20 digit number with 6 commas)
      // but allow up to two chars per separator for anything non-standard
      var buff = [_]u8{0} ** 33; // 32 + 1 for terminator

      // %'8.2f for floats or lld for signed
      \_ = c.setlocale(c.LC\_NUMERIC, "");
      const n = c.snprintf(&buff, 33, "%'llu", number);
      
      const len: usize = @intCast(n);
      const result = buff\[0..len\];
      
      return try ally.dupe(u8, result);
      

      }

      Ok, C interop I already talked about. But, here's the cool part. Notice in the `return` I allocate on the heap with the passed in allocator (the idiomatic way so the caller can choose which allocator they want) by duplicating the stack buffer used during the C interop. Cool cool cool, nothing out of the normal yet! Here's the cool part. In a unit test for it:

      test "formatNumber should work with the max 64-bit unsigned integer size" {
      const ally = std.testing.allocator;
      const result = try formatNumber(ally, 18_446_744_073_709_551_615);
      defer ally.free(result);

      try std.testing.expect(std.mem.eql(u8, result, "18,446,744,073,709,551,615"));
      

      }

      Notice the `defer` line. If I forget it I literally get a compiler error because this particular allocator requires an explicit free (not all do). But, it's a compiler error if you forget it! I mean, don't get me wrong, I'm sure a good linter can handle some of this. But, it's baked right into the compiler to say "nah bruh dat whack". Ed

      D Offline
      D Offline
      dandy72
      wrote on last edited by
      #2

      Jeremy Falcon wrote:

      compiler to say "nah bruh dat whack".

      Suddenly I want VS to show error messages like that. It would be more useful than some of the messages I've seen.

      J 1 Reply Last reply
      0
      • D dandy72

        Jeremy Falcon wrote:

        compiler to say "nah bruh dat whack".

        Suddenly I want VS to show error messages like that. It would be more useful than some of the messages I've seen.

        J Offline
        J Offline
        Jeremy Falcon
        wrote on last edited by
        #3

        dandy72 wrote:

        It would be more useful than some of the messages I've seen.

        Amen, buddy. :laugh:

        Jeremy Falcon

        1 Reply Last reply
        0
        Reply
        • Reply as topic
        Log in to reply
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes


        • Login

        • Don't have an account? Register

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • World
        • Users
        • Groups