[HN Gopher] Ziglings: Learn the Zig programming language by fixi...
       ___________________________________________________________________
        
       Ziglings: Learn the Zig programming language by fixing tiny broken
       programs
        
       Author : DyslexicAtheist
       Score  : 389 points
       Date   : 2021-02-13 17:39 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | dleslie wrote:
       | I really wish zig were a gcc frontend; the m68k and sh2 targets
       | available in gcc make it desirable for a certain form of hobby
       | programming.
        
         | danielEM wrote:
         | C target would solve it, I would be happy to use it with sdcc
        
           | dleslie wrote:
           | Ha, making gameboy games in zig would be neat.
        
             | slimsag wrote:
             | A few folks are working on gameboy emulators:
             | https://github.com/nrdmn/awesome-zig#emulators
        
               | dleslie wrote:
               | That's not really the same as producing binaries that can
               | function on original hardware.
        
         | Bekwnn wrote:
         | I'm not sure on the specifics of what you mean, but zig comes
         | bundled with and wraps gcc. `zig cc` command directly forwards
         | to gcc (try `zig cc --version`) and zig's build system can be
         | used to build C programs.
         | 
         | Zig currently is able to target quite a bit. There's a good
         | chance you could open an issue and it would get added, or find
         | an existing issue and see where it is on the roadmap.
        
           | mkishi wrote:
           | Zig ships with clang, not gcc.
        
           | dleslie wrote:
           | I was under the impression it was limited to llvm supported
           | targets; of which m68k is not officially supported.
        
       | aequitas wrote:
       | To bad testing[0] isn't introduced in any of the examples. As
       | breaking the compile step only get's you so far with generating
       | interesting challenges.
       | 
       | [0] https://ziglang.org/documentation/master/#Zig-Test
        
       | account-5 wrote:
       | If I wanted, as a complete novice, to learn a lower level
       | language, where would be the best place to start.
       | 
       | I always get confused by all these new languages. Ive heard of:
       | nim, rust, D, V, and now Zig. Where do I start? Should I start
       | with C or C++? Or pick one of these? But which one?
       | 
       | Im currently looking at Lisp because I read it was good for alot
       | of things. I'm also aware of Go and Swift but not looked into
       | them at all.
        
         | tigerlily wrote:
         | Depends what you want to do. Starting with C is good, because
         | then you get to learn the pitfalls, and hence understand the
         | problems the other languages solve, and their advantages and
         | disadvantages.
        
         | kilburn wrote:
         | What's your goal? Why do you want to learn a "lower level"
         | language? Do you have experience in "higher level" languages?
         | 
         | I would say that a better approach in your case is to start by
         | saying "I want to write programs to solve problems like XXXX",
         | or "I want to learn a language that lands me a job doing YYYY".
         | 
         | For example, if you want to:
         | 
         | - build network services -> golang
         | 
         | - fiddle with OS level stuff (schedulers, memory management,
         | etc.) -> C
         | 
         | - write high performance calculation/simulation programs ->
         | julia
         | 
         | - get a nice solid base that can cover most of the above and
         | has a promising future -> rust
         | 
         | Nim, D, V, Zig are very niche and I wouldn't recommend as a
         | first "lower level" language (because you'll have a harder time
         | finding answers, and they won't give you clear benefits over
         | the other options in any problem space).
         | 
         | C++ is... huge. Modern C++ is a fine language, but you'll have
         | to learn _a lot_ to be able to handle it.
        
           | account-5 wrote:
           | Im not what I consider a programmer though I can program. Ive
           | most experience with Python, on Linux I use shell scripts but
           | am no expert. On windows I use AutoHotKey, though I know most
           | wont consider it a proper language.
           | 
           | My main aim is really to learn about it. I wouldnt mind
           | having a broad general experience in high level and low level
           | before I decide to focus on anything in particular.
           | 
           | I've started looking a compilers and how they work im working
           | through a book about building a compiler. Im really just
           | interested in whats going on in the background. I always find
           | myself wondering about the implementations of the languages
           | I'm using.
        
         | kettro wrote:
         | I agree with pron, C is the best starter here. It is simple
         | enough to get your head around rather quickly, and has very
         | defined concepts. The one place that gets people is pointers,
         | but it's a very important part of software to understand.
         | 
         | C is not "low level", in the assembly sense. It is absolutely a
         | high level language. But it is the simplest, and the one with
         | the most fine control.
        
         | heldrida wrote:
         | Zig is great as a first! Visit ziglearn.com, will get you
         | started!
        
         | pron wrote:
         | Definitely start with C.
         | 
         | Also, unlike the other languages you mentioned, Go and Swift
         | aren't low-level languages. Low-level languages are those that
         | give you very precise control over the machine instructions,
         | almost as much as Assembly. Low-level programming is not as
         | widely important as it used to be, because these days the cost
         | of an instruction does not depend so much on what the
         | instruction itself is but on the current micro-architecture
         | state of the computer (e.g. which data is in which level of the
         | cache; which branches are predicted and how) so even machine
         | code is pretty high-level these days, but in some domains,
         | especially memory-constrained environments, it is still
         | irreplaceable.
        
           | TazeTSchnitzel wrote:
           | > Low-level languages are those that give you very precise
           | control over the machine instructions, almost as much as
           | Assembly
           | 
           | By this definition I would say C is not "low-level"
        
           | skohan wrote:
           | Swift actually does effectively let you get fairly low level
           | in the unsafe API, but for sure it's not the intended use-
           | case for the language.
        
       | 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.
        
           | lenkite wrote:
           | This will be fixed with C++ 20 concepts right ?
        
         | IgorPartola wrote:
         | One of the small but really good features of Zig that
         | immediately stood out to me was the fact that there are no
         | implicit function or method calls. _my.name_ will never call a
         | hidden function. As useful as @property is in Python, it really
         | makes it hard to reason about performance of code until you dig
         | all the way through every bit of every class and type.
        
         | 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.
        
             | dnautics wrote:
             | > Zig is neither a better C nor a better C++, but an
             | entirely...
             | 
             | I agree with your point because zig has evolved, but I do
             | think that it is important to note at least for historical
             | purposes, that zig was created literally as a "better c",
             | and a lot of decisions are made because of some specific
             | pain point X or Y in c
        
             | 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.
        
               | pron wrote:
               | In all low-level languages you don't pay for what you
               | don't use; that's not a design tradition but a
               | requirement of the domain. I'm talking about the
               | tradition of a low-abstraction, low-level language that
               | has many features so that, when it is read on the page it
               | appears as if it were high-level.
        
               | pjmlp wrote:
               | That would be the case if one wasn't allowed to turn them
               | off.
        
               | fpoling wrote:
               | The standard library of C++ assumes exceptions and that
               | dictates code style that, even if one assumes infallible
               | allocations and disable exceptions, one gets suboptimal
               | code. So even with exceptions off one pays the price
               | either in the form of non-standard library or accepting
               | non-optimal performance. And if one has to prepare for
               | fallible allocations, then the standard C++ is of no use
               | at all in practice.
        
               | Quekid5 wrote:
               | > So even with exceptions off one pays the price either
               | in the form of non-standard library or accepting non-
               | optimal performance.
               | 
               | Holy moving goalposts, batman!
               | 
               | The "don't pay..." thing has only ever applied to
               | runtime, there nothing in there about not having to write
               | more code yourself, etc.
               | 
               | (It's also a bit dubious in the first place. Chandler had
               | a good talk about this at one of the CppCon's, IIRC.
               | Can't be bothered to look it up, but it should be on
               | YouTube.)
        
               | pjmlp wrote:
               | I assume you aren't that comfortable with ISO C++, the
               | standard does allow for failible allocations.
               | 
               | That is the role nothrow in placement new, and custom STL
               | allocators as language tool.
               | 
               | Additionally plenty of APIs now have exception and error
               | based versions with noexcept.
        
               | fpoling wrote:
               | The fallible allocators require to use exceptions. There
               | is no way to use, for example, C++ containers with
               | fallible allocators and disabled exceptions.
               | 
               | But even with exceptions enabled fallible allocation in
               | practice does not work. There was an article that made
               | malloc to return null randomly. All tested C++
               | implementations crashed then because they allocated
               | memory when generating exceptions.
        
               | pjmlp wrote:
               | Stop talking in circles and point out ISO C++20 sections
               | then.
               | 
               | I am also curious to see how serious was that article.
        
               | fpoling wrote:
               | http://www.open-
               | std.org/jtc1/sc22/wg21/docs/papers/2019/p070... - this
               | discusses a lot of issues with exceptions as in ISO C++
               | and concrete proposals to make exceptions cost-free. The
               | section 4.3.5 discusses specifically memory allocations.
        
               | pjmlp wrote:
               | Including parts that relate to Linux, have nothing to do
               | with C++ and apply to any programming language.
               | 
               | You also skipped the section where Rust in its present
               | state doesn't has any kind of recovery, it just panics.
        
           | 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.
        
               | JacobCarlborg wrote:
               | In D, all semantic analysis is performed eagerly (I
               | think), except for templates. D also supports CTFE
               | (Compile Time Function Evaluation), `static if`, `static
               | assert` and a few other language constructs that are
               | evaluated at compile time.
               | 
               | I experimented a bit at how D's documentation generator
               | behaves using these language constructs. Here's a snippet
               | of some D code:                 /// some struct
               | description       struct Foo(T) // template       {
               | /// some alias description           alias Result = int;
               | /// some method description           Result foo()
               | {               string a = 3; // this does not normally
               | compile           }                  static if (is(T ==
               | int)) // evaluated at compile time           {
               | /// some method description 2               void bar() {}
               | }                  version (Windows)           {
               | /// some method description for Windows
               | void bazWindows() {}           }                  else
               | version (Posix)           {               /// some method
               | description for Posix               void bazPosix() {}
               | }                  else               static
               | assert(false, "Unsupported platform"); // evaluated at
               | compile time       }
               | 
               | When generating documentation for the above code, and
               | `Foo` has not been instantiated, the generated docs will
               | include `Foo`, `Result`, `foo`, `bar`, and `bazWindows`.
               | This is regardless of platform. The return type of `foo`
               | will be `Result` and not `int`. This clearly shows that
               | the D compiler doesn't perform semantic analysis when
               | generating documentation. When doing a regular
               | compilation and `Foo` is instantiated, `bar` will only be
               | included if `T` is an `int`. `bazWindows` will only be
               | compiled on Windows and `bazPosix` will only be compiled
               | on Posix platforms.
               | 
               | Looking at the implementation, the compiler will generate
               | the docs after semantic analysis and only if there are no
               | errors. But, if `Foo` is never instantiated no errors
               | have occurred so it will continue to generate the docs.
               | 
               | On the other hand, if `Foo` is instantiated (and
               | compiles) the compiler will generate docs for the AST
               | after semantic analysis has been performed and
               | `bazWindows` will only be included if the docs were
               | generated on Windows and `bazPosix` will only be included
               | on Posix platforms. What's weird though, is that it seems
               | `bar` will be included regardless of what type `T` is.
        
               | IgorPartola wrote:
               | But you can still check the syntax of that statement
               | without evaluating it all. You might even be able to
               | check if things like std.os exist.
        
         | vram22 wrote:
         | Is Zig's comptime feature like D's CTFE?
        
         | 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.
        
               | bobthebuilders wrote:
               | Incorrect Java does not have genetics. That is a C++
               | concept.
        
             | 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.
        
               | throwaway17_17 wrote:
               | I'm not clear on what you define syntax macros, but the
               | compile time evaluation that is present in Zig (based on
               | the example and documentation I've seen) are an almost
               | direct implementation of the multistage computation
               | research done late 90s-mid 00s. The papers and such are
               | typically ML based (with a caveat for the early Template
               | Haskell paper in 02) and the underlying constructs of
               | MetaML are very close to what Zig implements. All this
               | work is retroactively semantically underpinned by Rowan
               | Davies and Frank Pfenning work on Modal S4 logic. I don't
               | know if Andy based Zig on this research, but if he
               | didn't, the convergence toward the same theory is a great
               | thing to see.
               | 
               | My current work on a visual programming compatible
               | language also uses this strategy for meta programming, so
               | I'm very familiar with the academic literature. It
               | certainly seems that Zig got this right and is doing well
               | implementing it in a way that is usable and
               | understandable.
        
               | pron wrote:
               | By syntax macros I mean expressions that can be
               | referentially opaque, i.e. m(a) and m(b) might have
               | different semantics even though a and b have the same
               | reference. Lisp (and C, and Haskell, and Rust) is
               | referentially opaque while Zig is transparent. Opacity is
               | strictly more expressive, but is harder to understand;
               | Zig strives to be the "weakest" language possible to get
               | the job done.
               | 
               | MetaML certainly does seem to be similar to Zig, although
               | the one paper I've now read thanks to your suggestion (ht
               | tps://www.sciencedirect.com/science/article/pii/S03043975
               | 0...) does not mention introspection and type functions,
               | and another commenter here suggests that it is, actually,
               | referentially opaque.
        
               | ymbeld wrote:
               | It doesn't seem as general as MetaOcaml. Just two-stage
               | evaluation, and without quote and splice.
        
               | throwaway17_17 wrote:
               | I think (again based on examples and docs) that it is
               | actually multistaged. However, this is not apparent
               | because the quote and splice are semi-implicit. The
               | 'comptime' keyword is essentially a the quote operator,
               | ie. it produces what is essentially a compile time thunk,
               | lazily capturing the 'code' value of the expression
               | defined under the comptime keyword. This thunk is
               | directly analogous to a value of type 'code a' in MetaML.
               | Then there is an implicit splice operator in place any
               | time a value defined under comptime is used subsequently.
               | I say it is multistaged because it certainly appears that
               | one can define a comptime variable for some computation
               | and then use that variable in a later comptime definition
               | or expression. So, it looks like a basic data flow
               | analysis to determine dependency is done on the comptime
               | evaluations and those are ordered implicitly. This order
               | would correspond to the more explicit staging syntax of
               | MetaML and the operation semantics that underpin it.
        
               | pron wrote:
               | I think Zig's comptime has three interesting features:
               | 
               | 1. It is referentially transparent, i.e., unlike Lisp,
               | i.e. nothing in the language can distinguish between `1 +
               | 2` and `3`. This means that the semantics of the language
               | is the same as if everything was evaluated at runtime,
               | and the comptime annotation has no impact on semantics
               | (assuming syntax terms aren't objects and there's no
               | `eval`).
               | 
               | 2. It supports type introspection and construction.
               | 
               | 3. It doesn't have generics and typeclasses as separate
               | constructs but as applications of comptime.
               | 
               | I think 3 is unique to Zig, but I wonder about 1: is it
               | possible in MetaOCaml, as it is in Lisp, C, C++, Rust and
               | Haskell -- _but not in Zig!_ (or, say, Java) -- to write
               | a unit `m`, such that m(1 + 2) is different from m(3)?
        
               | ymbeld wrote:
               | I don't know. I think MetaOcaml is strict about
               | inspecting Code terms like Code (1 + 2) and Code 3 (as
               | far as I remember it is not allowed). So no, I don't
               | think you can distinguish between them.
        
               | 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).
        
               | pron wrote:
               | I've heard of Terra, but I didn't know it had predated
               | Zig by a couple of years; thought they were introduced at
               | about the same time. And yes, there are certainly
               | similarities, although Terra thinks of itself as two
               | interoperating languages, while in Zig there is just one
               | (although there are things you can only do in comptime so
               | perhaps it's more of a difference in perspective).
        
               | ymbeld wrote:
               | The term partial evaluation tends to be used for research
               | that focuses on automatic evaluation of the static part
               | of the program. When considered as metaprogramming the
               | research would probably discuss type-checking +
               | evaluation as two-stage evaluation, falling under the
               | general umbrella of multi-stage programming.
        
             | 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.
        
               | vram22 wrote:
               | Can you elaborate a bit on the first issue?
        
           | 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.
        
               | ywei3410 wrote:
               | It's really a shorthand for writing lists - sexp's are
               | lists, so can use the same syntax.
               | 
               | Macro's in Lisp are essentially "just" functions where
               | the arguments are un-evaluated - you can use all the same
               | functions etc...
               | 
               | Writing a simple Lisp interpreter is really quite
               | educational - when you add macros and quoting into the
               | language, you suddenly have a realisation at how simple
               | it is.
        
               | kazinator wrote:
               | That's right. There is no difference between:
               | (defmacro my-quote (x)         `(quote ,x))
               | 
               | and                 (defmacro my-quote (x)         (list
               | 'quote x))
               | 
               | That `(quote ,x) is just way of writing (list 'quote x),
               | not a notation for writing macros.
               | 
               | That's it.
        
           | JacobCarlborg wrote:
           | This is very common in D and D doesn't not have any macro
           | system. It uses regular syntax (more or less). D was doing
           | this way before Zig existed and before C++ had constexpr.
           | Simple example of platform specific members:
           | struct Socket       {           version (Posix)
           | int handle;           else version (Windows)
           | SOCKET handle;           else               static
           | assert(false, "Unsupported platform");       }
           | 
           | Another example is the checked numeric type [1] in the D
           | standard library. It takes two types as parameters. The first
           | being the underlying type and the second being a "hook" type.
           | The hook type allows the user to decide what should happen in
           | various error conditions, like overflow, divide by zero and
           | so on. The implementation is written in a Design By
           | Introspection style and inspects the hook type and adopts its
           | implementation depending on what hooks it provides. If the
           | hook type implements the hook for overflow, that hook will be
           | executed, otherwise it falls back to some default behavior.
           | 
           | [1] https://dlang.org/phobos/std_experimental_checkedint.html
        
       | 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 :)
        
           | simias wrote:
           | I completely agree with you, I love not caring about
           | formatting anymore. That being said, does this mean that zig
           | refuses to compile code containing tabs? Because that seems a
           | bit counterproductive to me.
           | 
           | A great advantage of rustfmt and friends is that I don't
           | really have to care about my editor being correctly
           | configured, I can just code without worrying about style and
           | run rustfmt before comitting. But if the compiler outright
           | rejects poorly formatted code it means that I have to run the
           | format tool every time I want to compile or risk having my
           | code rejected due to format issues. Now I have to care about
           | my style again! It's the opposite of what I want.
           | 
           | I mean it's a very small issue and mainly a bikeshed, but
           | that seems like an odd decision to me.
        
             | ymbeld wrote:
             | "Refuse to compile" makes it sound like the compiler is
             | able to but unwilling to compile the code. It could very
             | well be that the parser doesn't recognize tab as a valid
             | token.
        
             | m45t3r wrote:
             | You can just configure your editor to run formatter on save
             | or with a shortcut. Not really a deal breaker.
        
             | anand-bala wrote:
             | You have a valid point, but if the only formatting issue
             | you will have is tabs, then running `zig fmt` on your
             | codebase is pretty much a non-issue.
             | 
             | If your project is small, just run `zig fmt` on the command
             | line.
             | 
             | If you have a large codebase, you can just incorporate it
             | into your build process (similar to how clang-format and
             | clang-tidy are used in CMake projects).
             | 
             | But again, if you have a large codebase written in Zig,
             | you've probably already configured your editor to run `zig
             | fmt` on save :)
        
               | littlestymaar wrote:
               | > But again, if you have a large codebase written in Zig,
               | 
               | At this point it means you're probably Andrew himself
               | because the Zig compiler is the only large Zig codebase
               | out there;)
        
               | jorangreef wrote:
               | https://github.com/ifreund/river
               | 
               | https://www.youtube.com/watch?v=124wdTckHNY
        
         | 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
        
           | smallstepforman wrote:
           | The reason hard tab people dislike code editors which convert
           | to spaces is that pressing backspaces during editing removes
           | one space, not all auto-inserted spaces. This ends up being
           | very frustrating (since you need to press backspace 4 times).
           | Most "used" languages allow both. Accept tab as another white
           | space character and life goes on. Compile errors for hard
           | tabs is a stubborn decision.
        
             | kortex wrote:
             | Any editor worth it's salt will indent with tab and de-
             | indent with shift tab with the cursor at the first non
             | whitespace. Any _good_ editor will de-indent with the
             | cursor anywhere on the line.
        
             | dnautics wrote:
             | > The reason hard tab people dislike code editors which
             | convert to spaces is that pressing backspaces during
             | editing removes one space, not all auto-inserted spaces
             | 
             | This is simply not the case for any editor I have used
             | recently.
        
               | sedatk wrote:
               | In addition to this, "de-indentation" can be achieved
               | with Shift-Tab instead of backspace.
        
         | 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.
        
       | travisgriggs wrote:
       | I keep meaning to look into zig more. Can it be used for embedded
       | chips like M0s yet?
       | 
       | I'd love to hear if anyone's cross compiling to embedded chips in
       | any real projects with it. Or it's strongest play still command
       | line tools on Linux?
        
         | hansvm wrote:
         | Zig is still "not production ready," embedded is still rough,
         | and you might have to contribute to Ziglang itself to get any
         | particular architecture working appropriately. That said, yes
         | people are using Zig a little for embedded stuff:
         | 
         | https://codelv.com/blog/2020/5/using-zig-and-the-stm32h7-to-...
         | 
         | https://www.mdeditor.tw/pl/2Ap9
         | 
         | Xtensa is less supported. M0 might also have some issues:
         | https://github.com/Schroedingers-Hat/xtensa-zig
         | 
         | I've been meaning to try it out for embedded myself; I'll let
         | you know how it goes.
        
       | [deleted]
        
       | 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.
        
               | gmfawcett wrote:
               | Hah! I didn't know of any Zen languages -- just to find
               | one a stone's throw away from Zig. Thanks for pointing
               | that out.
               | 
               | (And that news story... what an absolute mess of a
               | situation.)
        
         | 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.
        
       | yoshuaw wrote:
       | Heh fun: this was inspired by Rustlings, which in turn was
       | inspired by NodeSchool.
       | 
       | Mozilla Berlin used to host NodeSchool and the Rust Hack & Learn
       | evenings. It became a bit of a hang spot, and at some point we
       | had a pretty consistent group of folks who'd go to both. Marisa
       | realized Rust could use something similar to NodeSchool, and
       | started hacking on Rustlings during these evenings -- which now a
       | few years later has really taken off!
       | 
       | It's really cool to now see other languages in turn be inspired
       | and follow from Rustlings ^^
        
       ___________________________________________________________________
       (page generated 2021-02-14 23:02 UTC)