Sometimes when reading Zig news I get a feeling that the community is waiting for a 1.0 to come out, hopefully sooner.
Why this rush? I would much prefer a language that evolves when realizing a mistake or seeing opportunities for an improved language or library.
It seems like “Go 1.0” has set the standard with a loud promise of language stability (“we promise to not break any code written for 1.0”).
But it should be a tradeoff. How much and how often are developers willing to update their code base in return for a better language or a better library.
Naturally the rate of change will decrease over time and groundbreaking changes like WriterGate (and upcoming std.Io interface) are going to happen more rarely.
As the language matures, one could decide to support deprecated APIs/features for 2-3 years, with appropriate compiler warnings.
I appreciate the patience the team has, and share the same feelings, I don’t need a 1.0 version that’s going to be unfinished. After all, there is no board that has to be pleased with a big overhyped rocket launch .
I think Go kinda shot itself in the foot with those promises, and instead of the community lifting light weights, the team is lifting very heavy weights, tip toeing around trying not to break anything with every release.
I am having great fun learning Zig, I obviously don’t mind the breaking changes. I’m feeling like I am having great time with this powerful language, in the future I’d like to be a long term user, and that shall not be rushed. Not for the impatient
Yes, Go is quite (too?) dogmatic with regard to “no breaking changes”.
For the few instances of “somewhat breaking change”, it has been swept under “okay, but if you actually read the definition, we never promised THAT to work like THAT”.
I wish they would be a little bit more generous (and less dogmatic) about updating the language.
Everybody want everything to be ready as soon as they discover the want it. Silly, but understandable.
Either way, the core point to understand wrt Zig (and all other software…) is that “1.0” is too few bits of information to represent the state of the project and whether it’s fit for your use case.
Different projects interpret 1.0 in different ways, for example Rust takes it to mean backwards compatibility, but not feature completeness of the language, Go instead took 1.0 to mean that the languages would not change much in short spans of time.
Zig has many things going on all at the same time, some more mature than others, some experimental, some fairly set in stone and/or feature complete.
If you’re somebody who stands to benefit from being an early adopter of Zig for your business, it’s on you to learn what aspects of Zig you need to rely on, and what the state of stability / completeness of those are.
But, as I said in the beginning, this is true for all software, not just Zig.
Speaking as TigerBeetle developer: we are fine with Zig being pre-1.0 and making breaking changes, we don’t plan around Zig becoming stable any time soon. For us, it’s more important that what’s there is just right.
I can empathize with those wishing for 1.0. I think there is a cultural and technical phenomenon that leads software engineers to believing that software can never truly be “finished”.
If zig is here to enable “maintainable” software, then it will need a way to provide “finished” software. This implies stability guarantees, likely on the order of 5-10 years.
Personally, I am not ready for 1.0. Async is my biggest want before then (both to prove that it is possible and to grind down the rough edges).
I honestly couldn’t care less what the version is, it is just a number to me.
That said, I am not writing enterprise-level software or have a business that relies upon it, so it is easy to say.
Speaking as someone that mostly writes PHP code, i very much appreciate that the Go code I wrote 10 years ago still compiles today. In the world of web where there’s a new framework every time you blink, it’s incredibly refreshing to have a language that you know is “rock solid”.
While this has certainly stifled Go’s ability to improve (i.e. error handling), it’s also in keeping with its theme of “boring, but fast enough, and easy”.
Zig on the other hand is an incredibly ambitious, (and quite impressive) language, and I think the scope of its goals are too big to fit into a “quick” 1.0 release, if that makes sense.
Speaking as someone that hardly ever actually reads or writes Zig, (and therefore whose opinion doesn’t matter), I’d like to see gradual breaking changes toward v1 as the language finds its footing, followed by slow, performance/std library improvements; only to be followed by v2 if:
a) A fundamental flaw is discovered in the language.
b) A fundamental shift in programming paradigms occurs, such as quantum computing becoming the norm.
I think 5-10 years per major revision sounds pretty excellent.
I’m also in the TigerBeetle-type camp of preferring just right over “we have 1.0”.
My sense of why some people are more keen for 1.0 is that it impacts the dependency equation. In the non-backwards-compatibilty world, if you decide to add a dependency (especially one with many of its own dependencies), you open yourself up to your project breaking when a deep dependency doesn’t upgrade for the new version.
Given so many people build projects using a significant number of dependencies (understandably in many cases), the lack of backwards-compatibilty guarantees affects them.
People wishing for 1.0 are often not using zig in the first place. They have no idea what kind of position it is currently at. Let it cook in the oven still.
Hello, I think the “IO” and “Allocator” changes have had an impact. Many people have certainly thought about 1.0.
As stated, such maneuvers are rarely used.
For now, I’m able to keep up, and I do nightly updates, but my project is still in progress, so maybe that’s why it doesn’t bother me.
On the other hand, the number of Gits that are not up to date is impressive.
I think there is also a group of people that won’t look at a tool that is “pre-1.0” for various reasons. So some of that camp are people who want to look at zig, but think they can’t until it is 1.0. Which is a valid approach, but should not have weight with regard to when the compiler team decides it’s ready.
Yes, one thing that’s more important than I realized is the dependency ecosystem.
If one module transitively depends on 30 others (as is not unusual in the Rust world), then it’s a huge task to bring all that up to date after a breaking language or stdlib change.
It reminds me - I saw Ginger Bill arguing against package managers (on Primeagen), and he had some good points. Some systems might make it too easy to transitively pull in a dependency mess.
And vendoring is maybe a somewhat underrated technique. Clone someone else’s module, make upgrades an intentional, manual process, and even make your own convenient patches in the dependency.
I like that thought.
Maybe a positive byproduct of having a still unstable language is that it makes developers more careful about what they depend on.
I don’t have too much experience dealing with opensource dependencies, so take it with a grain of salt. BUT my uneducated opinion is that I hope Zig will embrace a workflow of vendoring over too-automatic transitive spaghetti-dependency-pull (like cargo etc can tend to do)
My other hope is that Zig doesn’t stop evolving, even in places where it then needs to break existing code, after reaching 1.0. I guess it should be possible to have a process for incrementally moving over to new features. E.g. Rust has the “edition” concept, bumping every 3 years. So your crate can declare that it’s running the 2021 or 2024 edition of Rust. Of course this is more compiler work to maintain old editions for a period of time.
I don’t care about the version number. “1.0” is in my opinion for marketing. Guarantees about how the version number relates to breaking changes are nice to have, but I know how to pin the programs I write and their dependencies to a compiler version. Why the constant need to upgrade everything? The code doesn’t magically change out from under you unless you change it or how you build it. If you are truly concerned about the longevity of your code, store the build tools and dependencies you used to make it.
While there is some merit to GingerBill’s perspective on package managers, when all the pros and cons are weighed for each approach, I am of the mind that a standardized package manager for a language is a clear benefit, despite the sharp edges.
That said, in a pre-1.0 language, the notable issues that he brings up are very much exacerbated when the breaking changes are frequent. My personal takeaway is that in that until the language stabilizes, “not invented here syndrome” is a wise, and even recommended, practice. There are plenty of exceptions, but I would err on the side of the doing the work myself over something closer to adding dependencies for minor features like what one might see in Rust, JavaScript, etc.
The std.Io.Writer / std.Io.Reader changes were a major contribution to instability in 0.15.x release cycle, and also affect 0.16.x to a lesser extent.
The std.Io interface changes will again cause massive instability in 0.16.x.
The amount of instability makes the following advice less practical, but when those things calm down in favor of minor instabilities I think it will be wise advice:
Zig packages should be made to support multiple Zig versions. For instance, a package can use reflection, or check @import("builtin").zig_version to be compatible with a range of Zig versions. This makes it easier for applications to manage their dependencies - even if they’re trying to stay up-to-date, because it allows them to upgrade one package at a time, while leaving the rest of the dependency tree alone.
Even with massive breaking changes, packages which want to do such things have the option to have N copies of the code and switch between them based on Zig version string.
This allows Zig to avoid legacy baggage at the same time as giving application developers an easier time managing dependencies.
“If you’re really worried about the longevity of your code, hang on to the tools and dependencies you used to build it” (emphasis mine).
Yes, but a lot of the time it isn’t practical, because your dependencies are not always something you can safeguard (even if they’re open source).
They aren’t:
binaries; because the binary that worked for you won’t work for someone else
code; because the code doesn’t actually build without more effort than sane users are willing to give
They are:
distributed systems of prebuilt binaries that are expensive to maintain and growing fast
Then along came Zig!
IMO Zig earned the right to breaking changes, they are far more practical to deal with than in any other language I know of, due to its radical commitment to hermetic-ness.