How a basic usage of, for example, an ArrayList
would look like with inlining? For example, imagine a function that creates an ArrayList
, resizes it, fills it in a loop and returns it.
pub export fn foo1() *anyopaque {
const size: u8 = 32;
var buffer: [size]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
var arr = @call(.always_inline, std.ArrayList(u8).init, .{ allocator });
@call(.always_inline, std.ArrayList(u8).resize, .{ &arr, size }) catch unreachable;
for (0..size) |i| {
arr.items[i] = @intCast(i);
}
// ensure that arr is not optimized away
return &arr;
}
It does not look great, imagine there are more ArrayList
functions and all of them have to be wrapped into @call
. And if you forgot to do it, you won’t be notified by the compiler.
But what if a function foo2
takes an Allocator
as a parameter? What the author of this function should do? @call(.always_inline)
every ArrayList
function? It would help only if foo2
itself is inlined. But the author of the function can’t control that.
Personally, I don’t want to specify inlining frequently, because it may hurt perfromance. I want to rely on compiler for that.
That’s why I believe that the approach of @LucasSantos91 is better. Static polymorphism is a more basic building block than dynamic polymorhphism, because you can get latter from the former (by passing std.mem.Allocator
as a comptime Allocator
argument), but not vice versa. Advantages:
- you don’t have to remember to wrap function calls with
@call(.always_inline)
; - you let the compiler to decide what functions should be inlined;
- it gives more possibilities to the user (the user may decide whether they want to pass a concrete allocator or the interface
std.mem.Allocator
).
Disadvantages stem from the fact that it is harder to use.
- The user has to understand whether to pass their
ConcreteAllocator
or*ConcreteAllocator
. I don’t know how to improve it properly. - It may lead to code bloat if used extensively. It may be fixed by passing
std.mem.Allocator
on call sites (the user decides where exactly they want to do that). - Duck typing with
anytype
. I believe it should be solved by something likeconcept
s from C++.