Defer
If you are coming from the C world, the defer
keyword might surprise you and greatly impact your life, if you already know it from other languages like Go, bear with us to see how it is particulary useful in a language that has to manage its own memory.
defer is a really simple keyword all it does is: execute code at the end of the current scope.
Might not sound like much, because you might think "I could just put it at the of my scope", you are not entirely wrong but:
- Doing so makes your code less readable/understandable, because you have to scroll to the end of the function to find the code you might need that is related something hundred of lines above.
- Humans are prone to error and sometimes forget things. By instantly adding a defer after the related code you can be sure not to forget it later.
- When having to modify an old codebase, it is very hard to know or remember where deallocations are made, having the defer keyword give the possiblity to most of the time have the deallocation next to the allocation.
Exemple
In this exemple, the use of the defer
keyword really shines.
Here the programmer forgot to free the memory assigned to ptr_cool_number
by calling destroy. Memeory leaks like that could be hard to find in a large codebase because you would have to check every single allocation and find its corresponding free somewhere in the code.
test "we sometime forget to free memory" {
const allocator = std.testing.allocator; // Allocator that detect memory leaks
const bytes = try allocator.alloc(u64, 10);
for (0..9) |i| {
bytes[i] = i;
}
// ... lot of code normally here :)
const ptr_cool_number = try allocator.create(u64);
ptr_cool_number.* = bytes[2];
//allocator.destroy(ptr_cool_number);
allocator.free(bytes);
}
But this could be improved by using the defer
keyword and writing the dealloaction code right after the allocation one. This way if you have a memory leak, you just have to see everywhere you allocated and be sure there is a deallocation next to it.
test "and sometimes we just use defer and life is better" {
const allocator = std.testing.allocator; // Allocator that detect memory leaks
const bytes = try allocator.alloc(u64, 10);
defer allocator.free(bytes);
for (0..9) |i| {
bytes[i] = i;
}
const ptr_cool_number = try allocator.create(u64);
defer allocator.destroy(ptr_cool_number);
ptr_cool_number.* = bytes[2];
}