I noticed that a library I'm using frequently returns []const u8 instead of []u8 when it allocates memory and the caller is responsible for freeing it.
Should a function return a mutable slice []u8
when the data is owned by the caller and must be freed?
fn prefixString(
allocator: std.mem.Allocator,
string: []const u8,
prefix: []const u8
) ![]u8 {
return std.mem.concat(allocator, u8, &[_][]const u8{ prefix, string });
}
Here, prefixString returns a mutable slice of bytes, just like its underlying function, std.mem.concat
.
While it can be argued that it all depends on the design decisions of the library developers, it's indeed better to return []T
instead of []const T
when the caller owns the memory and needs to free it.
The const
provides a way to express restrictions in the API, that can protect against certain errors.
But in this case, the restriction isn't real, and the library users may have to cast away the const
to archive their goals.