HeadlinesBriefing HeadlinesBriefing.com

Traits in Zig: A Compile-Time Abstraction

Hacker News •
×

I have had more time recently to write code in Zig, and it has been good for my soul. This piece shares insights on abstractions in Zig, including techniques the author has found useful but rarely seen employed more broadly. Considerable ink has been spilled on Zig interfaces, and justifiably so. While not a language feature, interfaces are the de facto way of implementing runtime polymorphism in Zig. More has been said about Zig's comptime and how it may be leveraged to avoid the performance woes of dynamic dispatch and write slick, data-oriented code.

Polymorphism in Zig is conventionally obtained in one of two ways. Dynamic interfaces use opaque pointers, virtual tables, and dynamic dispatch to achieve runtime polymorphism. Comptime duck typing uses type reflection, switch statements, and monomorphism at compile time to achieve static polymorphism. This state of affairs has proven effective, but it is not without tradeoffs. Interfaces offer type contracts familiar from other languages, but because they are modular at runtime, they introduce a hard barrier for the compiler and thus a performance overhead. For performance-critical code, Zig typically relies on comptime duck typing, which catches interface violations at compile time but still requires careful documentation of the contract.

Developers coming from Rust's traits or Haskell typeclasses may find this arrangement simplistic, and Zig does aim to be simple. The author argues that, with a little adaptation, similar abstractions over types are possible in Zig userland. The proposal is a new convention for defining compile-time type contracts as Traits, requiring no libraries or machinery. It is inspired by functional programming in general and OCaml in particular.

A Trait is defined as a compile-time struct containing related functions over a given type. The article illustrates this with a Reducer trait for folding, where a type forms a reducer under an empty value and a combine operation. Separate sum and product traits for i32 show how the same generic reduce logic can be reused, with the compiler able to inline and unroll the loop. The author concludes that traits are simply bags of fun.

Source: Hacker News · Summarized by HeadlinesBriefing