So for background I’ve been using zig since ~0.12 but I’ve only recently really dug into the comptime/metaprogramming features. Whenever I’ve had to use anytype (or like an inline for that calls the same fn/access the same field, that sort of thing), I get a bad taste in my mouth. It feels like every implicit contract I add is going to make retracing my steps later that much harder. Maybe that’s just the trade-off, but my question is:
Does anyone have examples of strategies/design patterns I’m missing out on that can help narrow anytype/make it more explicit? For now I’m just trying to add good comments and putting in a few @compileErrors.
My main advice would be to only use it, if it is actually required, so if an explicitly declared struct or tagged union type would work to model the parameter then use that, instead of using anytype out of laziness.
Then when you do use it, make sure you have doc tests of the function (test functionName {...}) that demonstrate all the possible usecases, that way you have both testing and usage examples showing up in the documentation / making sure the intended api is documented and that it remains supported with future changes.
Yea my current project is using a good amount of anytype + interfaces and I’m leaning into interfaces as much as possible. Anytype has kinda been the escape hatch for things I can’t represent otherwise
I found that anytype is suitable for expecting a tuple where the length of properties is runtime-known or variable (std.debug.print) while type is good for generics parameters, e.g., std.mem.find, to build a reusable library.
At startup an array of different function pointers is assembled based on runtime parameters. The function to turn all these many structs into this interface (literally just looping through every decl and calling toInterface()) is accomplished through an inline for loop/anytype situation, but everything from then on uses the interface. It’s surely possible to do the same thing without an interface (it’s already halfway there) but this seemed like the right place to draw the boundary