i dont think its generally a good idea to be making complex type generators like this in zig. just write the type out.
the annoyingness of the thing you tried to do in zig is a feature. its a "don't do this, you will confuse the reader" signal. as for optional, its a pattern that is so common that it's worth having builtin optimizations, for example @sizeOf(*T) == @sizeOf(usize) but @sizeOf(?*T) != @sizeOf(?usize). if optional were a general sum type you wouldn't be able to make these optimizations easily without extra information
The point is that algebraic data types are common in functional languages. "Maybe" is just an example of an algebraic data type, there's tons more.
If the article says "functional programmers should take a look at Zig", and Zig makes algebraic data types hard, then maybe they shouldn't use it.
If you even say "the annoyingness is a feature, use zig the way it is intended to be used" then that's another signal for functional programmers that they won't be able to use zig the same way they use functional languages.
zig doesnt make algebraic types hard. algebraic types are exceptionally easy and also safe. and unlike rust, named in a way thats friendly to c devs.
zig makes stupid metaprogramming tricks on algebraic types annoying (not hard).
so, being precise: zig is not necessarily annoying for fp programmers (my main tool of trade in Elixir). zig is made to be annoying for architecture astronauts.
> if optional were a general sum type you wouldn't be able to make these optimizations easily without extra information
Rust has these optimizations (called "niche optimizations") for all sum types. If a type has any unused or invalid bit patterns, then those can be used for enum discriminants, e.g.:
- References cannot be null, so the zero value is a niche
- References must be aligned properly for the target type, so a reference to a type with alignment 4 has a niche in the bottom 2 bits
- bool only uses two values of the 256 in a byte, so the other 254 form a niche
There's limitations though, in that you still must be able to create and pass around pointers to values contained within enum, and so the representation of a type cannot change just because it's placed within an enum. So, for example, the following enum is one byte in size:
enum Foo {
A(bool),
B
}
Variant A uses the valid bool values 0 and 1, whereas variant B uses some other bit pattern (maybe 2).
But this enum must be two bytes in size:
enum Foo {
A(bool),
B(bool)
}
...because bool always has bit patterns 0 and 1, so it's not possible for an invalid value for A's fields to hold a valid value for B's fields.
You also can't stuff niches in padding bytes between struct fields, because code that operates on the struct is allowed to clobber the padding.
Yes, the care that Rust goes through to ensure that niches work properly, especially when composing arbitrary types from arbitrary sources, shows why you absolutely don't want to be implementing these optimizations by hand.
Came to say this. Early in my career I really thought implementing Maybe in any language is necessary but not I know better. Use the idioms and don’t try to make every language something it’s not.
This looks like an example of a low level language vs a high level language (relatively speaking). The low level language makes a lot more of what is going on underneath explicit compared to the higher level language which abstracts that away for a common pattern. Presumably that explicitness allows for more control and/or flexibility. So apples to oranges?
Low-level doesn’t mean more information, it means more explicit.
In Zig, that means being able to use the language itself to express type level computations. Instead of Rust’s an angle brackets and trait constraints and derive syntax. Or C++ templates.
Sure, it won’t beat a language with sugar for the exact thing you’re doing, but the whole point is that you’re a layer below the sugar and can do more.
Option<T> is trivial. But Tuple<N>? Parameterizing a struct by layout, AoS vs SoA? Compile time state machines? Parser generators? Serialization? These are likely where Zig would shine compared to the others.
I don't think there is a standardized meaning of 'low-level'. I think a useful definition is that a low-level language controls more/is explicit about more properties of execution.
So zig/c/c++/rust all have ways to specify when and where should allocations happen, as well as memory layout of objects.
Expressivity is a completely different axis on which these low-level languages separate. C has ultra-low expressivity, you can barely create any meaningful abstraction there. Zig is much better at the price of remarkably small amount of extra language complexity. And c++ and rust have a huge amount of extra language complexity for the high expressivity they provide (given that they have to be expressive even on the low-level details makes e.g. rust more complex as a language than a similar, GC-d language would be, but this is a necessity).
As for this particular case, I don't really see a level difference here, both languages can express the same memory layout here.
> Option<T> is trivial. But Tuple<N>? Parameterizing a struct by layout, AoS vs SoA? Compile time state machines? Parser generators? Serialization? These are likely where Zig would shine compared to the others.
I don't see how any of that becomes easier in the Zig case. It's just extra syntactic ceremony. The Rust version conveys the exact same information.
It’s precisely not syntactic ceremony. It’s normal Zig running at compile time in which you can program types as values. In Rust (and most other languages) all you get is a highly abstract DSL:
Foo<T> where for<‘a> T: Bar<‘a, baz(): Send>
Information dense, but every new feature needs language design work. Zig lets you express arbitrary logic, loops, conditionals, etc. It’s lower level of abstraction than a type constraints DSL.
For example, adding “the method in this trait is Send” to Rust’s DSL took a whole RFC and new syntax. The Zig equivalent could be implemented with an if statement on a type at comptime.
Or how about the transformation of an async function into a state machine. Years of work, deep compiler integration, no way to write such transforms yourself. Same with generators, which still aren’t stable. I’d really like to be able to write these things like any other program.
If you don’t want or need to express things at this lower level of abstraction, fair, same reason most people stick to scripting languages and don’t think about memory layout. But “extra ceremony” is really underselling it.
But there's literally none of that in the example we're talking about. It's just an inert datatype declaration. And if anything the Zig version is more abstract - for the Rust version I have to understand <T>, whereas for the Zig version I have to understand comptime, Self, and @.
Not long ago I was looking through programming language sites to figure out how to best introduce the language I'm working on.
ruby-lang.com stood out with a text in a big font:
Ruby is...
Followed by a paragraph about what makes Ruby special. I think that was an exceptionally simple and natural way of introducing something as complex as a programming language.
"Programmer's best friend" is precisely the wrong thing to do though (it says nothing and only makes the reader confused. Are we talking about a language or a pet? I'm not looking for a friend.). They took a step back with that.
The old one was better because it said something about what the language is and how it benefits the user. "Best friend" is not descriptive. "dynamic language with minimal syntax that is easy to read and write" at least tells me something about Ruby, its priorities, and value proposition. I'm very concerned about a language that claims it wants to be my friend.
Dunno, it's a comfy tagline. I never got into Ruby but it always feels to me like it's a really ergonomic and cozy language. Sure, the best friend thing is a stretch, but it's honestly a slogan. How many people land on this page with no knowledge of what Ruby is and will confuse it with an app to make friends?
It sure is a comfy tagline, but because it doesn't really mean anything you could say it about any language, and it only works if you already know what Ruby is. It's not that anyone would confused Ruby with an app to make friends, but it doesn't really say anything about Ruby at all. As other pointed out, the page doesn't even make clear that Ruby is a programming language.
Sure, but one could imagine that there are people working at the supermarket who would also rather do personal stuff or go cycling. But there they are, serving you.
I think this kind of slop has negative value. It's unclear how much of the information in the comic is hallucinated, and the malformed code "for i = i1+|>" and nonsense text "(starts write hooks!" doesn't bode well.
Definitely still needs a "human in the loop." I don't know if this particular comic was cherry-picked or if it was the first one generated by Nano-Banana Pro, but either way, it's still got plenty of messy typos.
RULES OF HOORS?
Updste #2: setState
Starts wite hooks!
At which point I feel like I would rather the human have invested their time into writing a design doc that we could discuss well before they submitted a PR.
I'm not familiar with Hetzner personally, but maybe they mean the uplink? I've found that with some smaller providers, advertising 10Gbit, but you rarely get close to that speed in reality.
reply