News for hackers. Stuff that matters.
Re:Zig-style generics are not well-suited for most languages by programmer_dude on Sunday October 09, 2022 @02:42PM (#33144031)
> This post is meant to discuss reasons why Zig-style generics are not well-suited for languages other than Zig.

> Limited compiler support when calling generic code

> Limited compiler support when writing generic code

> Limited type inference

> Cannot distribute binary-only libraries with generic interfaces

> Tooling needs to do more work

> Inability to have non-determinism at compile time

> Inability to support polymorphic recursion

Why are these things not a problem in Zig?

Re:Zig-style generics are not well-suited for most languages by oconnor663 on Sunday October 09, 2022 @03:15PM (#33144297)
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 as 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.

Re:Zig-style generics are not well-suited for most languages by programmer_dude on Sunday October 09, 2022 @03:22PM (#33144351)
> 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

Edit: I call this misfeature of the C language the "polluted/busy call site syndrome".

Re:Zig-style generics are not well-suited for most languages by paoda on Sunday October 09, 2022 @03:50PM (#33144575)
This 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.

Re:Zig-style generics are not well-suited for most languages by programmer_dude on Sunday October 09, 2022 @04:01PM (#33144682)
> 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.

Re:Zig-style generics are not well-suited for most languages by paoda on Sunday October 09, 2022 @05:12PM (#33145405)
Oh 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.

Re:Zig-style generics are not well-suited for most languages by hansvm on Sunday October 09, 2022 @05:15PM (#33145417)
> 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.

Re:Zig-style generics are not well-suited for most languages by flohofwoe on Monday October 10, 2022 @06:55AM (#33149901)
> 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). 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.

Re:Zig-style generics are not well-suited for most languages by Ar-Curunir on Monday October 10, 2022 @12:59PM (#33153782)
How do you query if the type implements a particular method?
Re:Zig-style generics are not well-suited for most languages by flohofwoe on Monday October 10, 2022 @03:55PM (#33155752)
There's a std.meta.trait.hasFn() comptime helper function in the stdlib:

https://www.godbolt.org/z/xe98Md74r

E.g. if you change the method 'bla' to something else:

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).

Re:Zig-style generics are not well-suited for most languages by lifthrasiir on Sunday October 09, 2022 @03:12PM (#33144270)
They are called trade-offs. They are still a problem in Zig but the language is designed to work around them. If your language doesn't work around them you will suffer a lot more from those problems. If your language works around them it is basically Zig but less polished and far less used.
Re:Zig-style generics are not well-suited for most languages by flohofwoe on Monday October 10, 2022 @06:50AM (#33149872)
Because in typical Zig code, generics are often used to solve relatively basic problems, and not to play code golf. For instance, if you just want to write a container for a generic type T you don't need any advanced features.

Also, quite a few problems where people would reach for template code in C++ can be solved much easier in Zig with a combination of regular comptime code and only some 'generic typing' sprinkled over.