3 ms·
RAII works fine in Zig
by AndyKelley 5y ago
RAII works fine in Zig
- lenkite 5y agoNo it doesn't. https://github.com/ziglang/zig/issues/782 https://github.com/ziglang/zig/issues/782
- AndyKelley 5y agoshow me a raii code example in C++ and I'll show you the zig equivalent
- lenkite 5y agoNote that in `good` below, one can have many such lock guards: lk1, lk2, etc without any explicit lock release expression in the body of the function. std::mutex m; void good() { std::lock_guard<std::mutex> lk(m); // RAII class: mutex acquisition is initialization f(); // if f() throws an exception, the mutex is released if(!everything_ok()) return; // early return, the mutex is released } // if good() returns normally, the mutex is released
- AndyKelley 5y agovar m: std.Thread.Mutex = .{}; fn good() !void { m.lock(); defer m.unlock(); try f(); if (!everything_ok()) return; } It's still the RAII pattern. The explicit call to deinitialization does not disqualify it. I can overcomplicate it with a LockGuard class too: const LockGuard = struct { mutex: *std.Thread.Mutex, fn init(mutex: *std.Thread.Mutex) !LockGuard { mutex.lock(); return .{ .mutex = mutex, }; } fn deinit(lg: *LockGuard) void { lg.mutex.unlock(); } }; fn good() !void { var lk = try LockGuard.init(&m); defer lk.deinit(); try f(); if (!everything_ok()) return; } In this case it demonstrates an improvement over C++, which is what happens if an error happens during a constructor. In C++ throwing an exception in a constructor is essentially UB; in zig it's a regular function call just like anything else.
- lenkite 5y agoThanks for the informative snippet, but explicit expressions involving defer is not what RAII means. In RAII resource is automatically tied to object lifetime. https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization https://en.wikipedia.org/wiki/Resource_acquisition_is_initia... Regarding errors in a C++ constructor: https://isocpp.org/wiki/faq/exceptions#ctors-can-throw https://isocpp.org/wiki/faq/exceptions#ctors-can-throw