Disclosure: I'm not a seasoned c/c++ developer. Just started working with just 3 days ago using 0.0.5 release, it's a young language, but very nice to work with even now. Just starting to do more non-trivial things, but it's a nice alternative to doing stuff with c. Managed to do most of what I could with c after some trial and error and using the offical docs, including using C libraries without much issue. Great work Andrew and everyone else working on Zig!
I wrote a small thing with gtk and zig a while ago, it feels like magic to just import a C header and have it work, and the experience is generally very good, especially for such a young language, and any problems i had figuring things out, I found the community very friendly in helping me.
One very cool feature of Zig is that it supports calling async/await from any function [1], not just async functions, which avoids the famous function coloring problem altogether.
I believe function coloring has never been about syntax but about semantics. It's not possible to yield while waiting for an async function to resolve without being async yourself. And if you have a choice between an async and a sync function that you could call from your async function, you should prefer to call the async one to avoid stalling whatever executor is driving your function.
Zig isn't avoiding it; it's impossible to avoid. Zig is just inferring the async-ness of the function automatically without you needing to write a keyword for it.
> Wanna know one [programming language] that doesn’t [have this problem]? Java. I know right? How often do you get to say, “Yeah, Java is the one that really does this right.”? But there you go. In their defense, they are actively trying to correct this oversight by moving to futures and async IO. It’s like a race to the bottom.
I think function colouring is a positive thing. A synchronous function cannot yield; so calling an asynchronous function from it doesn't make sense since those cannot yield either.
A synchronous function cannot yield, but it can make sure another thread is available to take its place before it issues a blocking syscall. If properly constructed, synchronous stdlib functions would be safe to call from async functions. Any "executor" implementation that uses a fixed-size thread pool and is vulnerable to all threads in that pool being tied up this way at once is BROKEN.
I'm happy to see Zig moving along. I've been using my extra spare time the last couple of weeks to play with it and it's been fun. Documentation is still sparse but there is a whole lot more of it both in general and on the stdlib (zig test cases code is still the best place to figure out the stdlib IMO). Some things just feel "right" without having to give up access to the memory; a good example being arbitrary width integers being used in packed structs to create file/network headers without having to manually bit-twiddle every 4 bit field. Cross compiling is really as easy as it says on the tin and the standard library isn't afraid to include things like net and unicode but at the same time doesn't feel like it tries to throw the kitchen sink in too.
Unfortunately it is still very much the 0.x the name implies. Taking the above example defining 2 u129 or larger and trying to multiply them results in an error while compiling about it not being supported yet. Packed struct items that cross word boundaries result in a broken struct that contains a size larger than the data (which breaks pretty much all code that tries to use it due to size/type checking). Also due to comptime being as big of an idea as it is not everything works quite yet like const example: f64 = std.math.sin(4) * std.math.sin(2) being a compile time error since sin isn't defined for comptime floats yet.
Like I said it's definitely fun to play with but it's still quite a few releases away from "is this a compiler bug or did the documentation skim over something I'm just supposed to know" no longer being a problem so if that's not your cup of tea best to just watch the release notes over the next year or two.
Thank you for working so tirelessly on this, Andy! I’ve seen first hand the blood, sweat and tears you’ve put into Zig. I’m so happy to be able to support your dream, a dream that is really meant for making other people’s lives better! Keep on keeping on!
There are hundreds of changes listed here and still no mention of fixing the fact that zig purposely errors out on tabs and carriage returns. This might sound too ridiculous to believe, but if you use tabs or save a file out of windows text editor with normal settings, zig just won't compile. It would be trivial to do what every other compiler in history does, but they want to screw with windows users or anyone you uses tabs for some philosophical reason.
Ever used or read about Fortran, Haskell, or Python? The idea that whitespace does not matter and will just be handled as-is is and has been a language design choice before and after Zig regardless how many times you pose the question. That Zig or any other language did not make the choice to treat whitespace the way you'd prefer in the compiler and instead left that it to the formatter does not make them "user hostile". The Zig docs link to the reasons they made the choice not to support varying whitespace (and other character and syntax choices), if you don't like those reasons feel free not to use it but it's a bit rude to make it out like they did it to "screw Windows users" when it's neither technically true nor the actual motive.
This is all coming from a guy who has only messed with Zig on a Windows box with a preference for tabs over spaces (except post indent alignment). Zig fmt works great, haven't had an issue, less difficult to get going than mingw or vs that's for sure.
First, I said screw with windows users. Second, none of those languages error on carriage returns. Third, whitespace being significant is not the same as erroring out when your users don't use your preferred white space. I don't use tabs for anything, but it is all trivial to handle and they bomb out anyway. It's a slap in the face to users and it's "rude" to waste people's time by making them deal with nonsense. It is not "rude" to point out that a piece of software does this.
Also none of what you put here is an an actual justification for stuff like this. This is like being in the twilight zone, why would anyone defend this?
"With" or not with you don't find it a bit ridiculous to say that a group designed a C compatible language that can cross compile to/from Windows easier than any existing C compatible language to this point yet they specifically chose the whitespace as they did because they want to screw with Windows users - no better reason?
Again Unix newline style is the least of the worries for whitespace, Windows and built-ins like Notepad handle it just fine for years now if that's what you code in. Try inserting tabs in place of spaces as you please in Python or Haskell though and yes you are likely to run into problems trying to run a program. It's not called "significant whitespace" in those languages because it's ignored.
It's fine to point out you think something is harder to use than it needs to be but the way you've done it says more about you than the language. You won't a whole language because it requires you run the built in formatter to compile? Might as well not use GCC either it forces you to use -- for options instead of / and other tools handle it just fine they just want to screw with Windows users that's it! What's left to talk about except these kind of nitpicks if that's where you draw the line for ignoring whole projects with years of effort put in them at?
None of what I put here was claimed as justification I said the Zig docs link to the reasons. Specifically (in case you'd rather I'd bring them up for you) the reasons were around ease of parsing as a large portion of the syntax was. The whole language specification is actualy very specific about making sure each line can be simply tokenized individually and parsed one way regardless of convetion - not actually so picked just to screw with people that like tabs or Windows. Zig fmt is allowed to "eat" any complexity in normalizing code (referencing ICU data, normalizing whitespace and other syntax, and so on) so zig build-exe doesn't have to. This philosophy of keeping as much functionality out of the core compiler and language is a big part of what allows Zig to target many places e.g. Rust doesn't even though Zig is still very fresh.
If running "zig-fmt" as part of your custom build process or using one of the editor plugins ziglang maintains that does this for you is "a slap in the face to users" I'm not sure there is any language those users would be happy with as there are other things they are going to like less than it replacing their whitespace on them. It's certainly not harder to do than post scathing reviews about how you couldn't just use tab on the release discussions though.
> The whole language specification is actualy very specific about making sure each line can be simply tokenized individually and parsed one way
This is the rationalization given, but it doesn't make any sense. Carriage returns could just be ignored. It is completely trivial, especially compared to all the other changes. Can you explain how this explanation actually connects to reality?
Again the thought was Zig could take a stance on supporting multiple of the 5-ish line endings and let every tool that is written deal with it and dozens of other whitespace decisions or it could be normalized to 1 way to represent it with no variability in whitespace characters as part of the built in language tooling. Allowing 2 ways is not an alternative path to having 1 way. This concept is extended to all sorts of whitespace characters it's not just about newline and tab.
You write about the line ending like you get paid per \r\n you push up to Git, there is no reason to care which whitespace character the formatter outputs for you. Zig init-exe is literally going to do this for you when you make a project. Build.zig can literally run zig fmt for you as part of the build process.
There is no "taking a stance". There are two line endings being talked about here, with carriage returns and without. Why are you so desperate to change the goal posts? This change log is hundreds of lines long, you think ignoring carriage returns is a big deal?
Why would it matter for tools? Have the tools run zigfmt. Why make users build a script to compile a hello world program? Does zig only allow a single space between tokens?
Again you are trying anything you can think of to justify a ridiculous choice because you want to defend zig as a whole. Nothing ads up here.
> there is no reason to care which whitespace character the formatter outputs for you.
I never said anything about that. I have only talked about the compiler erroring out on carriage returns as an intentional design choice.
There is stance to take you just disagree with the choice. I think at this point you understand the initial aims and reasons of why Zig chose the syntax it did so here's a question about your stance both line endings should be supported by the compiler: why is it more important than the reasons Zig gave? Sure everything can be made to support variations in line endings but why? It's not that a formatter is hard to come by, it ships with the build tools. It's not that it's hard to initialize, it ships with the build tools. It's not that editors don't support the line ending, even Notepad does. It's not that existing tools that look for multiple types of line endings don't work, they still see the \n as is. Is it literally just because if you go to write your first hello world on some machines you get a syntax error telling you what needs to be changed for it to be a valid Zig source file or are there other reasons?
It's not like there is an enormously "wow this would change everything about using the language" _either way_ (which is part of why it's so confusing it's the hill you're willing to die on about using Zig) it's literally "there was an option for simplifying syntax and parsing at the cost of making \r\n a syntax error". You may not agree with it but there were reasons and a path was taken. It's not the Twilight Zone, ridiculous, nonsense, user hostile, or to screw with Windows users it's a minor choice you don't agree with in a project with millions of choices to make.
You can say it's just a "disagreement" but there are no benefits to doing this. No one has actually out forward reasoning that makes sense. You have just thrown out flimsy arguments and then moved on to more flimsy arguments when I point out how absurd they are.
This is a typical thing people do when they can't directly confront something. They throw out as much as they can and don't acknowledge when what they said was shot down, they just throw out more and hope something sticks.
You said so much and none of it made sense, but instead of backing up claims of "parsing being easier" or "can't support multiple line endings" or any other nonsense, you just make be on to more nonsense. Literally no other compiler intentionally breaks by default. There is no reasonable reason to do this and you haven't even come close to mentioning one and infact have had to go into bizarre concoctions because you don't want to admit how silly this is.
I've presented the cases for why it was done, whether you agree with the cases or not does not cause their existence to cease they are still the reasons Zig made the decision. Also whether or not you think it was the right decision overall it does make parsing easier. You may argue in the singular case it is only trivially easier but looking for \n is still unarguably easier than looking for \r\n OR \n (or any other line endings some languages accept). This is all ignoring the overall picture of having the fewest ways to do something as possible which is a whole ideological debate I don't think would go anywhere.
I then asked for clarification on why Zig shouldn't have made the decision:
"I think at this point you understand the initial aims and reasons of why Zig chose the syntax it did so here's a question about your stance both line endings should be supported by the compiler: why is it more important than the reasons Zig gave?"
and:
"Is it literally just because if you go to write your first hello world on some machines you get a syntax error telling you what needs to be changed for it to be a valid Zig source file or are there other reasons?"
And instead of responding you said more about how I've only said nonsense and unable to directly confront something.
"There is no reason to do this" is not an argument why it should be done one way or the other. "No other compiler intentionally breaks [on line endings] by default" is not a reason either but I think it relates to the only argument I identified: "if you go to write your first hello world on some machines you get a syntax error telling you what needs to be changed for it to be a valid Zig source file". I'd also love to say how silly this all is and that there is some solid reason to use tabs and Windows line endings (remember I'm a Windows user who uses the tab key) but in using Zig I have not found any reasons myself.
So on that note, again I'll ask: is there anything else this choice on line endings breaks? That is to say: not that you think it's nonsense, not that you haven't seen it before, not "well you haven't convinced me it should be this way". I'm genuinely asking about why you think it shouldn't in practice - is your only reason for caring about this because when you wrote hello world it told you the line ending needed to be \n or does it actually break some tool or workflow or limit functionality down the line or not have support somewhere or something else I haven't thought of?
If it's just the latter I think we're about as far as we can get and maybe that's why you feel there isn't any direct confrontation - you think that mildly rare error is more important than the mildly simpler syntax definition, not the end of the world for either side so be it at least we all understand the whys and why nots that led to it. I have a feeling though, considering you've been here all this time and listed it as the reason you refuse to use the language, that perhaps there are other reasons this was the wrong decision I'm still missing?
It's kind of funny to me though that there's an actual language out there where you can do use-after-free and all sorts of other C-level stuff but can't use tabs.
It is consistently surprising to me how many people bikeshed this particular decision.
Zig has taken an aggressive stance on many things. For instance, it has no default allocator, no compiler warnings, variable shadowing is a compile error, no function overloading, no operator overloading, etc. And all of these decisions have pages and pages of discussion and justification.
But hey, let's keep talking about the one that is the most trivial.
Breaking by default for no other reason than because you think windows 'does it wrong' is not bikeshedding something trivial.
Think about this. You tell your supervisors to check out zig. They ask why it doesn't work with the small program and compiler options they copied from the website. How would you explain that to them? Are you going to try to convince them that ignoring a character is a problem and that the time they spent wondering why it doesn't work is justified?
I am continuously surprised by the amount of work zig committers manage to put out every release. It is actually inspiring. How do they get to appear so productive?
Anyway, here's a nitpick. In this release they've removed varargs, and now this is how a printf call looks like in zig:
std.debug.warn("{}+{} is {}\n", .{1, 1, 1 + 1});
The ergonomics of typing .{} for every print seems pretty awful if you're a heavy user of debug printing. I was hoping that maybe some sort of a syntax sugar is planned so that tuples could be used without .{} -- emulating varargs, but the bug tracker doesn't turn up anything in that direction.
In the previous release (0.5.0) one didn't need the .{}, but instead integer literals needed explicit casts, because the vararg implementation was limited:
std.debug.warn("{}+{} is {}\n", i32(1), i32(1), i32(1 + 1));
Both of these options seem like a regression compared to the usual
printf("%d+%d is %d\n", 1, 1, 1 + 1);
... and there doesn't seem to be a way to work around it by e.g. using a function overloaded in the number of arguments (no such thing in zig) or some preprocessor tricks (again, no such thing).
PS. I'm also surprised to find out that zig seems to take 2.6 seconds to compile the above example.
To be honest typing and remembering %d %f %c %s etc. seems like more hassle than typing {} and typing it for every case.
I think the real gotchas are that { is escaped as {{ and } as }} instead of \{ and \} (though it does follow from the old %%) and you must either include , .{} or rewrite the function call to something significantly different to do unformatted print.
32 comments
[ 0.20 ms ] story [ 84.7 ms ] thread[1] https://ziglang.org/#Concurrency-via-Async-Functions
Zig isn't avoiding it; it's impossible to avoid. Zig is just inferring the async-ness of the function automatically without you needing to write a keyword for it.
If you haven't heard of it: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
Highlight:
> Wanna know one [programming language] that doesn’t [have this problem]? Java. I know right? How often do you get to say, “Yeah, Java is the one that really does this right.”? But there you go. In their defense, they are actively trying to correct this oversight by moving to futures and async IO. It’s like a race to the bottom.
Unfortunately it is still very much the 0.x the name implies. Taking the above example defining 2 u129 or larger and trying to multiply them results in an error while compiling about it not being supported yet. Packed struct items that cross word boundaries result in a broken struct that contains a size larger than the data (which breaks pretty much all code that tries to use it due to size/type checking). Also due to comptime being as big of an idea as it is not everything works quite yet like const example: f64 = std.math.sin(4) * std.math.sin(2) being a compile time error since sin isn't defined for comptime floats yet.
Like I said it's definitely fun to play with but it's still quite a few releases away from "is this a compiler bug or did the documentation skim over something I'm just supposed to know" no longer being a problem so if that's not your cup of tea best to just watch the release notes over the next year or two.
My experience is mostly in Go and Java and I've dabbled in C a couple of times, but I found Zig the language quite easy to understand.
Things I like the most about Zig (for now, I haven't tried everything): * error handling * optionals * tagged unions * meta programming * zig fmt
The API documentation of the std lib is still sparse though, I find it's best to search directly in the code to understand how to use it.
Looking forward to try the async functionality.
This is all coming from a guy who has only messed with Zig on a Windows box with a preference for tabs over spaces (except post indent alignment). Zig fmt works great, haven't had an issue, less difficult to get going than mingw or vs that's for sure.
Also none of what you put here is an an actual justification for stuff like this. This is like being in the twilight zone, why would anyone defend this?
Again Unix newline style is the least of the worries for whitespace, Windows and built-ins like Notepad handle it just fine for years now if that's what you code in. Try inserting tabs in place of spaces as you please in Python or Haskell though and yes you are likely to run into problems trying to run a program. It's not called "significant whitespace" in those languages because it's ignored.
It's fine to point out you think something is harder to use than it needs to be but the way you've done it says more about you than the language. You won't a whole language because it requires you run the built in formatter to compile? Might as well not use GCC either it forces you to use -- for options instead of / and other tools handle it just fine they just want to screw with Windows users that's it! What's left to talk about except these kind of nitpicks if that's where you draw the line for ignoring whole projects with years of effort put in them at?
None of what I put here was claimed as justification I said the Zig docs link to the reasons. Specifically (in case you'd rather I'd bring them up for you) the reasons were around ease of parsing as a large portion of the syntax was. The whole language specification is actualy very specific about making sure each line can be simply tokenized individually and parsed one way regardless of convetion - not actually so picked just to screw with people that like tabs or Windows. Zig fmt is allowed to "eat" any complexity in normalizing code (referencing ICU data, normalizing whitespace and other syntax, and so on) so zig build-exe doesn't have to. This philosophy of keeping as much functionality out of the core compiler and language is a big part of what allows Zig to target many places e.g. Rust doesn't even though Zig is still very fresh.
If running "zig-fmt" as part of your custom build process or using one of the editor plugins ziglang maintains that does this for you is "a slap in the face to users" I'm not sure there is any language those users would be happy with as there are other things they are going to like less than it replacing their whitespace on them. It's certainly not harder to do than post scathing reviews about how you couldn't just use tab on the release discussions though.
This is the rationalization given, but it doesn't make any sense. Carriage returns could just be ignored. It is completely trivial, especially compared to all the other changes. Can you explain how this explanation actually connects to reality?
You write about the line ending like you get paid per \r\n you push up to Git, there is no reason to care which whitespace character the formatter outputs for you. Zig init-exe is literally going to do this for you when you make a project. Build.zig can literally run zig fmt for you as part of the build process.
Why would it matter for tools? Have the tools run zigfmt. Why make users build a script to compile a hello world program? Does zig only allow a single space between tokens?
Again you are trying anything you can think of to justify a ridiculous choice because you want to defend zig as a whole. Nothing ads up here.
> there is no reason to care which whitespace character the formatter outputs for you.
I never said anything about that. I have only talked about the compiler erroring out on carriage returns as an intentional design choice.
It's not like there is an enormously "wow this would change everything about using the language" _either way_ (which is part of why it's so confusing it's the hill you're willing to die on about using Zig) it's literally "there was an option for simplifying syntax and parsing at the cost of making \r\n a syntax error". You may not agree with it but there were reasons and a path was taken. It's not the Twilight Zone, ridiculous, nonsense, user hostile, or to screw with Windows users it's a minor choice you don't agree with in a project with millions of choices to make.
This is a typical thing people do when they can't directly confront something. They throw out as much as they can and don't acknowledge when what they said was shot down, they just throw out more and hope something sticks.
https://en.m.wikipedia.org/wiki/Gish_gallop
You said so much and none of it made sense, but instead of backing up claims of "parsing being easier" or "can't support multiple line endings" or any other nonsense, you just make be on to more nonsense. Literally no other compiler intentionally breaks by default. There is no reasonable reason to do this and you haven't even come close to mentioning one and infact have had to go into bizarre concoctions because you don't want to admit how silly this is.
I then asked for clarification on why Zig shouldn't have made the decision:
"I think at this point you understand the initial aims and reasons of why Zig chose the syntax it did so here's a question about your stance both line endings should be supported by the compiler: why is it more important than the reasons Zig gave?"
and:
"Is it literally just because if you go to write your first hello world on some machines you get a syntax error telling you what needs to be changed for it to be a valid Zig source file or are there other reasons?"
And instead of responding you said more about how I've only said nonsense and unable to directly confront something.
"There is no reason to do this" is not an argument why it should be done one way or the other. "No other compiler intentionally breaks [on line endings] by default" is not a reason either but I think it relates to the only argument I identified: "if you go to write your first hello world on some machines you get a syntax error telling you what needs to be changed for it to be a valid Zig source file". I'd also love to say how silly this all is and that there is some solid reason to use tabs and Windows line endings (remember I'm a Windows user who uses the tab key) but in using Zig I have not found any reasons myself.
So on that note, again I'll ask: is there anything else this choice on line endings breaks? That is to say: not that you think it's nonsense, not that you haven't seen it before, not "well you haven't convinced me it should be this way". I'm genuinely asking about why you think it shouldn't in practice - is your only reason for caring about this because when you wrote hello world it told you the line ending needed to be \n or does it actually break some tool or workflow or limit functionality down the line or not have support somewhere or something else I haven't thought of?
If it's just the latter I think we're about as far as we can get and maybe that's why you feel there isn't any direct confrontation - you think that mildly rare error is more important than the mildly simpler syntax definition, not the end of the world for either side so be it at least we all understand the whys and why nots that led to it. I have a feeling though, considering you've been here all this time and listed it as the reason you refuse to use the language, that perhaps there are other reasons this was the wrong decision I'm still missing?
It's kind of funny to me though that there's an actual language out there where you can do use-after-free and all sorts of other C-level stuff but can't use tabs.
Zig has taken an aggressive stance on many things. For instance, it has no default allocator, no compiler warnings, variable shadowing is a compile error, no function overloading, no operator overloading, etc. And all of these decisions have pages and pages of discussion and justification.
But hey, let's keep talking about the one that is the most trivial.
Think about this. You tell your supervisors to check out zig. They ask why it doesn't work with the small program and compiler options they copied from the website. How would you explain that to them? Are you going to try to convince them that ignoring a character is a problem and that the time they spent wondering why it doesn't work is justified?
Anyway, here's a nitpick. In this release they've removed varargs, and now this is how a printf call looks like in zig:
The ergonomics of typing .{} for every print seems pretty awful if you're a heavy user of debug printing. I was hoping that maybe some sort of a syntax sugar is planned so that tuples could be used without .{} -- emulating varargs, but the bug tracker doesn't turn up anything in that direction.In the previous release (0.5.0) one didn't need the .{}, but instead integer literals needed explicit casts, because the vararg implementation was limited:
Both of these options seem like a regression compared to the usual ... and there doesn't seem to be a way to work around it by e.g. using a function overloaded in the number of arguments (no such thing in zig) or some preprocessor tricks (again, no such thing).PS. I'm also surprised to find out that zig seems to take 2.6 seconds to compile the above example.
I think the real gotchas are that { is escaped as {{ and } as }} instead of \{ and \} (though it does follow from the old %%) and you must either include , .{} or rewrite the function call to something significantly different to do unformatted print.