I deeply miss C++ templates in most other languages, excepting fully dynamic languages, and D.
Have you tried Zig? Comptime templating it one of its selling points.
Have you tried Zig? Comptime templating it one of its selling points.
As far as C replacements go, Zig has my vote for the most approachable but also the most well thought-out. I couldn't sing its praises enough.
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 var 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.https://en.wikipedia.org/wiki/Resource_acquisition_is_initia...
Regarding errors in a C++ constructor: https://isocpp.org/wiki/faq/exceptions#ctors-can-throw