[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)