Hacker News new | past | comments | ask | show | jobs | submit login

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
  }



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.


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);


That's what errdefer is for.




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

Search: