The removal of usingnamespace I think is a net good. However, I think there may have been a misunderstanding in the removal.
The changelog, as well as a lot of the justifications for removing usingnamespace, says that there’s an alternative way to implement mixins. However, the mixin shown in all of the examples I’ve seen in migration (that CounterMixin one) doesn’t actually address the core reason that I’ve loved the mixin pattern: automatic implementation of “standard interfaces”.
Specifically, I have a mixin named PackedFlagsMixin(T) which implements the format, jsonStringify, jsonParse, and jsonParseFromValue methods for a given type. For now I can work around the removal of mixins by doing the following:
pub const MyBitFlags = packed struct {
foo: bool = false,
bar: bool = false,
baz: bool = false,
const Mixin = PackedFlagsMixin(@This());
pub const format = Mixin.format;
pub const jsonStringify = Mixin.jsonStringify;
pub const jsonParse = Mixin.jsonParse;
pub const jsonParseFromValue = Mixin.jsonParseFromValue;
}
I recognize that verbosity can be good, but this can start to get ridiculous when you also want to start implementing things like format and others.
But perhaps, we could have something like the following:
pub const MyBitFlags = packed struct {
foo: bool = false,
bar: bool = false,
baz: bool = false,
pub const Fmt = PackedFlagsFmt(@This());
pub const Json = PackedFlagsJson(@This());
}
which would be short for something like
pub const MyBitFlags = packed struct {
foo: bool = false,
bar: bool = false,
baz: bool = false,
pub const Fmt = struct {
pub fn format(self: MyBitFlags, writer: *std.Io.Writer) !void { ... }
};
pub const Json = struct {
pub fn stringify(self: MyBitFlags, jsonWriter: anytype) !void { ... }
pub fn parse(alloc: std.mem.Allocator, source: anytype, options: std.json.ParseOptions) !MyBitFlags { ... }
pub fn parseFromValue(alloc: std.mem.Allocator, source: std.json.Value, options: std.json.ParseOptions) !MyBitFlags { ... }
};
}
This would make implementing interfaces much easier IMO. This also has some other miscellaneous DX benefits:
- It’s easy to tell what a function is meant for, since it’s namespaced by the struct name (i.e.
formatnow has an explicit tie-in to thefmtpackage) - They are no longer methods, since they don’t take the same struct as a parameter. This is a hint to callers that these functions are not meant to be directly called outside of the library functions that are meant to call them.
- The functions are now indented, offering additional visual clarity that these methods are meant to specifically be called by the
fmt/json/etc library fucntions.