23 ms·
A Review of the Zig Programming Language (Using Advent of Code 2021)
- AnIdiotOnTheNet 5y ago> Initializing arrays is weird in Zig. Lets say you want to have a 0 initialized array, you declare it like [_]u8{0} * 4 which means I want an array, of type u8, that is initialized to 0 and is 4 elements long. You get used to the syntax, but it’s not intuitive. Alternatively: var some_array = std.mem.zeroes([4]u8); Though as mentioned later in the article the standard library documentation is not very good, making this not as obvious as it could be. > Everything in Zig is const x = blah;, so why are functions not const bar = function() {};? Good question, there's an accepted proposal to fix this: https://github.com/ziglang/zig/issues/1717 https://github.com/ziglang/zig/issues/1717 > The builtin compiler macros (that start with @) are a bit confusing. Some of them have a leading uppercase, others a lowercase, and I never did work out any pattern to them. In idiomatic zig, anything that returns a type is uppercased as though it were itself a type. Since only a few builtins return types, the vast majority of builtins will start with a lowercase letter. I think it is only `@Type`, `@TypeOf`, `@This`, and `@Frame` that don't.
- rgrmrts 5y agoAny recommendations on learning more about what constitutes idiomatic zig? This is an issue I have with learning any new language - it’s kind of hard for me to figure out what writing idiomatic code in that language looks like. I usually go looking for popular/high quality projects and reading that code but it takes away from the experience of actually just toying around not to mention it being hard knowing what a high quality project is. Thanks in advance!
- gavinray 5y agohttps://ziglearn.org/ https://ziglearn.org/
- dnautics 5y agoI don't think of this as an idiomaticity guide.
- gavinray 5y agoIt's unfortunately the only comprehensive reference I know of besides the official docs. There is "Ziglings", but those are a collection of small exercises with answers rather than a full guide. https://github.com/ratfactor/ziglings https://github.com/ratfactor/ziglings If you know of better resources than these two, please do share (not being passive aggressive here).
- dnautics 5y agohonestly, the standard library. But there should be an idiomaticity guide. At least for capitalization patterns, any other naming conventions, etc (things that zig fmt can't capture). I don't know that this officially exists, anywhere yet. Here is an example of what I'm talking about in my $DAYJOB lang: https://hexdocs.pm/elixir/naming-conventions.html#content https://hexdocs.pm/elixir/naming-conventions.html#content edit: see sibling comment, apparently I never noticed the style guide in the standard docs
- deleted 5y ago[deleted]
- cturtle 5y agoThe style guide in the language reference explains the accepted naming conventions [0]. [0]: https://ziglang.org/documentation/master/#Style-Guide https://ziglang.org/documentation/master/#Style-Guide
- dnautics 5y agooh man! I'd missed this! Thanks
- 5y ago
- Shadonototra 5y agoif you need to import a package to clear an array, something went very wrong somewhere..
- christophilus 5y agoWhy?
- Shadonototra 5y agobecause it's trivial, it's like assigning a value to an integer, it shouldn't require a package
- messe 5y agoDepending on your perspective, it's not trivial. It's significantly more expensive than assigning a value to an integer. Zeroing a [4096]u64 would require several thousand times more operations than zeroing a u64. In the areas that zig targets, this can be quite important.
- Shadonototra 5y agoi disagree, it's just backward to need to import a package
- kristoff_it 5y agoIn Zig zero initialization is not idiomatic. Unless you have an active reason to do so (and during AoC you need zero init a lot more than normal IME), you should just set the array to undefined like so: var foo: [64]usize = undefined;
- ithkuil 5y agoI don't know zig. Is one a constant initializer while the other is not?
- anonymoushn 5y agoIt looks like the value returned by std.mem.zeroes will end up being a compile-time constant, but I'm only like 90% on this.
- anonymoushn 5y ago> One nugget of knowledge I’ve worked out though - Zig is not a replacement for C. It is another replacement for C++. While comptime is a potential source of complexity, I sort of think C++ developers won't accept a replacement that has no RAII or automatic invocation of destructors.
- tomcam 5y agoMeh. Not trying to start a language war but I was grateful to switch from C++to Go when the price was to lose generics and a few other things in exchange for the language’s simplicity and clarity.
- deleted 5y ago[deleted]
- dnautics 5y agoI think there are so many corners where people are using C++ that making generalizations about them is likely to fail.
- Bekwnn 5y agoThere's an open issue to add some kind of function annotation+errors for functions which require you to call a cleanup function. The discussion has had a lot of back and forth and they haven't really settled on a desirable solution yet, but it's something they're hoping to add. https://github.com/ziglang/zig/issues/782 https://github.com/ziglang/zig/issues/782 I work in games with C++ and we already do so much manual management and initialization+teardown functions that lack of RAII isn't a deal-breaker. Though I'd definitely prefer it if there was something either well-enforced or automatic.
- typon 5y agoWhile the standard library documentation is non existent, using grep on it and just reading through it is very easy, compared to almost any other language I have used. I would actually say this is preferred: it's early days, so the documentation can't go out of sync because it doesn't exist, and library maintainers are incentivized to write understandable code, which most people who are getting into the language are forced to read, creating a consensus of what is considered idiomatic in the community.
- kristoff_it 5y agoYep, and we also encourage this, if you open the (incomplete, buggy) autogenerated doc for the standard library, you get a banner at the top that links you to a wiki page that explains how the standard library is structured. https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code https://github.com/ziglang/zig/wiki/How-to-read-the-standard...
- zppln 5y agoI've also found the tests for the standard library pretty useful when digging around trying to figure out how to use stuff.
- dureuill 5y ago> Try and read a moderately complex Rust crate and it can be mind boggling to work out what is going on. I do that all the time, even reading the source of the std, something that I cannot do sanely in C++. IME Rust code is easy to read, with symbols that are always either defined in the current file, imported, or referred to by their full path.
- nu11ptr 5y agoAgreed, when I see comments like this I tend to think they haven't spent much time using the language. It takes a while, but after a month or so you can read just about any Rust code. Honestly, feels like a much simpler language in day to day usage than say a language like Scala (just an example) to me.
- oxymoron 5y agoI also agree with this sentiment, although there are some examples of really weird meta programming that remains opaque to me. For instance, I’m able to use `warp` as a framework, but the use of things like type level peano arithmetic is mostly incomprehensible to me at the moment. I also find that I run into Higher Rank Trait Bounds so rarely that I have a poor grasp of it (which might be as intended). All that to say that there are some odd corners of the language, given that I’ve been using it for five years now and as my main professional language for three years.
- tialaramex 5y agoTo be fair, the thing that makes a working C++ standard library unreadable is also a hazard in understanding Rust's std. Macros. The macros in a C++ standard library are horrible, because it is here that essential compliance and compatibility are squirreled away, and because the C++ macros aren't hygienic they're bigger than they'd otherwise need to be (e.g. you mustn't call it foo, say __x5_foo instead). But while they're far more readable on their own terms, the Rust macros littering std do mean it's harder to see how say, a trivial arithmetic Trait is implemented on u32 because a macro is implementing that trait for all integer types. A macro-pre-processed std might be easier for the non-expert rustacean to grok even though it isn't the canonical source. The symbol thing is pure insanity, machines have no problem knowing what symbol8164293 refers to, but humans can't get that right, and programming languages, including in theory C++ are intended for humans to write.
- dnautics 5y ago> Everything in Zig is const x = blah;, so why are functions not const bar = function() {};? This may or may not happen: https://github.com/ziglang/zig/issues/8383 https://github.com/ziglang/zig/issues/8383 > Fixing the standard library documentation would be my biggest priority if I worked on Zig, because I think that is the only thing holding back general usage of the toolchain. This is a valid concern, but I believe the zig team is deliberately holding off on improving the std lib documentation, because they are expecting (potentially huge, maybe not? who knows) breaking changes down the line. The "stdlib is not documented" is a deliberate choice to signal "use at your own risk, especially with respect to forwards compatibility". > there are still quite a few bits of syntatic sugar hiding the real cost of certain operations (like the try error handling, there is implicit branches everywhere when you use that... I dunno, that's like saying that `if` hides branching. It's a language-level reserved word, you're expected to understand how they work under the hood.
- ArtixFox 5y agoyes, our first priority is stage2, after that, we might deal with stdlib. Andrew is going to go through the stdlib before the 1.0 release.
- dnautics 5y agoit's super reasonable to expect language-level stability before shoring up the stdlib. I know 'gatekeeping' is a bad word sometimes here, but this is soft-gatekeeping, and imo, a good thing (for now) to help focus the language.
- ArtixFox 5y agounfortunately yes, it somewhat is, but the devs try to maintain extremely readable source, not the best thing but i think its really good and important cuz its the best example of good zig code and might teach you a bit or two like i learnt how to write saner and better code. and the stdlib breaks sometimes soo its better to not put a loot of effort in docs
- guidorice 5y ago> I wanted something more like Rust’s cargo test that’d find all tests and run them. Maybe Zig does have this but I just didn’t find it? Try `zig build test` https://ziglang.org/documentation/master/#Zig-Build-System https://ziglang.org/documentation/master/#Zig-Build-System
- moffkalast 5y agoNow you can really move zig. For great justice.
- guidorice 5y agoCorrection: https://github.com/ziglang/zig/issues/10018 https://github.com/ziglang/zig/issues/10018
- gilbetron 5y ago> One nugget of knowledge I’ve worked out though - Zig is not a replacement for C. It is another replacement for C++. I hope this isn't the case, since I see Rust as the C++ replacement, and another replacement isn't very interesting to me. The main reason I've been interested in Zig is because I thought it was a replacement for C, which is an interesting idea.
- dnautics 5y agoI don't understand where that came from. It's really a replacement for C. The place where complexity comes from in zig is pretty much the comptime type system, which is emergent from the idea of replacing irregular consteval rules for C and replacing preprocessor macros I would say that Zig is: C - {make, autoconf, etc., preprocessor, UB[0]} + {*defer, !, ?, catch/try, "async"[1], alignment, comptime} I don't think that rises to the level of "C++ replacement". Maybe it's that comptime lets you do generics a la C++ templates? [0] by default, in zig you can have UB for performance [1] in quotes because async is not actually async, it's a control flow statement that is usually and most usefully used to do async things.
- isaiahg 5y agoThat's the one part in which I really disagreed and the author does a bad job of explaining why they think that.
- ncmncm 5y agoHint: Rust will not be replacing C++. C++ and Rust will coexist indefinitely. At some point in the future, it is possible that more Rust coders will be using it daily in their work than the number who pick up C++ for the first time in any given week, who will go on to use it professionally. Or, that might not happen, and Rust will join Ada and so many other languages that never got their miracle. Even if Zig doesn't fizzle like the overwhelming majority of languages, it won't replace, or displace, C, never mind C++. Everybody willing to move on from C already did a long time ago. People still using C today like it for its failings, so a language that fixes them is exactly what they don't want. It doesn't give C++ users any of the things they need. The only real advance in systems languages in the last 50 years is the destructor, so it is frankly weird to find a new language without it. The Drop trait is all that makes Rust a viable prospect for its own miracle.
- flohofwoe 5y agoThe part about making things easy to type is interesting, because this generally only works with a single international keyboard layout (usually US English), e.g. making things easy to type on the US keyboard layout may make it harder on an international layout. It's an old problem though, for instance the {}[] keys are terribly placed on the German keyboard layout, requiring the right-Alt-key which was enough for me to learn and switch to the US keyboard layout, and not just for coding. I think a better approach for a programming language would be to use as few special characters as possible. PS: Zig balances the '|' problem by using 'or' instead of '||' ;)
- formerly_proven 5y agoI've heard this before but personally I've never had a problem with {}[], I just use the right thumb for shifting to the ancient greek layer.
- dralley 5y ago>PS: Zig balances the '|' problem by using 'or' instead of '||' ;) I wish Rust had made that decision as well.
- e12e 5y agoIt's a bit bizarre to complain about the pipe symbol IMNHO (as a user of Norwegian kbd layout, where åæø/ÆØÅ takes up prime estate) - without pipe you can't use a posix shell at all - so if you're on a layout without pipe, it's not like you likely could use any languages outside Smalltalk/Self, or possibly Pascal... That said, yes, I think there's room for languages with very limited use of special characters. But I think they'd always be somewhat specialized. Like Markdown.
- e12e 5y ago> For loops are a bit strange too - you write for (items) |item| {} >, which means you specify the container before the per-element variable. Mentally I think of for as for something in many_things {} and so in Zig I constantly had to write it wrong and then rewrite. That does feel like the syntax is missing an "each" or a "with", as in "for each somethings as some do" or "with each somethings as some" - or in a similar terse/compact syntax: each (items) |item| {} I'm surprised there's no mention about (lack of) string type - considering the domain (advent of code). I've not found the time to actually work on aoc this year, but I also had a brief look at starting with Zig - and quickly met a bit of a wall between the terse documententation on allocator, and the apparent lack of standard library support for working with strings. I think the documentation will improve as the language stabilizes and there's likely to be more tutorials that work with text (both trivial like sirt/cat/tac in zig, and more useful like http or dns client and servers etc).
- kzrdude 5y agoIn "The Good" section, the author says there are only while loops and no for.. but apparently there is a for, now I'm unsure what it means. Is `for` a function?
- firethief 5y ago`for` is a foreach. If you want to increment a number through a range like a typical C `for`, you have to use a `while` loop. I don't really see the draw.
- dnautics 5y agoman if I were andrew I'd just rename for to "foreach", because this is a huge complaint and source of confusion.
- kzrdude 5y agoSeems fine to me. Rust has a "foreach" which is named for, working ok. Of course Rust has ranges as iterators, so it's not necessarily noticed that "there is no numerical for" but it works.
- deleted 5y ago[deleted]
- fmakunbound 5y ago> and so making getting at heap allocations harder by explicitly getting them through an allocator is a great thing. Did not follow this logic.
- llimllib 5y agoI think the idea is that heap allocations are costly, so making them explicit exposes their cost clearly, and promotes careful thought about strategies for heap allocaiton.
- ModernMech 5y agoHow is that any more explicit or intentional than calling malloc though? You have to tell it exactly how many bytes you want on the heap.
- anonymoushn 5y agoIt's more explicit to pass an allocator to things that will allocate than not to, in the same way that other local variables are more explicit than other global variables. By cultural convention, you'll be able to bring your own allocators to almost any library, so you won't have to let your libraries decide when your program performs heap allocations.
- formerly_proven 5y agoZig makes it supremely easy to use different allocators for different pieces so you can do much better than just calling malloc everywhere. This enables very easy and straightforward use of arena allocators in particular.
- sirwhinesalot 5y agoIf I call some function foo() I have no idea if it does any heap allocation internally. In zig I always know because all functions that allocate memory explicitly request an allocator. That also allows me to control which allocator they use.
- anatoly 5y agoI also did AoC 2021 in Zig: https://github.com/avorobey/adventofcode-2021 https://github.com/avorobey/adventofcode-2021 One thing the OP didn't mention that I really liked was runtime checks on array/slice access and integer under/overflow. Because dealing with heap allocation is a bit of a hassle, I was incentivized to use static buffers a lot. I quickly figured out that I didn't have to worry about their sizes much, because if they're overrun by the unexpectedly large input or other behavior in my algorithms, I get a nice runtime error with the right line indicated, rather than corrupt memory or a crash. Same thing about choosing which integer type to use: it's not a problem if I made the wrong choice, I'll get a nice error message and fix easily. This made for a lot of peace of mind during coding. Obviously in a real production system I'd be more careful and use dynamic sizes appropriately, but for one-off programs like these it was excellent. Overall, I really enjoyed using Zig while starting out at AoC problem 1 with zero knowledge of the language. To my mind, it's "C with as much convenience as could be wrung out of it w/o betraying the low-level core behavior". That is, no code execution hidden behind constructors or overloads, no garbage collection, straight imperative code, but with so much done right (type system, generics, errors, optionals, slices) that it feels much more pleasant and uncomparably safer than C. (you can still get a segmentation fault, and I did a few times - by erroneously holding on to pointers inside a container while it resized. Still, uncomparably safer)
- geokon 5y ago"runtime checks on array/slice access and integer under/overflow" I'm probably missing something. I feel like you'd get this and a lot of the other benefits you list if you just compile C/C++ with Debug options - or run with Valgrind or something. Are you saying you get automatic checks that can't be disabled in Zig? (that doesn't sound like a good thing.. hence I feel I'm missing something :) )
- JediPig 5y agoI get this feeling its a one / two / three man I want to write a compiler phase. I seen dozens of these languages over the years. I looked at the language, and without something revolutionary, this will die a slow death. I think it is experiencing that , main developer(s) are using crowd funding and nothing has really been "wow". I was right about dart and flutter being the next big one. However, zig is a dead language in a grave yard of 100s. It tries to revolution coding without changing the methodology.
- jimbob45 5y agoDart has a lot of really neat features that should have caught on in other languages by now. In particular, the Dart ".." operator, implicit interfaces on every declared class, and mixins really should have made their ways to C# and Java by now.
- kristoff_it 5y agoI'd say comptime and having enough features to be better than C at using and (cross-) compiling C libraries is somewhat revolutionary.
- anonymoushn 5y agoWere you right about Dart being the next dead language or the next language propped up by Google? We're having a great time using Zig in production. Thanks.
- ArtixFox 5y agonice! where are u using zig in production?
- nick__m 5y agoTo me Zig doesn't seems like a zombie. * It is actively developed, has frequent releases and it is steered toward a stable 1.0 * The crowd funding model proves that some users want that language. * It doesn't try to revolutionize coding, it tries to be a better C, hence the wowlessness Nim¹ and Crystal² have probably more chances of eventually becoming dead languages but I hope they don't as they are both fun languages. 1- https://nim-lang.org/ https://nim-lang.org/ : Nim is a statically type checked compiled Pythonesque language with a type system residing somewhere between Pascal and Ada. 2- https://crystal-lang.org/ https://crystal-lang.org/ : Crystal is a statically type checked compiled Ruby-like language.
- OtomotO 5y agoThe one thing I personally love about Zig, from an outsiders perspective, is the relatively clear scope and the "no, we won't add each and every feature we can imagine"-stance. It also seems rather elegant.
- ArtixFox 5y agothe world has learnt from the horrors of C++, the same mistakes should not be repeated lol.
- formerly_proven 5y agoThe optionals story in Zig seems a bit weak to me, because it has dedicated syntax to support conditional unwrapping: if(optional) |captured_optional| { ... } if actually is three different syntaxes: if(expression) {} else {} if(optional) |captured| {) if(optional) |captured| {) else {} if(errunion) |result| {} else |err| {} The latter is kinda awkward because it looks exactly like the optional syntax until the else and you have to know the type of the variable to know which is which. Capturing doesn't allow shadowing, which makes the optional case awkward. This is one area that e.g. Kotlin has done better by checking if the expression of any if statement implies non-nullity of variables and then implicitly unwrapping them, as they can't ever be null: if(optional != null) { use optional directly } This works much better for multiple optionals: if(optA != null && optB != null) { can use both optA and optB directly } You can write this in Zig as well, but it results in a sea of unchecked .?, while Kotlin while give you compile errors if you use an optional without unwrapping that was not implied to be non-null. Or you go multiple levels deep, as the if-optional syntax only allows one optional: if(optA) |capturedOptA| { if(optB) |capturedOptB| { } } The error union story is fairly sound so far but one major annoyance is that while it composes well for returning errors, it doesn't compose well for error handling. You can't do: someComplexThing(file1, file2) catch |err| switch(err) { CryptoErrorSet => handle_crypto_error(err); FileErrorSet => ... } as switch does not support error sets for branches, only error values. This seems to me like it incentivizes you to do have either something like this: someComplexThing(file1, file2) catch |err| { if(cryptoErrorToString(err)) |errdescription| { // ... } if(ioErrorToString(err)) |errdescription| { // ... } } Or just a huge handleAllTheErrorsPls thing. Errors are also just a value - if you want some extra information/diagnostics to go along with an error, you'll have to handle that yourself out-of-band. On errors, Zig doesn't seem to have a strerror for std.os errors - awkward.
- kristoff_it 5y ago> you have to know the type of the variable to know which is which. That's not correct. The error version differs from optional by the capture on the else branch. The optional version can't have it, and all error versions must have both captures. You can always tell which case it is just by looking at the code, without having to know the types involved.
- travisgriggs 5y agoComputer language inventors are torn between a voice whispering “use the language Luke” and and a more gravelly “let your feelings for the compiler grow, embrace the syntax side.” I did a two-day sprint through Zig a month ago and really really liked it. It has some quirks that I would have done differently, but overall I think it’s pretty cool. I just need a good small scale project to try it out on now. My favorite example of the “use the language” ethos is the way Zig does generics. I have hated generics/templates in every language I use them in. They are the gordian knot of confusion that most languages in pursuit of some sort of unified type theory impale themselves on (yes, I’m mashing metaphors here). But Zig just uses its own self to define user types and generics come along for free. It resonates (with me at least) as a realization of what Gilda Bracha has shared about how to reify generics. [1] https://gbracha.blogspot.com/2018/10/reified-generics-search-for-cure.html?m=1 https://gbracha.blogspot.com/2018/10/reified-generics-search...
- jstimpfle 5y agoI've grown used to the idea that generics (data structure macros, C++ templates...) aren't that useful. If I find myself in a situation where I'm thinking of a solution that involves generics, I stop and ponder what is actually the essence of the repeated stuff. It rarely is on the syntactic level, often it runs deeper. Probably the commonalities can be distilled into a data structure. Simple example: Intrusive linking headers (e.g. Linux kernel list.h). While those can benefit from an optional very very thin generics layer on top, essentially the code for linking e.g. nodes in a tree should be the same regardless of the data structure where the headers are embedded. Getting this right simplifies the code but can also speed up compile times.
- pcwalton 5y agoHow do you write a generic quicksort function without generics? There are two ways I know of: (1) throw type and memory safety out the window and use void pointers plus size/alignment like qsort(3) does; (2) require that users manually write an interface with a swap(int i, int j) function like Go before generics does. Both solutions are really bad.
- ncmncm 5y agoAll it needs to be actually useful is destructors. And, constructors. I am always amazed when a new language omits destructors. Sure, CS assignments don't need them, but out here we have real resources, not just memory, to manage.
- kristoff_it 5y agoThere's plenty of great languages with those features. Zig brings a different mindset to programming, so you need to empty your cup of tea before being able to enjoy Zig. https://ashidakim.com/zenkoans/1acupoftea.html https://ashidakim.com/zenkoans/1acupoftea.html
- jstimpfle 5y agoThe application I'm working on has about 8K lines of bare bones C + Win32 + some optional OpenGL currently. It probably has about 5 lines of repetitive cleanup code that can't be easily folded into a single place (so might benefit from RAII style cleanup). If I want to properly release even "static" resources so the app can be used as a library (which is not necessary), that number might grow to 20 lines. It's not something I'm sweating about, and I'm happy about all the time I saved by not doing "proper" RAII design prematurely, which has more ramifications and constraints than one might think.
- flohofwoe 5y agoMost of the problems that C++ added on top of C are caused by RAII though (e.g. a too rigid coupling of code and data). I think Zig made the right decision with the 'defer' keyword, even if it requires some change of perspective.
- deleted 5y ago[deleted]
- ncmncm 5y agoBy "problems" I guess you meant usefulness: "Most of the usefulness that C++ added on top of C is a product of RAII." Because usefulness is why C++ is used so much. And, "too rigid" meaning maximally flexible, likewise.
- rStar 5y ago
- kaba0 5y agoHow does it compare to other C-replacement languages, like Beef?
- balaji1 5y agoI got into Rust by working on Advent of Code 2021. The problems seem arbitrary, repetitive and sometimes unnecessarily hard. But they are well-designed for starting on a new language. We are forced to repeatedly use basic concepts of a language, so that is useful to get a few reps in on a new language. We are also forced to build utils that can be used a few times. And if you challenge yourself to solve the problem as quickly as possible so as to see where the story leads, you can stay motivated to work thru the problems. Helps if you have a friendly competition going with a few friends.
- deleted 5y ago[deleted]
- adamrezich 5y ago> For loops are a bit strange too - you write for (items) |item| {}, which means you specify the container before the per-element variable. Mentally I think of for as for something in many_things {} and so in Zig I constantly had to write it wrong and then rewrite. Also you use the | character in Zig quite a lot, and while this may just be a problem with Apple UK keyboards, actually getting to the | character on my laptop was uncomfortable. When doing C/C++ or Rust, you use the | character much less and so the pain of writing the character was something I never noticed before. Jonathan Blow has gone on the record to say that with his language, Jai, he spent a lot of time working out how easy it would be to type common things, such that the more common an operation in the language, the easier it would be to type. I've written much more "Jai" than Zig but this is one of the things that stuck out to me the most in Zig's syntax as being strange. in "Jai", for loops iterate over arrays, ranges (0..10), or anything else that has a for_expansion defined for it. implicitly, "it" is the iterator and "it_index" is the index. to for-loop over an array, you simply write foos: [..] int; for foos { /*...*/ } if you don't want to use it and it_index, likely because you're nesting loops, you write for foo: foos { } for foo, foo_index: foos { } this has some very nice properties in addition to relative terseness: when you want to iterate over something, which is something you do all the time in all kinds of contexts, you just write "for foos do_something_to_foo(it);" suddenly you find you need to use something other than the implicit it/it_index, so you just change it to "for foo: foos do_something_to_foo(foo);" maybe when you're "sketching out" your program code, "foos" is just an array of ints, but as you flesh things out further, you realize you want it to be a custom data structure with additional information that can nonetheless be iterated over as if it were still an array. you simply write a for_expansion for the new data structure: Foo_Storage :: struct { items: [..] int; additional_info: string; } for_expansion :: (using storage: *Foo_Storage, body: Code, flags: For_Flags) #expand { for `it, `it_index: items { #insert body; } } foos: Foo_Storage; for foos { /*...*/ } // the loop interface remains unchanged I completely agree with the author here in that I appreciate this approach as opposed to Zig's, with regards to making it as easy as possible to write basic constructs ("loop over some stuff") that you're going to be writing a lot, in a lot of different places, in a lot of different contexts, all the time, constantly. this is the one area in which this language and the design ethos behind it is completely different from Zig and other contemporaries—it balances power and simplicity with developer ergonomics quite nicely.
- arch_rust 5y agoThere is an open issue for something like `cargo test` https://github.com/ziglang/zig/issues/10018 https://github.com/ziglang/zig/issues/10018
- hota_mazi 5y agoCan someone more knowledgeable than me in Zig explain this: > var x = try foo(); means x is equal to the result of foo() unless there was an error in the result. > If there was an error, return from the function with the error now. > This meant that you don’t have the messy littering of if conditionals after every function that you > typically get in C, but you also don’t have the complete disaster that is exceptions in C++/C#. How is this different from exceptions? Exiting a function immediately in case a function call fails sounds exactly like an exception.
- von_lohengramm 5y agoBecause it's a part of the type signature and cannot be accidentally ignored. Every possible error case must be handled when unwrapping the error value.
- hota_mazi 5y agoSo... like checked exceptions (e.g. Java needs to declare those in the signature, and they are an integral part of said signature). The more I hear about how Zig implements it, the more it is exactly like exceptions.
- von_lohengramm 5y agoIt is different in implementation, for better or worse. Instead of stack unwinding, it's a part of the return value.
- masklinn 5y ago> The more I hear about how Zig implements it, the more it is exactly like exceptions. It's exactly like exceptions aside from all the problematic bits of exceptions: * it is very explicit * it is much easier to interact with * it can be abstracted over (since a "result" is a reified value of a known type) * it supports but is not over-optimised for happy path or split-path scenarios * it doesn't require separate allocations or RTTI * it has a much more uniform cost model That doesn't necessarily mean it's the right system for what you usually work with, but it's a really nice way to do error handling. For an expansion of this, Brian Cantrill has a paean to this error handling style in his "falling in love with rust"[0], I can't direct-link the section but it's "1. Rust’s error handling is beautiful". [0] http://dtrace.org/blogs/bmc/2018/09/18/falling-in-love-with-rust/ http://dtrace.org/blogs/bmc/2018/09/18/falling-in-love-with-...
- ptrwis 5y agoIf dereferencing the pointer is through ptr.*, wouldn't it be more consistent to take the address with myvar.& instead of &myvar?
- hermitsings 5y agoHelpful article.
- butterisgood 5y agoZig is definitely a C replacement in my opinion. I agree about the array and pointer syntax being hard to remember. I’ve high hopes for the language.