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