[HN Gopher] Ziglings: Learn the Zig programming language by fixi... ___________________________________________________________________ Ziglings: Learn the Zig programming language by fixing tiny broken programs Author : DyslexicAtheist Score : 229 points Date : 2021-02-13 17:39 UTC (5 hours ago) (HTM) web link (github.com) (TXT) w3m dump (github.com) | haberman wrote: | Neat concept. Exploring the difference between what successfully | compiles vs. what won't seems like a great way of getting more | familiar with the language. | | I've written a little over 1,000 lines of Zig at this point and I | really like it. I think its key feature is a rich compile-time | imperative programming environment ("comptime"). If you can have | full compile-time imperative code execution, you can get a lot of | the benefits of more complicated language features (like C++ | templates) "for free." | | In C++ templates are "a language within a language", but even | templates with all their complexity cannot solve all of the | problems you might want to solve at compile-time, so C++ has been | gradually expanding its compile-time code execution features so | that more and more of the language is available at compile-time | (constexpr, consteval, etc). Zig jumps straight to the finish | line by making most of the language available at compile-time | from the outset, and in doing so avoids the need to add the | complexity of templates in the first place. | | Having "slices" as a first class type feels like a general and | powerful solution to the problems that std::string_view and | std::span are trying to solve. | | I am comparing Zig to C++ a lot, which many Zig fans would | probably take exception to as Zig does not aspire to be a better | C++, but rather a better C. Indeed many key C++ patterns like | RAII are explicitly out of scope. But to me Zig bridges the gap | between C and C++ by solving many of the problems that make C | feel too spartan without jumping to the incredible complexity of | C++. | | There are a few things about Zig that give me pause. I've noticed | that compile-time feels like a very lazy environment, meaning | that functions do not seem to undergo full semantic analysis | unless they are called from somewhere. You can write a function | that compiles successfully, leading you to believe the function | is syntactically and semantically coherent, only to find that | when you add an actual _call_ to that function, the compiler now | flags errors inside that function. This adds some friction to | development, because the act of writing a function is no longer a | self-contained activity. Writing the function feels more like | sketching it; later when you actually call it you have a new set | of compile errors to contend with. | | I also miss tools like ASAN to catch memory errors. I'm guessing | things like that will come with time. | | Overall I feel very positive on Zig. | klyrs wrote: | > You can write a function that compiles successfully, leading | you to believe the function is syntactically and semantically | coherent, only to find that when you add an actual call to that | function, the compiler now flags errors inside that function. | | This happens to me pretty frequently in C++. It won't compile | with a syntax error, but if you don't call, say, a templated | function, then the compiler simply can't know that the stuff | you're doing inside is nonsense. | | I don't consider this to be friction. I generally know what | I've called, and what I haven't. I expect dark code to be bug- | ridden placeholders with good intentions. | Hoppetosse wrote: | The standard library has a General Purpose Allocator that can | catch some of the errors that ASAN can, like memory leaks. | kristoff_it wrote: | > I am comparing Zig to C++ a lot, which many Zig fans would | probably take exception to as Zig does not aspire to be a | better C++, but rather a better C. | | I was one of those people that started the idea that Zig should | be compared to C more than C++. One day I'll express more | clearly what I meant by that, but in the meantime I would say | that Zig can and should be compared with C++ too. | | More generally I think we got to the point where Zig deserves | to be analyzed in it's own right and not as a reflection of | another language because, among other things, it leads to this | kind of misunderstanding: | | > I've noticed that compile-time feels like a very lazy | environment, meaning that functions do not seem to undergo full | semantic analysis unless they are called from somewhere. | | Comptime's lazyness is a necessary feature and not an accident. | This is how Zig can avoid having a macro system. | | More in general the idea is that you are supposed to write | tests for your code, which will then ensure your functions get | analyzed, and which in turn will produce documentation for your | code. This makes testing more core to the development process | than it is in other languages. | | I'm not saying everyone has to like this approach, but if you | stop at the comparison with C, you risk missing how the design | of Zig is able to spiral into an new and radical programming | experience. | | See for example this Twitch clip from yesterday: | https://clips.twitch.tv/RockyLivelyChimpanzeeDoubleRainbow-P... | pron wrote: | Totally. Zig is neither a better C nor a better C++, but an | entirely new (and better, IMO) concept for how low-level | programming can and should be done. Zig is about as simple as | C and as expressive and powerful as C++, but it doesn't | follow either's design tradition (unlike Rust, which is very | much in the C++ tradition), and should only be compared to | either one by virtue of all three being low-level languages. | fpoling wrote: | What is C++ tradition? Is it that one does not pay for a | feature unless one uses it? In practice C++ broke with that | with exceptions and RTTI. Even Rust does adhere to it since | its standard library assumes infallible allocations making | one to pay for not relying on it in the form of having to | write an alternative library. | pjmlp wrote: | That would be the case if one wasn't allowed to turn them | off. | haberman wrote: | I'm not sure how my statement was a misunderstanding if you | are confirming that function analysis is in fact lazy. | kristoff_it wrote: | The misunderstanding lies in not realizing how lazy | evaluation is an integral part of what makes comptime a | useful tool and that removing it would break comptime | horribly. | haberman wrote: | That seems a bit of an overstatement. Calls to sometimes- | unavailable functions are but one of the many uses of | comptime. It seems entirely possible that lazily-analyzed | blocks or functions could be demarcated syntactically | (eg. "lazy { }") and that the large majority of comptime | evaluation would not need to be inside such a block. | aarchi wrote: | > Comptime's lazyness is a necessary feature and not an | accident. This is how Zig can avoid having a macro system. | | Can you elaborate on lazy analysis replacing the need for | macros? | defen wrote: | C macros are lazy, but they also operate at the level of | lexical tokens instead of the AST, which means you can use | macros to generate C code, but you can't really do it in a | way that is guaranteed to be safe. | | With Zig you can have a function where some or all | arguments are marked as "comptime", which means the values | for those arguments must be known at compile time. Combined | with the fact that types can be used as values at compile | time means that you can use Zig to generate Zig functions | in a safe way. | dralley wrote: | https://www.youtube.com/watch?v=Gv2I7qTux7g&t=17m10s | Quekid5 wrote: | I'd appreciate some elaboration on that too. It sounds | vaguely similar to SFINAE in C++, but I don't know enough | about Zig's compilation model to know for sure. | | (I'm vaguely familar with Zig from a talk by the creator | about 11/2 years ago, fwiw.) | kristoff_it wrote: | Lazyness is what allows you to write code that feels | naturally coherent but that would be an error with eager | analysis. As an example: | switch(build.target.os) { .Linux => std.os.fork(), | .Windows => std.os.funcUniqueToWindows(), else => | @compileError("feature not supported for target os"), | } | | This a simplified example to say that each path that | depends on a comptime condition, such as the target OS, for | example, feels intuitively consistent but in Zig types can | (and do) mutate depending on those conditions and if the | compiler were to eagerly check dead branches it would find | plenty of semantical errors. In the stdlib you can see how | `os` corresponds to a different struct definition depending | on the target: https://github.com/ziglang/zig/blob/master/l | ib/std/os.zig#L5... | AndyKelley wrote: | This definitely does cause problems though; I want to | acknowledge that. For example, right now we have an issue | that auto-generated documentation does not include | unreferenced globals. | | I have some ideas to address this, but it does represent | a flaw in the status quo design of the language. | fpoling wrote: | Zig compile-time evaluation even allows to construct an | arbitrary type like a struct with a platform-specific members | all using the same core language. This beats even Rust macros | and in retrospect I wonder why this not used in other | languages? Even Lisp ended up with macros with own sub language | instead of making the core language more useful for code | generation. Or consider Go attempts at generics. Something like | Zig approach will fit it more I think than various generics | proposals. | afranchuk wrote: | I would guess one reason it wasn't done in other languages | was because people simply didn't have a good cross- | architecture JIT compilation resource, and didn't want to | write it themselves. LLVM makes this _really_ easy. I realize | that Zig is transitioning to an LLVM-optional model now. But, | for instance, I've been working on an s-expr language with | f-expr application, and this combined with LLVM c bindings | allows you to generate arbitrary compile time or runtime | code. The JIT portion for compile time code was a single | function call in LLVM! I started this a while before Zig came | out, but alas I haven't devoted enough time to it over the | years... | haberman wrote: | I agree it's an idea that seems so natural in retrospect that | I'm also curious why it hasn't traditionally been more | popular. One possible reason that comes to mind is that an | imperatively-constructed type is harder to statically | analyze. | | But on the other hand, even C++ templates are Turing complete | and even C++ parse trees can depend on the output of a | Turing-complete evaluation. So it is hard to see what benefit | a C++-like template feature is buying in comparison. | fpoling wrote: | Even Java and Rust ended up with Turing-complete generics. | bobthebuilders wrote: | Java turing complete generics are an edge case though, | and never hit during normal compilation. | fpoling wrote: | Still the compiler has to deal with that. So one ends up | with an interpreter in the compiler for very esoteric and | hard to write/read language instead of just embedding an | interpreter of a subset of Java. | | One alleged benefit of Java constrained genetics is that | they allow in theory better error messages. Still in | complex cases even after over 15 years with genetics in | Java the error messages are not that great. Zig to some | extend delegates to the compile-time library authors | responsibility of producing good error messages. But then | the error messages can be improved without waiting for | the compiler to improve its reporting heuristics to cover | all edge cases. | pron wrote: | Not only was it not "more popular," I am not aware of even | research languages taking the idea of general-purpose | partial evaluation _not_ through syntax macros to the same | lengths as Zig (although that doesn 't mean there weren't | any). It's possible that no one had thought of that, | perhaps because type systems, while known to be possibly | considered as a form of partial evaluation, are generally | treated and studied as a completely separate concept: | partial evaluation is a compilation technology while types | are part of the theory. | haberman wrote: | > I am not aware of even research languages taking the | idea of general-purpose partial evaluation not through | syntax macros to the same lengths as Zig | | One that comes to mind is Terra: http://terralang.org/ | | In retrospect Terra seems a clear precursor to Zig | (though I don't know if it was a direct influence). | jeltz wrote: | Tow issues I have noticed with Zig: not as good type | signatures for functions and not as good error messages. I | am not sure if those are fundamental issues with Zig's | apporach or if they can be fixed with more work. | mhh__ wrote: | We have a slightly vague proposal in D to basically construct | programs as a library at compile time (i.e. we give you an | AST, you play with it and give it back, if it's valid it.gets | turned into a type). | | D has been making structs at compile time for years now, | however. | gmfawcett wrote: | "Even Lisp ended up with macros with own sub language..." I | assume you're talking about Scheme approaches like `syntax- | case` and `syntax-rules`? In Common Lisp, macros are written | in Lisp, the same way you would write runtime code. Unquoting | and splicing are part of the core language (e.g. they can be | applied to data as well as to code). | fpoling wrote: | I was not aware that unquoting in Common Lisp can be | applied to data. So it is not a specialized sub language | just for macros, but a general purpose template system that | could also generate code. | smallstepforman wrote: | I'm interested in exploring Zig, but the draconian measure to ban | hard tabs is pushing me (and many others from what I've read | online) away from it. Andrew, get off your high horse, allow hard | tabs, and we can all join hands and work together. | anand-bala wrote: | I think the whole point of picking a language standard is to | prevent the "space vs tabs" debate. Andrew is trying to | standardize the language formatting issues, similar to tools | like `rust fmt`, `gofmt` and `black`. | | The "Spaces vs. Tabs" argument shouldn't be what stops you from | joining hands and working together :) | mssundaram wrote: | You're saying this from atop your own high horse. | | I used to fight about prettier (js) gofmt and so on. I just | finally found I don't care. It's more fun to just code and | watch it all get autoformatted to the project or language | standard | zamadatix wrote: | If tabbed indetation not being supported by the stage1 compiler | is enough of a reason to not use a language it's probably best | for zig to avoid those that would make this type of feedback | and vice versa until stage2 and the language are stable (both | support tab indentation, they just aren't finished). | | I'm solidly in the tabs camp myself I just understand | bikeshedding about this class of issue isn't what zig wants | to/should be worrying about at the moment while core components | are still being shifted around and written. In the meantime | "zig fmt" runs as part of my build and life moves on. | leetrout wrote: | I wish these types of projects would identify themselves as koans | in the README or something. Makes it much easier to surface | exercises like this when googling. | | I think this is the best way to learn languages. | | Does anyone know of any for TypeScript? | jamesholden wrote: | I saw your comments and I was thinking to myself.. "They should | have one for Regex (regular expressions). That would be a cool | way to learn it." | | Apparently someone did. -\\_(tsu)_/- TIL | | https://regex101.com/ | nick__m wrote: | Regex101 is especially useful, I use it to check for | catastrophic backtracking1 before committing a regex. | | 1-https://www.regular-expressions.info/catastrophic.html | markbnj wrote: | I have regex101 open in a tab any time I am developing a | regex :). It's an awesome tool, and I especially appreciate | the mini language reference in the lower right corner of the | window. | BasedInfra wrote: | Never heard of koans before, it's a brilliant idea for learning | a new language. | | Opportunity for a index or site for koans. | danpalmer wrote: | Koans are a fairly well-known technique, and if you Google | "<language> koans" you'll find something for most languages. | I like it as a learning style. | gmfawcett wrote: | Let's hope that nobody invents a language called Zen -- | they will run into problems. :) | kristoff_it wrote: | if you want to have a laugh, check the news section of | ziglang.org. There was also a pretty big discussion on HN | at the time. | davegauer wrote: | You're absolutely right. My own first exposure to this type of | learning resource was Ruby Koans. I believe Rustlings (which | was my direct inspiration) also credits RK. I'll update the | README with the grandparent attribution. :-) | yarinr wrote: | https://github.com/typescript-exercises/typescript-exercises | maddyboo wrote: | I love these sorts of resources! I just created an "awesome | list" [1] to keep track of resources specifically centered | around learning by example. I've only got a few so far, several | of them being from this thread. Contributions welcome! | | [1]: https://github.com/b0o/awesome-by-example | jedisct1 wrote: | This is a very good idea! | | A nice way to discover a very promising language. ___________________________________________________________________ (page generated 2021-02-13 23:00 UTC)