8 ms·
Zig's Lovely Syntax
- do_not_redeem 1y agoSince we're talking syntax... it's mildly infuriating that the zig parser is not smart enough to understand expressions like `const x=a()orelse b();`. You have to manually add a space before `orelse` -- but isn't that what `zig fmt` is for? I have RSI and it's maddening having to mash the arrow keys and add/remove whitespace until the parser is happy. I've heard the argument that people might confuse binary operators for prefix/postfix operators, but I don't buy it. Who would think an operator named `orelse` is anything but binary?
- hmry 1y ago"Read the file, or else!" The threatening postfix operator
- nateglims 1y agoThe error when you accidentally pass a variable directly instead of in a .{} is also really unclear.
- hiccuphippo 1y agoNo idea why it wouldn't add the space, but you could configure your editor to always add a space after `)` and let zig fmt remove the space when not needed.
- phplovesong 1y agoI find Zig syntax noicy. I dont like the @TypeOf (at symbol) and pals, and the weird .{.x} syntax feels off. Zig has some nice things going on but somehow code is really hard to read, admitting its a skill issue as im not that versed in zig.
- flohofwoe 1y agoThe dot is just a placeholder for an inferred type, and IMHO that makes a lot of sense. E.g. you can either write this: const p = Point{ .x = 123, .y = 234 }; ...or this: const p: Point = .{ .x = 123, .y = 234 }; When calling a function which expects a Point you can omit the verbose type: takePoint(.{ .x = 123, .y = 234 }); In Rust I need to explicitly write the type: takePoint(Point{ x: 123, y: 234); ...and in nested struct initializations the inferred form is very handy, e.g. Rust requires you to write this (not sure if I got the syntax right): const x = Rect{ top_left: Point{ x: 123, y: 234 }, bottom_right: Point{ x: 456, y: 456 }, }; ...but the compiler already knows that Rect consists of two nested Points, so what's the point of requiring the user to type that out? So in Zig it's just: const x = Rect{ .top_left = .{ .x = 123, .y = 234 }, .bottom_right = .{ .x = 456, .y = 456 }, }; Requiring the explicit type on everything can get noisy really fast in Rust. Of course the question is whether the leading dot in '.{' could be omitted, and personally I would be in favour of that. Apparently it simplifies the parser, but such implementation details should get in the way of convenience IMHO. And then there's `.x = 123` vs `x: 123`. The Zig form is copied from C99, the Rust form from Javascript. Since I write both a lot of C99 and Typescript I don't either form (and both Zig and Rust are not even close to the flexibility and convenience of the C99 designated initialization syntax unfortunately). Edit: fixed the Rust struct init syntax.
- do_not_redeem 1y agoZig is planning to get rid of explicit `T{}` syntax, in favor of only supporting inferred types. https://github.com/ziglang/zig/issues/5038 https://github.com/ziglang/zig/issues/5038 So the explanation of a dot standing in for a type doesn't make sense in the long run.
- flohofwoe 1y agoAh, I wasn't aware of that proposal. But yeah in that case I would also heavily prefer to "drop the dot" :) IMHO Odin got it exactly right. For a variable with explicit type: a_variable : type = val; ...or for inferred type: a_variable := val; ...and the same for constants: a_const : type : val; a_const :: val; ...but I think that doesn't fit into Zig's parser design philosophy (e.g. requiring some sort of keyword upfront so that the parser knows the context it's in right from the start instead of delaying that decision to a later time).
- dsego 1y agoZig is noisy and and the syntax is really not elegant. One reason I like odin's syntax, it's minimal and so well thought out.
- ngrilly 1y agoYes, Zig’s syntax is a bit noisier, but it enables things such as using if/for/while/switch in expressions, or using anonymous struct literals to emulate named and default parameters in functions.
- zabzonk 1y agoIn my experience, everyone finds the syntax of their favourite language lovely - I love (mostly) C++.
- jeltz 1y agoI am an exception then. Rust may be my favourite language but the syntax is pretty awful and one of its biggest weaknesses. I also love Ruby but I am pretty meh about its syntax.
- zabzonk 1y agoI don't think many people would start to use a language unless the found the syntax at least a little simpatico - but I guess they could be drawn by the semantics it provides.
- sampullman 1y agoI (almost) don't consider syntax at all when considering a language, just whether it's suitable for the task. The exception is languages with syntax that require a non-standard keyboard.
- jeltz 1y agoI mostly chose languages due to semantics.
- ben-schaaf 1y agoAs someone who works almost exclusively in C++, the whole "most vexing parse" makes the syntax indefensible.
- zabzonk 1y agoIn my experience, people simply go "Doh, of course!" or don't write the wrong code in the first place. It has never caused me any real problems. For those of you that may be curious, or not know C++, in C++ this: Obj x(); is a declaration of a function called x that returns an Obj. Whereas this: Obj x; defines (possibly, depending on context) an instance of the type Obj called x. Most people get over this pretty quickly. If that is your main complaint about a language then the language doesn't have too many problems. Not that I'm suggesting that C++ doesn't have more serious problems.
- MrResearcher 1y agoIt's still not clear to me how you can make two comptime closures with different contents and pass those as a functor into the same function. It needs to have a sort of VTable to invoke the function, and yet since the contents are different, the objects are different, and their deallocation will be different too. Defining VTable in zig seems to be a pretty laborious endeavor, with each piece sewn manually.
- zoogeny 1y agoThere was a recent Zig podcast where Andrew Kelley explicitly states that manually defining a VTable is their solution to runtime polymorphism [1]. In general this means wrapping your data in a struct, which is reasonable for almost anything other than base value types. 1. https://youtu.be/x3hOiOcbgeA?si=Kb7SrhdammEiVvDN&t=7620 https://youtu.be/x3hOiOcbgeA?si=Kb7SrhdammEiVvDN&t=7620
- pton_xd 1y ago"Zig doesn’t have lambdas" This surprises me (as a C++ guy). I use lambdas everywhere. What's the standard way of say defining a comparator when sorting an array in Zig?
- tux1968 1y agoSame as C, define a named function, and pass a pointer to the sorting function.
- tsimionescu 1y agoAnd what if you need to close over some local variable?
- flohofwoe 1y agoNot possible, you'll need to pass the captured variables explicitly into the 'lambda' via some sort of context parameter. And considering the memory management magic that would need to be implemented by the compiler for 'painless capture' that's probably a good thing (e.g. there would almost certainly be a hidden heap allocation required which is a big no-no in Zig).
- nine_k 1y ago...or escape analysis and lifetimes, but we already have Rust %)
- pton_xd 1y agoAs far as I know lambdas in C++ will not heap allocate. Basically equivalent to manually defining a struct, with all your captures, and then stack allocating it. However if you assign a lambda to a std::function, and it's large enough, then you may get a heap allocation. Making all allocations explicit is one thing I do really like about Zig.
- andrepd 1y agoWhy would capturing require a heap allocation? Neither Rust nor C++ do this.
- hardwaregeek 1y agoEveryone agrees that "syntax doesn't matter", but implicit in that is "syntax doesn't matter, so let's do what I prefer". So really, syntax does matter. Personally I prefer the Rust/Zig/Go syntax of vaguely C inspired with some nice fixes, as detailed in the post. Judging by the general success of that style, I do wonder if more functional languages should consider an alternative syntax in that style. The Haskell/OCaml concatenative currying style with whitespace is elegant, but sufficiently unfamiliar that I do think it hurts adoption. After all, Rust's big success is hiding the spinach of functional programming in the brownie of a systems programming language. Why not imitate that?
- nromiun 1y agoThat saying never made any sense to me either. After all syntax is your main interface to a language. Anything you do has to go through the syntax. Some people say the syntax just kind of disappears for them after some time. That never seems to happen with me. When I am reading any code the syntax gets even more highlighted.
- brabel 1y agoI always thought that languages (or at least editors) should allow the user to use whatever syntax they want! It's possible. Just look at Kotlin and Java... you can write the exact same code in both, even if you discount the actual differences in the languages. It's not hard to see how you could use Haskell, or Python syntax, to write the exact same thing. People don't like the idea too much because they think that makes it sharing code and reading code together harder, but I don't buy that because at least I myself, read code by myself 99% of the time, and the few times I read code with someone else, I can imagine we can just agree quite easily on which syntax to use - or just agree to always use the "default" syntax to avoid disagreements. I dream to one day get the time to write an editor plugin that lets you read and write in any syntax... then commit the code in the "standard" syntax. How hard would that be?!
- hinkley 1y agoPeople who do a lot of deep work on code, particularly debugging and rearchitecting, tend to have opinions about syntax and code style that are more exacting. As one of those people I’ve always felt that the people working the code the hardest deserve to have an outsized vote on how to organize the code. Would that potentially reduce throughput a bit? Probably. But here’s the thing: most management notice how the bad situations go more than the happiest path. They will kick you when you’re down. So tuning the project a bit for the stressful days is like Safety. Sure it would be great to put a shelf here but that’s where the fire extinguishers need to go. And sure it would be great not interrupting the workday for fire safety drills, but you won’t be around to complain about it if we don’t have them. It’s one of those counterintuitive things, like mise en place is for a lot of people. Discipline is a bit more work now for less stress later. You get more predictable throughput from a system by making the fastest things a little slower to make the slow things a lot faster. And management needs predictability.
- bscphil 1y ago> Like Rust, Zig uses 'name' (':' Type)? syntax for ascribing types, which is better than Type 'name' I'm definitely an outlier on this given the direction all syntactically C-like new languages have taken, but I have the opposite preference. I find that the most common reason I go back to check a variable declaration is to determine the type of the variable, and the harder it is to visually find that, the more annoyed I'm going to be. In particular, with statically typed languages, my mental model tends to be "this is an int" rather than "this is a variable that happens to have the type 'int'". In Rust, in particular, this leads to some awkward syntactic verbosity, because mutable variables are declared with `let mut`, meaning that `let` is used in every declaration. In C or C++ the type would take the place of that unnecessary `let`. And even C (as of C23) will do type inference with the `auto` keyword. My tendency is to use optional type inference in places where needing to know the type isn't important to understand the code, and to specify the type when it would serve as helpful commentary when reading it back.
- SkiFire13 1y ago> In C or C++ the type would take the place of that unnecessary `let` In my opinion the `let` is not so unnecessary. It clearly marks a statement that declares a variable, as opposed to other kind of statements, for example a function call. This is also why C++ need the "most vexing parse" ambiguity resolution.
- reactordev 1y agoI’m in the same boat. It’s faster mentally to grok the type of something when it comes first. The name of the thing is less important (but still important!) than the type of the thing and so I prefer types to come before names. From a parser perspective, it’s easier to go name first so you can add it to the AST and pass it off to the type determiner to finish the declaration. So I get it. In typescript I believe it’s this way so parsers can just drop types all together to make it compatible with JavaScript (it’s still trivial to strip typing, though why would you?) without transpiling. In go, well, you have even more crazier conventions. Uppercase vs lowercase public vs private, no inheritance, a gc that shuns away performance minded devs. In the end, I just want a working std library that’s easy to use so I can build applications. I don’t care for: type Add<A extends number, B extends number> = [ …Array<A>, …Array<B>, ][“length”] This is the kind of abuse of the type system that drives me bonkers. You don’t have to be clever, just export a function. I don’t need a type to represent every state, I need intent.
- Y_Y 1y ago> C uses a needlessly confusing spiral rule Libellous! The "spiral rule" for C is an abomination and not part of the language. I happen to find C's type syntax a bit too clever for beginners, but it's marvellously consistent and straightforward. I can read types fine without that spiral nonsense, even if a couple of judicious typedefs are generally a good idea for any fancy function types.
- throwawaymaths 1y agoIt's not context free though.
- Rusky 1y agoIt is context free, just ambiguous.
- Twey 1y ago> fancy function types If the syntax were straightforward, plain old function types wouldn't be ‘fancy’ :)
- Y_Y 1y agoAmbiguous parse. I don't mean that all function types are fancy, I mean that some are fancy (when you have a function pointers in the arguments or return value, or several layers of indirection), and that those which are fancy are helped by typedefs.
- Twey 1y agoI maintain — they shouldn't be fancy. ‘Fancy’ is the mark of something your language doesn't support well. They can be _long_, and that's often worth breaking up, but if something is ‘fancy’ it's because it's not clear to read, so you should attach some identifier to it that explains what it's supposed to mean. That's significantly, though not exclusively, a function (ha) of the syntax used to express the concept. If you're working with Roman numerals, division is a very fancy thing to do.
- pjmlp 1y agoHaving @ and .{ } all over the place is hardly lovely, as is having modules like JavaScript's CJS.
- Akronymus 1y agoIt's especially bad on a qwertz keyboard as well.
- flohofwoe 1y agoThat's why "real programmers" use English keyboard layout regardless of the physical keyboard ;) Curly brace syntax would never have been invented in Europe (case in point: Python and Pascal).
- Akronymus 1y agoOh for sure. I am using qwerty myself. And my fav language (f#) has relatively few curly braces.
- christophilus 1y agoF# is wonderful. I wish someone would make an F# that compiled as fast as OCaml or Go and which had Go’s standard library and simple tooling.
- pjmlp 1y ago.NET ecosystem is only matched by Java, and Native AOT exists, even if there are some issues with printf, due to its current implementation.
- pjmlp 1y agoReal programmers deliver business value, regardless of what keyboard they have at their disposal. Just like great musicians make the difference in the band, regardless of the instruments scattered around the studio.
- the__alchemist 1y agoI wish Zig had lovely vector, quaternion, matrix etx syntax. The team's refusal to add operator overloading will prevent this.
- flohofwoe 1y agoYou don't need operator overloading for vector and matrix math, see pretty much all GPU languages. What Zig is missing is a complete mapping of the Clang Extended Vector and Matrix extensions (instead of the quite limited `@Vector` type): https://clang.llvm.org/docs/LanguageExtensions.html#vectors-and-extended-vectors https://clang.llvm.org/docs/LanguageExtensions.html#vectors-... https://clang.llvm.org/docs/LanguageExtensions.html#matrix-types https://clang.llvm.org/docs/LanguageExtensions.html#matrix-t...
- renox 1y agoAgreed, their reason for not allowing it is weird. No hidden overloading? OK make it explicit then: #+, #/ would be fine.
- Cyph0n 1y agoThat would open a can of worms, because then the next thing would use a different symbol. AFAIK, Scala had a huge issue with random symbols polluting code readability.
- renox 1y agoThat's not a reasonable objection, each proposal must be evaluated on its own, not on other non existing future proposal.
- nromiun 1y agoI like Zig as well, but I won't call its syntax lovely. Go shows you can do pretty well without ; for line breaks, without : for variable types etc. But sure, if you only compare it with Rust, it is a big improvement.
- nine_k 1y agoI personally find Go's bare syntax harder to parse when reading, and I spend more time reading code than typing it (even while writing). An excessively terse syntax becomes very unforgiving, when a typo is not noticed by the compiler / language server, but results in another syntactically correct but unexpected program, or registers as a cryptic error much farther downstream. Cases in point: CoffeeScript, J.
- nromiun 1y agoThat is why syntax debates are so difficult. There is no objectively best syntax. So we are all stuck with subjective experience. For me I find Python (non-typed) and Golang syntax easiest to read. Too many symbols like ., :, @, ; etc just mess with my brain.
- aatd86 1y agoYes it's sigils that are the culprits more often than not. They are often semantically irrelevant and just make things easier to parse for the machines. Happy Go doesn't indulge too much in them.
- IshKebab 1y agoRemoving stuff doesn't necessarily make the syntax better, otherwise we'd all use Lisp and the space bar wouldn't exist: https://en.wikipedia.org/wiki/Scriptio_continua https://en.wikipedia.org/wiki/Scriptio_continua
- nromiun 1y agoTrue. But my point is that adding stuff doesn't necessarily make the syntax better either. Otherwise we would all be using Perl by now. The sweet spot is somewhere in the middle.
- Western0 1y agoLove Ruby and Cristal syntax ;-)
- darthrupert 1y agoAbsolutely. Kinda of the best of many worlds, because it has what looks like an indentation-based syntax but actually blocks are delimited by start and end keywords. This makes it possible (unlike, say, python) to programmatically derive correct code formatting more reliably. And no pointless semicolons.
- jeffWrld 1y ago[dead]
- WalterBright 1y agoconst x: i32 = 92; D has less syntax: const int x = 92; Just for fun, read each declaration out loud.
- WalterBright 1y agoZig: const std = @import("std"); D: import std;
- brabel 1y agoI think this is not equivalent because in D, this imports all symbols in the package `std` while in Zig, you just get a "struct" called `std`. I think the equivalent D is: import std=std;
- WalterBright 1y agoWhat I wrote is equivalent to the zig declaration. Google says: const my_module = @import("my_module.zig"); This allows you to access pub (public) declarations from my_module.zig through the my_module identifier.
- brabel 1y agoYes, but how is that equivalent? Zig: const std = @import("std"); pub fn main() !void { // std is like a namespace here std.debug.print("Hello, World!\n", .{}); } D: import std.stdio; void main() { // no namespace here, "writeln" and everything else in "std.stdio" is imported writeln("Hello, World!"); } The closest to Zig in D would be: import io = std.stdio; void main() { io.writeln("Hello, World!"); }
- WalterBright 1y agoYou can write in D: std.stdio.writeln("Hello, world!");
- 1y ago
- lvl155 1y agoZig is just fun to write. And to me, it’s actually what I wish Rust was like. Rust is a great language, and no one’s going to argue that point but writing Zig for the first time was so refreshing. That said, Rust is now basically default for systems and Zig came too late.
- throwawaymaths 1y agonever underestimate second mover advantage. if zig gets static borrow checking, it would be amazing
- Twey 1y ago> I think Kotlin nails it: val, var, fun. Note all three are monosyllable, unlike const and fn! At least in my pronunciation, all five of those are monosyllabic! (/kQnst/, /f@n/). (Nice to see someone agree with me on minimizing syllable count, though — I definitely find it easier to chunk[1] fewer syllables.) [1]: https://en.m.wikipedia.org/wiki/Chunking_(psychology) https://en.m.wikipedia.org/wiki/Chunking_(psychology) The use of Ruby block parameters for loops in a language without first-class blocks/lambdas is a bit weird to me. I might have preferred a syntax that looks more like normal variable binding.
- losvedir 1y ago> Note all three are monosyllable, unlike const and fn! I'm not sure if I'm parsing this right, but is the implication that "const" is not monosyllabic? It certainly is for me. How else do people say it? I get "fn" because people might say "eff enn" but I don't see what the equivalent for const would be.
- z_open 1y ago> Raw or multiline strings are spelled like this: const still_raw = \\const raw = \\ \\Roses are red \\ \\ Violets are blue, \\ \\Sugar is sweet \\ \\ And so are you. \\ \\ \\; \\ ; This syntax seems fairly insane to me.
- steveklabnik 1y agoI had the exact opposite reaction.
- fcoury 1y agoI really like zig but that syntax is indeed insane.
- IshKebab 1y agoMaybe if you've never tried formatting a traditional multiline string (e.g. in Python, C++ or Rust) before. If it isn't obvious, the problem is that you can't indent them properly because the indentation becomes part of the string itself. Some languages have magical "removed the indent" modes for strings (e.g. YAML) but they generally suck and just add confusion. This syntax is quite clear (at least with respect to indentation; not sure about the trailing newline - where does the string end exactly?).
- konart 1y agoI may be missing something but come Go has a simple: `A simple formatted string ` ?
- rybosome 1y agoYours is rendered as: A\n\tsimple\n\t\tformatted\n\t\t\tstring\n\t If you wanted it without the additional indentation, you’d need to use a function to strip that out. Typescript has dedent which goes in front of the template string, for example. I guess in Zig that’s not necessary which is nice.
- qcnguy 1y agoWeird the author finds it lovely and compares to Kotlin, but doesn't find Kotlin superior. Kotlin invested heavily in a really nice curly brace syntax. It is actually the nicest out there. In every point the author makes, it feels like Kotlin did it the same or better. For example: 1. Integer literals. "var a = 1" doesn't work, seems absurd. In Kotlin literals do have strong types, but coercion is allowed when defining variables so "var a = 1" works, and "var a: Long = 1" works even though you can write a literal long as 1L. This means you can write numbers to function parameters naturally. 2. Multi-line string literals. OK this is a neat idea, but what about copy/paste? In Kotlin you can just write """ .. """.trimIndent() and then copy paste some arbitrary text into the string, the indent will be removed for you. The IDE will also help with this by adding | characters which looks more natural than \\ and can be removed using .trimMargin(), only downside is the trimming is done at runtime but that could easily be fixed without changing the language. 3. Record literals. This syntax is called lovely because it's designed for grep, a properly funded language like Kotlin just uses named kwargs to constructors which is more natural. There's no need to design the syntax for grep because Kotlin is intended to be used with a good IDE that can answer this query instantly and precisely. 4. Function syntax. "fn foo(a: i32) i32 {}" seems weird. If the thing that has a type and the type are normally separated by a : then why not here? Kotlin does "fun foo(a: Int): Int {}" which is more consistent. 5. Locals. Agree with author that Kotlin nails it. 6. Not using && or ||, ok this one Zig wins, the Zig way is more consistent and reads better. Kotlin does have `and` and `or` as infix operator functions, but they are for the bitwise operations :( 7. Explicit returns. Kotlin supports blocks that return values and also doesn't need semicolons, so not quite sure what the tradeoff here is supposed to be about. 8. Loops being expressions is kinda cool but the Kotlin equivalent of his example is much easier to read still: "val thing = collection.first { it.foo > bar }". It compiles to a for loop due to the function inlining. 9. Generics. Zig's way seems primitive and unnecessarily complex. In Kotlin it is common to let the compiler infer generics based on all available information, so you can just write "someMethod(emptyList())" and emptyList<T>() infers to the correct type based on what someMethod expects. Overall Zig looks like a lot of modern languages, where they are started as a hobby or side project of some guy and so the language is designed around whatever makes implementing the compiler most convenient. Kotlin is unusual because it doesn't do that. It was well funded from the start, so the syntax is designed first and foremost to be as English-like and convenient as possible without leaving the basic realm of ordinary curly-brace functions-and-oop style languages. It manages to be highly expressive and convenient without the syntax feeling overly complex or hard to learn.
- IshKebab 1y ago> As Zig has only line-comments Such a good decision. There's no reason to use block comments in 2025.
- kcartlidge 1y agoI much prefer C# 11's raw string literals. It takes the indentation of the first line and assumes the subsequent ones have the same indentation. string json = $""" <h1>{title}</h1> <article> Welcome to {sitename}. </article> """; And it even allows for using embedded curly braces as real characters: string json = $$""" <h1>{{title}}</h1> <article> Welcome to {{sitename}}, which uses the <code>{sitename}</code> syntax. </article> """; The $ (meaning to interpolate curly braces) appears twice, which switches interpolation to two curly braces, leaving the single ones untouched.
- Metasyntactic 1y agoJust a minor correction (as I'm the author of c#'s raw string literal feature). The indentation of the final ` """` line is what is removed from all other lines. Not the indentation of the first line. This allows the first line to be indented as well. Cheers, and I'm glad you like it. I thought we did a really good job with that feature :-)
- gf000 1y agoReally not trying to go into any of the "holy wars" here, but could you please compare C#'s feature to Java's multi-line strings? I'm only familiar with the latter, and I would like to know if they are similar in concept or not.
- winwang 1y agoThat's a fantastic design idea, and it seems to require all the other lines to have the same indentation "prefix". Haven't used much C#, but I love Scala's `.stripPrefix` and `StringContext`.
- panzerboiler 1y agoDid you draw inspiration from Swift's multiline string literal, or was it the other way around? The syntax looks very similar, if not identical.
- kcartlidge 1y ago
- yegle 1y ago> As Zig has only line-comments, this means that \n is always whitespace. Do I read this correctly that it replaces `\n` at the end of the line with a whitespace? CJK users probably won't be happy with the additional whitespaces.
- throwawaymaths 1y agothat's not correct.
- ww520 1y agoZig is great. I have fun writing in it. But there’re a few things bug me. - Difficult to return a value from a block. Rust treats the value of the last expression of a block as the return value of the block. Have to jump through hoops in Zig to do it with label. - Unable to chain optional checks, e.g. a?.b?.c. Support for monadic types would be great so general chaining operations are supported. - Lack of lambda support. Function blocks are already supported in a number of places, i.e. the for-loop block and the catch block.
- n42 1y agothis is a really, really good article with a lot of nuance and a deep understanding of the tradeoffs in syntax design. unfortunately, it is evoking a lot of knee-jerk reactions from the title and emotional responses to surface level syntax aesthetics. the thing that stands out to me about Zig's syntax that makes it "lovely" (and I think matklad is getting at here), is there is both minimalism and consistency to the design, while ruthlessly prioritizing readability. and it's not the kind of surface level "aesthetically beautiful" readability that tickles the mind of an abstract thinker; it is brutalist in a way that leaves no room for surprise in an industrial application. it's really, really hard to balance syntax design like this, and Zig has done a lovely and respectable job at doing so.
- Twey 1y ago> it's not the kind of surface level "aesthetically beautiful" readability that tickles the mind of an abstract thinker Rather, the sort of beauty it's going for here is exactly the type of beauty that requires a bit of abstraction to appreciate: it's not that the concrete syntax is visually beautiful per se so much as that it's elegantly exposing the abstract syntax, which is inherently more regular and unambiguous than the concrete syntax. It's the same reason S-exprs won over M-exprs: consistently good often wins over special-case great because the latter imposes the mental burden of trying to fit into the special case, while the former allows you to forget that the problem ever existed. To see a language do the opposite of this, look at C++: the syntax has been designed with many, many special cases that make specific constructs nicer to write, but the cost of that is that now you have to remember all of them (and account for all of them, if templating — hence the ‘new’ uniform initialization syntax[1]). [1]: https://xkcd.com/927/ https://xkcd.com/927/ This trade-off happens all the time in language design: you're looking for language that makes all the special cases nice _as a consequence of_ the general case, because _just_ being simple and consistent leads you to the Turing tarpit: you simplify the language by pushing all the complexity onto the programmer.
- n42 1y agoI considered making the case for the parallels to Lisp, but it's not an easy case to make. Zig is profoundly not a Lisp. However, in my opinion it embodies a lot of the spirit of it. A singular syntax for programming and metaprogramming, built around an internally consistent mental model. I don't really know how else to put it, but it's vaguely like a C derived spiritual cousin of Lisp with structs instead of lists.
- melodyogonna 1y agoVery interesting, Zig seems really nice. There was a severe lack of resources when I tried to get into it few years ago, it is nice to see that situation improving in real time. The part about integer literal is similar to Mojo, with a comp-time type that has to be materialized to another type at runtime. In Mojo though this can be done implicitly so you don't need explicit casting.
- culebron21 1y agoI've been seeing articles on Zig for the last 2 years, and was interested, but it seems the language community is too far from my area of interest -- data and geospatial, and the tools in my sphere in Zig aren't mature enough. E.g. to parse a CSV, you have to use very simple packages or just use a tokenizer and parse the tokens yourself.
- MrBuddyCasino 1y ago> I think Kotlin nails it: val, var, fun. Been saying this, and I find it strange how few agree.
- norir 1y agoFrom my vantage point, Zig's syntax perfectly matches the language: it is ad-hoc, whimsical and serendipitous. It is lacking in grace, elegance and compassion.
- ruuda 1y ago> as name of the type, I think I like void more than () It's the wrong name though. In type theory, (), the type with one member, is traditionally called "Unit", while "Void" is the uninhabited type. Void is the return type of e.g. abort.
- ivanjermakov 1y agoIf I understood `abort` semantics correctly, it has a type of `never` or Rust's `!`. Which has a meaning "unobtainable value because control flow went somwhere else". `void` is closer to `unit` or `()` because it's the type with no allowed values. Cool trick: some languages (e.g. TypeScript) allow `void` generics making parameters of that type optional.
- steveklabnik 1y agoUnit has exactly one allowed value.
- ivanjermakov 1y agoRight, but there is not much semantic difference in having one or having zero allowed values.
- NobodyNada 1y agoThere's a huge semantic difference: a type with zero allowed values can never be constructed. This means that a function that returns an uninhabited type is statically known to not return -- since there's no way it could construct an uninhabited value for a return expression. It also means you can coerce a value of uninhabited type into any other type, because any code which recieves a value of an uninhabited type must be unreachable. For instance, in Rust you can write the following: let weekday_name: &str = match weekday_number { 1 => "Sunday", 2 => "Monday", 3 => "Tuesday", 4 => "Wednesday", 5 => "Thursday", 6 => "Friday", 7 => "Saturday", i => panic!("invalid weekday number: {i}); }; Because panic! aborts the program and doesn't return, its return type is uninhabited. Thus, a panic! can be used in a context where a string is expected.
- ivanjermakov 1y ago> Almost always there is an up-front bound for the number of iterations until the break, and its worth asserting this bound, because debugging crashes is easier than debugging hangs. Perhaps in database systems domain yes, but in everything else unconditional loop is meant to loop indefinitely. Think event loops, web servers, dynamic length iterations. And in many cases `while` loop reads nicer when it has a break condition instead of a condition variable defined outside of the loop.
- pinoy420 1y ago[dead]
- wolvesechoes 1y agoSo Zig is a new darling, eh? I sometimes have an impression that the main purpose of all these new languages is to write blog posts about them. Even if they call themselves general-purpose, they are mostly blog-purpose.
- cyber1 1y agoAt first glance, when I looked through the Zig reference, I didn’t like a lot about its syntax (though syntax isn’t the most important thing for me). But when I tried writing in it, I changed my mind - it’s a concise and convenient language with a very low entry barrier. It feels like Go, and with some C experience, you can quickly start writing functional stuff.
- akkad33 1y agoAll of these examples look weird and unreadable to me. Rust borrows from decades of ML language syntax. I don't think that can go wrong. Not sure where the Zig choices come from but they seem to be there just to look "different"