3 ms·
Speaking from extremely limited Zig experience here: I think some of these downsides will get clearer over time as Zig becomes more popular. Classic C++ issues
by oconnor663 4y ago
Speaking from extremely limited Zig experience here: I think some of these downsides will get clearer over time as Zig becomes more popular. Classic C++ issues like "wtf does this 500-line compiler error mean" aren't a big deal when you're working on programs that are entirely written by you. You probably know what you did wrong, and what you expected yourself to do instead. It's when you have large applications maintained by rotating teams of programmers, or big open-source library ecosystems where everyone is using tons of other people's code, where it starts to be a bigger problem, especially for beginners.
One concrete way this stood out to me is that I don't think Zig has any way to say "this function should take a Writer". (I.e. a File or a Socket or something you can stream bytes into.) Zig does have a Writer abstraction in the standard library, which takes a basic write function and provides lots of helper methods like writeAll. However, the Writer abstraction gives you a new struct type, and while you could write a function that takes a specific type of Writer, I don't think there's any way to say "any Writer". Instead you usually have to take "anytype".
I think things like the Writer interface in Go or the Write trait in Rust are very powerful and useful for organizing an ecosystem of libraries that all want to interoperate. This might be something Zig struggles with in the future. On the other hand, a lot of Zig's design seems targeted at use cases where you don't necessarily want to call lots of library code (which for example might be allocating who-knows-how-much memory from who-knows-where). In use cases like kernel modules and firmware, there might be an argument that making lots of fancy abstractions isn't the best way to go about things. I'd love to hear more about this from more knowledgeable Zig folks.
- programmer_dude 4y ago> don't necessarily want to call lots of library code Makes sense since Zig is meant to be a replacement for C and "C is NOT a modular language! The best way to use C is to roll your own (or copy and paste) data structures for your problem, not try to use canned ones!" from a comment here: https://news.ycombinator.com/item?id=33130533 https://news.ycombinator.com/item?id=33130533 Edit: I call this misfeature of the C language the "polluted/busy call site syndrome".
- paoda 4y agoThis may be the case with the current Zig ecosystem (even then, two community-created package mangers already exist), but my understanding is that at some point, Zig will receive an official package manager. The current build system and type system go a long way to encourage library use (since it's quite easy) and the future package manager will be yet another step towards that.
- programmer_dude 4y ago> The current build system and type system go a long way to encourage library use I have zero experience with Zig but this contradicts what the other poster in this thread said. Not sure what to make of this.
- paoda 4y agoOh that's fair. Zig makes a big deal about ensuring that "what you're supposed" to do is the simplest/easiest option at your disposal. In service of this, even in Zig's current pre-1.0 state, adding a library can be as simple as something like the following in your project's build.zig: // Argument Parsing Library exe.addPackagePath("clap", "lib/zig-clap/clap.zig"); This and the language just having generics (which isn't necessarily the goal of all c-replacement languages i recently found out) suggests to me that the language as it currently stands encourages libraries to be written and reused. In Zig, allocators are "just another argument", functionally an interface so as a library author you have to pay less attention to whether your library can be used in hostile environments. I'm quite sure this idiom exists primarily to just make Zig libraries (like the stdlib) useful in more places. Certainly, Zig doesn't have all the tools you'd expect in other languages to aid library authors and consumers. I personally would love to see proper interfaces in the language, rather than the interface-by-convention situation we have right now. It's a matter of tradeoffs, many of which I imagine will be addressed and reconsidered as the language matures.
- hansvm 4y ago> doesn't have any way to say "this function should take a Writer" AFAIK there isn't any dedicated pretty syntax, but there are plenty of solutions that aren't too painful. They all rely on the fact that you're not generating a "new" struct with each call -- comptime function calls assume that the same inputs will yield the same outputs and cache the results to enforce that behavior, so if you call Writer(foo) in two different places you get the _exact_ same struct in both places. One option would be to instantiate the Writer type just as you would dependent generics in any other language. fn foo(comptime writerFn: anytype, comptime WriterT: Writer(writerFn), writer: WriterT) Another option would be to just check the type at comptime. You're able to throw custom error messages during compilation, and comptime code doesn't add runtime overhead of any sort. fn foo(writer: anytype) !void { checkWriterT(@TypeOf(writer)) } For completeness, it's worth noting that the correct behavior for strings and more complicated objects is still AFAIK a subject of debate with respect to comptime caching. It should have some nice solution by 1.0 in a few years, but for primitives like functions and types you should have no issues with either of the two above approaches.
- flohofwoe 4y ago> this function should take a Writer I think some of this can be achieved in the function body by checking the incoming generic types via Zig's comptime type inspection features (see: https://ziglang.org/documentation/master/#typeInfo https://ziglang.org/documentation/master/#typeInfo). Kinda like 'comptime type-asserts'. Together with @compileError this would at least provide more useful error messages if a generic type doesn't have the expected features. PS: I think it's important to not look at Zig's generic feature in isolation, instead it goes hand in hand with comptime and reflection.
- Ar-Curunir 4y agoHow do you query if the type implements a particular method?
- flohofwoe 4y agoThere's a std.meta.trait.hasFn() comptime helper function in the stdlib: https://www.godbolt.org/z/xe98Md74r https://www.godbolt.org/z/xe98Md74r E.g. if you change the method 'bla' to something else: https://www.godbolt.org/z/77118zG1K https://www.godbolt.org/z/77118zG1K ...there's probably more advanced helper functions in the same std.meta.trait module, I haven't explored that yet. Also, disclaimer: I haven't dabbled much yet with Zig generics, don't know if this is the proper style (in this case it's probably better to get rid of T entirely and just use anytype for the obj argument).