I’m wondering if anyone else feels that API’s that include a comptime T: type
parameter can be a bit redundant.
For example, consider the following function that uses this functionality, this function takes a packed struct and converts it to bytes in the proper order for a binary protocol:
const std = @import("std");
const native_endian = @import("builtin").target.cpu.arch.endian();
/// convert a packed struct to bytes that can be sent via ethercat
///
/// the packed struct must have bitwidth that is a multiple of 8
pub fn pack_to_ecat(comptime T: type, packed_struct: T) [@divExact(@bitSizeOf(T), 8)]u8 {
comptime std.debug.assert(@typeInfo(T).Struct.layout == .@"packed"); // must be a packed struct
var bytes: [@divExact(@bitSizeOf(T), 8)]u8 = undefined;
switch (native_endian) {
.little => {
bytes = @bitCast(packed_struct);
},
.big => {
bytes = @bitCast(packed_struct);
std.mem.reverse(u8, &bytes);
},
}
return bytes;
}
Now at the callsite I must write:
test "pack_to_ecat" {
const Command = packed struct(u8) {
flag: bool = true,
reserved: u7 = 0,
};
try std.testing.expectEqual(
[_]u8{1},
pack_to_ecat(Command, Command{}),
);
}
This feels like I am asserting that the second argument Command{}
has type Command
, but I don’t care what type the arguments are, that’s why I made it a generic.
Generally, I want to use the full features of a language to express my intent, and my intent is to not care about the type, which pushes me towards this at the call site:
const my_command = Command{};
_ = pack_to_ecat(@TypeOf(my_command), my_command);
But now I’m just thinking, the compiler knows the type already for me, why should I have to say it!