News for hackers. Stuff that matters.
Re:Zig, Skia, Clojure, Geometry and the Japanese TV Show: IC... by majormajor on Thursday July 15, 2021 @05:27PM (#27850349)
Defer sounds like a nice improvement over old old languages, but Java's try-with-resources is one of the nicer ways of handling resource cleanup I've seen in a "mainstream" language, it's fairly neat and conceptually similar to some stuff I've seen done with lisp macros or Ruby blocks. It seems like defer is still lacking compared to this.
Re:Zig, Skia, Clojure, Geometry and the Japanese TV Show: IC... by ptrwis on Thursday July 15, 2021 @08:23PM (#27851766)
With defer it's developer's responsibility to free resources in right order, when one depends on another. Maybe something like this in Zig would be better:

  try std.fs.cwd().openFile(path, .{}) |file| : file.close()
  {
    // ... code ...
    // file.close() is called at the end
  }
Re:Zig, Skia, Clojure, Geometry and the Japanese TV Show: IC... by dinglejungle on Thursday July 15, 2021 @08:35PM (#27851836)
defer in Zig is per-scope, so

    {
        var file = try std.fs.cwd().openFile(path, .{});
        defer file.close();

        // ... code ...
        // file.close() is executed here
    }
would work just fine.
Re:Zig, Skia, Clojure, Geometry and the Japanese TV Show: IC... by ptrwis on Thursday July 15, 2021 @10:01PM (#27852323)
Yes, but look at the example in the blog post of this thread- "stat" depends on "file", "file" depends on "path". You can call defer in any order in your code, the language syntactically doesn't enforce you to call defer right after resource acquisition. "try-with-resources" in Java (or "using" in c#) will always call "finalizers" in order opposite to how resources where created. Following the syntax I inveted above, for someone used to Java it would be easier to read than to think how defers are called:

  try std.fmt.allocPrint(allocator, "problems/{}", .{ id }) |path| : allocator.free(path) {
    try std.fs.cwd().openFile(path, .{}) |file| : file.close() {
      try file.stat() |stat| {
        try allocator.alloc(u8, stat.size) |contents| : allocator.free(contents) {
          // do something with 'contents'
        }
      }
    }
  }
In Zig you can write this, and mess everything up:

  const path = try std.fmt.allocPrint(allocator, "problems/{}", .{ id });
  var file = try std.fs.cwd().openFile(path, .{});
  const stat = try file.stat();
  var contents = try allocator.alloc(u8, stat.size);
  defer allocator.free(contents);
  defer file.close();
  defer allocator.free(path);
Re:Zig, Skia, Clojure, Geometry and the Japanese TV Show: IC... by dnautics on Friday July 16, 2021 @12:29AM (#27853058)
That's what errdefer is for.