[HN Gopher] Looking into Zig
___________________________________________________________________
Looking into Zig
Author : GordonS
Score : 229 points
Date : 2021-08-06 20:12 UTC (1 days ago)
(HTM) web link (ayende.com)
(TXT) w3m dump (ayende.com)
| Groxx wrote:
| Purely on the topic of `errdefer`, I believe the equivalent in Go
| would be: // must use named returns so you can
| observe the returned error func yourfunc() (result
| thingtype, err error) { thing := constructIt()
| defer func(){ if err != nil {
| thing.Close() } }() // use
| thing to do a few things that could error err =
| thing.setup() if err != nil { return nil,
| err } other, err := thing.other()
| if err != nil { return // naked returns are fine too
| } // etc return }
|
| Which is...... _technically possible_ , and not even all that bad
| (as much as I strongly dislike named returns, since I find them
| very error-prone), but the fact that I have not ever seen this
| done does sorta reveal how much friction there is. Instead, I
| usually see manual additions of err-cleanup to relevant branches,
| and I've seen that pattern fail repeatedly as well (especially
| when the code is modified much later by some other person).
|
| The Zig equivalent seems like it would be roughly (I don't know
| Zig) func yourfunc() thingtype {
| thing := constructIt() errdefer thing.Close()
| // use thing to do a few things that could error try
| thing.setup() other = try thing.other()
| return thing }
|
| which is quite a bit more palatable and future-mistake-resistant.
| A sizable chunk of that is due to `try` of course, but still.
| mjbrusso wrote:
| The equivalent in Visul Basic would be:
|
| On Error Goto line
| tored wrote:
| Deserves an upvote. Not everyday you see praise about Visual
| Basic.
|
| Looked this up and _line_ can also be a label. Great.
| benibela wrote:
| Or in Pascal try ... except
| end
|
| wrapped around the error/exception generating code
| ziml77 wrote:
| I'd be interested to see if someone who works regularly with Go
| can show a cleaner way to do this. Because what I'm seeing here
| is just reinforcing my biases against Go. I've tried Go a
| couple times before but only ever read about Zig and yet I
| still find the Zig far easier to follow. It's much less verbose
| without being less explicit.
|
| (Also I'm not sure if the compiler would catch this, but there
| seems to be a bug in that Go code that's hard to see at a
| glance. You're never assigning a value to result)
| slimsag wrote:
| Actually, not only are you right about your errdefer Go
| implementation - but that's actually fairly common in Go code.
|
| Especially for tracing/logging of errors returned from
| functions; or for e.g. rolling back DB transactions in the
| event of an error.
|
| Here's some ~100 examples from my work's (Sourcegraph's)
| codebase[0]
|
| [0]
| https://sourcegraph.com/search?q=context:global+repo:%5Egith...
| Zababa wrote:
| > This year, I decided to look into Zig. Both Zig and Rust are
| more or less in the same space, replacing C.
|
| Maybe we should think about this in terms of space occupied by
| the languages and not the language themselves. One of the
| features of C is that pretty much anything can interface with it.
| Another is that you can write very fast code with it. Another is
| that pretty much any platform has a C compiler. Another is that
| it's small and fits in your head. Depending on what you're trying
| to do, you might use one "C replacement" or another.
|
| Another way of looking at it would be to see the shortcomings of
| C you're trying to overcome. I think this way of thinking would
| be more productive than just thinking about "replacing C",
| "replacing C++" or things like that.
| mypalmike wrote:
| I think there's an implicit, often unspoken list of C
| shortcomings wherever these replacement languages are
| concerned. Some of the most obvious ones are: Macro hell,
| transitive include hell, and the ease with which even
| experienced developers can unwittingly create unsafe code.
| rightbyte wrote:
| > Macro hell
|
| I can hardly think of any language addon more innocent than
| Cpp (the preprocessor).
|
| Imagine what madness would have emerged if it had proper
| variable assignment, goto:s or any loop construct?
| xhealthgothx wrote:
| Zig libraries can be exported with the C ABI[0], so pretty much
| anything can interface with it. You can write very fast code
| with it. It is also small and fits in your head. The only thing
| missing is a variety of implementations, however there is a
| clear path to bootstrapping the compiler from source with a
| semi-recent C++ compiler[1] and from there, there's already a
| growing number of supported targets[2]. There is also a major
| focus on making sure cross-compilation is well supported out of
| the box, including C code that Zig can also compile[3].
|
| It's perfectly fair to compare Zig to C in this case, as the
| project originated as a dialect of C before the author decided
| to do a complete clean break[4]. The primary frame of reference
| when designing the language was C and addressing its
| shortcomings, both language and tooling.
|
| [0]: https://ziglang.org/learn/overview/#export-functions-
| variabl...
|
| [1]: https://github.com/ziglang/zig-bootstrap
|
| [2]: https://ziglang.org/download/0.8.0/release-
| notes.html#Suppor...
|
| [3]: https://andrewkelley.me/post/zig-cc-powerful-drop-in-
| replace...
|
| [4]: https://www.youtube.com/watch?v=Gv2I7qTux7g
| Zababa wrote:
| I'll restate my point: sometimes when replacing C people want
| something that's just as fast but also way more safe, and in
| that case will usually reach out for Rust. That's what the
| people doing the cryptography in Python did. Rust can also
| expose a C ABI, you can write code as fast as C. People will
| often choose Rust instead of Zig because Rust has stronger
| guarantees about memory safety, and these guarantees are more
| important for them than having a language that's small and
| fits in your head.
|
| This is why I think talking about what you're trying to
| achieve is more fruitful than just talking about the language
| you want to replace. For example, if you want to replace C
| code and you don't need all of the performance in the world,
| you couold simply switch to a garbage collected language. In
| that case, since speed wasn't the most important requirement,
| a language that isn't usually thought as a C replacement can
| replace C code.
|
| If you want to make the point that Zig is "closer to C"
| compared to other language that wants to replace C, that's a
| fair claim to make.
| Gibbon1 wrote:
| I feel that people aren't using C because it's fast as much
| as it's not dog slow. And that it has a stable ABI and a
| very small footprint.
| xhealthgothx wrote:
| Rust is also not 'small and fits in your head', so that's
| yet another point it is missing in your initial set of
| criteria. Its main implementation and library also emits
| rather large binaries in the usual case. You may not find
| this important, but others do.
| nicoburns wrote:
| As others have pointed out, neither is C if you take into
| account avoiding UB, the preprocessor, the build systems,
| the many stdlib functions you need to avoid, etc. You
| might already know how these work, but that doesn't mean
| there's less to learn than a language like Rust.
| Zababa wrote:
| I addressed that point:
|
| > People will often choose Rust instead of Zig because
| Rust has stronger guarantees about memory safety, and
| these guarantees are more important for them than having
| a language that's small and fits in your head.
|
| For some people, having a language that's small and fits
| in your head is not a requirement, not a priority, and
| sometimes not even important.
| tialaramex wrote:
| > This is why I think talking about what you're trying to
| achieve is more fruitful than just talking about the
| language you want to replace
|
| This is definitely the right approach in my opinion. Even
| for your garbage collection example on the one hand, in
| some cases your program is dominated by tricky reclamation
| problems and the "correct" Rust program is basically 90%
| garbage collector, so that an existing GC language might
| produce _faster_ programs; but on the far opposite scale
| maybe your program has tricky non-memory resource problems
| and GC doesn 't help at all, so the GC language has worse
| performance and yet it makes your problem harder to solve
| than in Rust anyway.
|
| One of the nice things about Rust and about C++ RAII here
| is that you don't care whether the resources are memory.
| Database handles? Aerial drones? A tape robot? These are
| all just resources you can wrap in an object to manage
| them, in both languages. "I only have 15MB of RAM" and "I
| only have 4 fire-fighting robots" are the same kind of
| problem from this perspective.
|
| > If you want to make the point that Zig is "closer to C"
| compared to other language that wants to replace C, that's
| a fair claim to make.
|
| This is really important. Zig is very much inspired by C.
| Rust has the syntax of a semi-colon language like C, but
| its inspirations come from all over the shop. I came to
| Rust having already programmed not only C and Java (and a
| little C++) but also Python and ML (and a little Prolog)
| and so this was less disconcerting. But I can see if you've
| literally never encountered a functional language some of
| Rust is _weird_ because even though it is spelled like
| semi-colon languages you know it behaves very differently.
|
| I like Rust, much more than I liked Go or Python when I
| picked those up. It feels less clunky. An elegant weapon,
| for a more civilised age.
| Zababa wrote:
| For the comparaison between C, Zig and Rust syntax, I'm
| honestly not that sure. People love to complain about
| Rust's syntax for reasons I don't really understand. Sure
| the turbofish is a bit weird the first time, but other
| than that I don't find it especially difficult. On the
| other hand, I still have a hard time understanding Zig
| code. Probably because I never really played with it, but
| it's just like Rust, you need to familiarize yourself a
| bit. Maybe people that did only C are able to get up to
| speed with Zig more quickly than Rust? But that seems a
| bit superficial, if these people are already spending
| most of their time with only one language, if they learn
| a second to spend that much time with a few hours to get
| up to speed with the syntax is nothing.
| oconnor663 wrote:
| > Another is that it's small and fits in your head.
|
| I know this is a common view, but I want to highlight some
| counterexamples:
|
| - C programmers need to learn about many different forms of UB:
| https://blog.regehr.org/archives/1520. Most take years to learn
| these rules. Many never learn them.
|
| - Most real world C programs use some nonstandard language
| extensions on some target platforms. C learners trying to read
| production code have to navigate these.
|
| - The C compilation and linking model is complicated and
| platform dependent. Compilation is a major stumbling block for
| students who have to learn Make or CMake at the same time they
| learn C.
|
| There is some truth to the "C is simple" idea, I'll grant that.
| It's obviously simpler than C++. But I think there's a big
| effect where we tend to forget how hard it was to learn,
| because we learned it so long ago. There's also been
| substantial progress since the 70's on designing simpler
| programming languages.
| surajs wrote:
| A reduced feature/keyword set does not a simple language
| make. C is smaller, but definitely not simpler. Also
| definition of simplicity is context dependent, I would say in
| many scenarios C++ turns out to be the simpler choice.
| alerighi wrote:
| C is not a difficult language. I know a lot of electronic
| engineers that know how to program in C but don't know a
| thing about informatics, for example what is DNS, or what is
| JSON, or how to access a FTP server, and things like that.
| But they know how to program their microcontrollers in C.
|
| > C programmers need to learn about many different forms of
| UB: https://blog.regehr.org/archives/1520. Most take years to
| learn these rules. Many never learn them.
|
| UB really don't care that much in real life. When you are
| targeting a particular platform, that for most C programmer
| is some sort of 8/32 bit microcontroller, the only thing you
| care is the datasheet of the microcontroller. Of course you
| do things that in general are undefined behavior, but in the
| particular case lead to a perfectly predictable result.
|
| In reality you only have to care about UB if your goal is to
| share code between hardware platform. But let's be realistic,
| most of the time you don't. Even if you do, some UB are these
| days standardized, for example integer overflow is UB, in
| practice you know that on every architecture 2 complement
| arithmetic is used and thus is well defined.
|
| The real problem is that compiler for a misinterpretation for
| the standard started treating UB as "you are allowed to do
| whatever stupid thing you want since the condition will never
| happen", that is the real problem. In reality if you compile
| without optimization and with flags that avoid this stupid
| decisions it's not a problem.
|
| > Most real world C programs use some nonstandard language
| extensions on some target platforms. C learners trying to
| read production code have to navigate these.
|
| Again, it's a problem only if you are targeting different
| hardware platforms. But if you only program on ST
| microcontrollers (for example) why should you care?
|
| And you must use them in some situations, for example in C
| there is not a way to control how a struct is packed (to
| decode efficiently data from a serial connection for example
| you define a packed structure and access individual fields).
| Or inline assembly is not in the standard (what if you need
| to use an instruction of the microcontroller that is not
| exposed by the C library?).
|
| > The C compilation and linking model is complicated and
| platform dependent. Compilation is a major stumbling block
| for students who have to learn Make or CMake at the same time
| they learn C.
|
| It's. But most of the time you stuck on whatever the
| development environment for the target hardware platform is
| setup to. Most C programmers doesn't even know what CMake or
| Make is, I care about it and do things by hand, most other
| people use IAR or Keil or whatever proprietary software that
| integrates compiler, build system and IDE.
| jolux wrote:
| Compilers _are_ allowed to do whatever they want when
| encountering undefined behavior, not because it will never
| happen, but specifically because it's undefined.
| SAI_Peregrinus wrote:
| And they're allowed to do whatever they want even with
| optimizations off.
| oconnor663 wrote:
| And future versions of your compiler are going to want to
| do different things with your UB than what your current
| compiler does.
| Zababa wrote:
| I think your post highlights perfectly why I think we
| should talk about the roles of C and not C itself. The C
| you talk about seems to be a very different beast compared
| to the C people write and use when building shared
| libraries that are used across a wide variety of platforms.
| For example, the people writing OpenSSL would have very
| different concerns from the people you talk about.
| tialaramex wrote:
| > In reality if you compile without optimization and with
| flags that avoid this stupid decisions it's not a problem.
|
| Worse programs. Written by people who believe "C is not a
| difficult language" and who sacrificed all benefits of
| using a high performance language because they couldn't
| understand what they were doing.
|
| So long as you don't have any competitors who use a better
| language or skilled programmers you can coast along like
| this, putting out a sub-par product and just pretending
| it's the best possible. But you can get a very sudden and
| rude awakening if anybody decide to offer what's possible
| here.
| pjmlp wrote:
| Easy one uses an external Assembler like in the good old
| days when inline Assembly wasn't a feature one could rely
| on.
| alfiedotwtf wrote:
| Thanks! This is probably the first time I've heard C called
| _not_ a small language.
|
| Perl was my main language for over a decade, and when I
| wanted to go lower, I honestly struggled... but not with the
| language itself, with the peripherals which are exactly what
| you described!
| SAI_Peregrinus wrote:
| C is small, but it's not simple or easy to get right.
| pjmlp wrote:
| Depends on how much compiler extensions across multiple
| compilers one wants to be knowledgeable on.
| Zababa wrote:
| That's a good point. I personally don't share this view, and
| it's also not something I look for in a language. But people
| using C currently seem to be very attached to this, and
| knowing how to connect to your audiance is important.
| oddity wrote:
| Absolutely! A common example I like to use is Java. It might be
| hard to imagine now, but there was a time where Java (and then
| C#) were pitched as a replacements to C++ (even the name "C#"
| supposedly derived from "C++++"). There was no reason to write
| native code any more, many people said. And, they were kind of
| right. Many people were writing applications in C++ because
| they thought they had to, even though they weren't writing C++
| in the style needed to make proper use of it. A lot of old C++
| code bases today look like much more verbose Java applets. This
| peeling, when it happens, is usually good for everyone since
| languages (and tools) evolve to better fit the domains in which
| they are most used and happens so gradually that few notice.
| The inverse also happens, but with more conflict: you can see
| this today in Python (and other dynamic languages) adopting
| typing features aimed at assisting tooling for large code
| bases, well beyond the traditional learning or glue scripting
| mentality for which they were designed. This often results
| fierce debates around language features (like static typing vs
| dynamic typing) that are really proxy battles for the usage
| intent of the language.
|
| Unfortunately, I think the "replacing X language" mentality
| happens because it's the easiest point to start with. The field
| of programming and computers is so vast now that most (all?)
| people have a very narrow view and it's easy to assume it's
| universal. I've lost track of all the "things all programmers
| should read/know/do" articles.
| hawski wrote:
| Many C++ code bases, especially older ones, I have seen were
| really trying to be their own Java. This caused them to join
| disadvantages of C++ with disadvantages of Java. I don't
| believe the result was faster than JVM and start up time
| hardly mattered and still was not fast enough.
| jcelerier wrote:
| I dont't think the slowest c++ app I ever used was slower
| than the fastest java app I ever used
| pjmlp wrote:
| Even when it wins the benchmark games, it isn't relevant
| for many businesses.
|
| There is a budget to be fulfilled for project delivery
| acceptance, going beyond that is wasted money.
| Zababa wrote:
| > Unfortunately, I think the "replacing X language" mentality
| happens because it's the easiest point to start with. The
| field of programming and computers is so vast now that most
| (all?) people have a very narrow view and assume it's
| universal. I've lost track of all the "things all programmers
| should read/know/do" articles.
|
| I think another effect is that if you really like a language,
| promoting it is one of the best thing you can do to work with
| it. When you see the recent (2010 and later) new languages,
| they all have a story of addressing a particular pain point.
| Typescript is Javascript at scale, Kotlin is old Java on
| android, Go is web services, Rust is performance and safety.
| This is solid marketing, and is part of how these languages
| end up dominating their domains. On the other hand, a
| language that's "X but slighly better everywhere" won't
| really attract people, since there is already code and jobs
| in that language.
|
| Currently in the Great War Of Replacing C And C++, there are
| lots of fighters. Some people promote Rust, some others Go,
| some others D, some others Zig, some others to just keep
| writing C and C++. Part of the battle is writing code,
| libraries. Part of the battle is making the language and
| tooling itself better. And part of the battle is making
| articles, comments, talking to people and promote your
| language.
| pjmlp wrote:
| The best way to win battles in the context of systems
| programming languages is to have a platform ship with the
| language, libraries alone won't do it.
|
| This is how C put other of business other system languages,
| much better than it. When you get UNIX and have already
| paid for a compiler, hardly any department will allow to
| buy additional compilers.
|
| And C++, people tend to forget it was also born on the same
| place as UNIX and C, thus it was quickly adopted by all
| OSes that were UNIX clones in some fashion, and then by C
| compiler vendors on other platforms.
|
| And on cases like Java, Go, TypeScript or Kotlin, you need
| a godfather company to push it no matter what.
| Zababa wrote:
| For the part about platforms, hasn't that ship already
| sailed? From what I understand the industry had settled
| on C, C++, Windows and UNIX. Some people are trying to
| replace some of these with different solutions, but
| that's about it. I think a new platform would have the
| same challenges as a new system programming language, but
| would be even harder to convert people to.
| pjmlp wrote:
| Not at all.
|
| Want to develop for Apple platform?
|
| Depending on which level of the stack, the painless
| option will be C++, Objective-C or Swift.
|
| On Android it will be a mix of Java (slowly being left
| behind on purpose), Kotlin or C++.
|
| On Windows, .NET (and in some cases C# or C++/CLI only
| due to the way MSIL gets exposed) and C++. You can also
| keep using C if your view of Windows is like Windows XP
| APIs.
|
| On Fuchsia, it is all about Flutter, C++, Go and Rust.
|
| On ARM Mbed and Arduino, C++.
|
| On microEJ, Java and C.
|
| On Meadow, .NET.Core.
|
| Azure Sphere, C.
|
| CUDA, C++, Fortran, Python JIT and PTX aware backends.
|
| There are plenty of other platforms I could keep on
| listing.
|
| Naturally you can try to fit something else, but then it
| is on you and others to build the ecosystem, work around
| support issues and lack of IDE tooling.
| Zababa wrote:
| I see, I had a really limited vision and understanding of
| what you meant by "platform". That makes a lot of sense.
| Thanks.
| 0-_-0 wrote:
| Nim compiles to C, so it can be a drop in replacement.
| Zababa wrote:
| I think you should be a bit more precise on exactly when. If
| it compiles to C, that means that it inherits from C the
| great platform support. I don't know much about it, so I
| can't judge Nim on other qualities that people attribute to
| C: you can call it from pretty much any language, it's seen
| as simple, you can write highly performant code in it, you
| can use it in very restricted environments, and I'm probably
| forgetting some others.
| jasfi wrote:
| It's also very easy to write Nim, the syntax has been
| compared to Python.
| Zababa wrote:
| Honestly, I don't think these kind of drive-by shallow
| comments are selling anyone on Nim. Many people here have
| posted long and insightful comments about the
| complexities of replacing C and some other topics, and
| two of the three comments about Nim are a bit shallow.
| auxym wrote:
| I think the fact that Nim compiles to C is neat in that you can
| use it on any platform that has a C compiler.
|
| Here is a recent project that uses nim for AVR platforms, for
| example: https://github.com/PMunch/badger
| agbell wrote:
| I know very little Zig, but I agree with the post, that comptime
| seems simple, obvious and powerful.
|
| It is interesting that it bears some surface level similarities
| to type constructors in languages with higher kinded types.
| naasking wrote:
| Yes, and in principle you can generalize the type language into
| a full language with lambdas and such (type constructor is a
| lambda(ground type)->ground type), though you typically want it
| to be strongly normalizing so you know that the compiler will
| eventually halt. Then you don't need kinds, kind polymorphism,
| sorts, etc., you just have a dependently typed language with
| types and universes.
| agbell wrote:
| Yeah, functions returning types based on computations in Zig
| can look a lot like Idris if you squint
| koeng wrote:
| One thing that I'm quite bummed out with Zig is the lack of a
| good http server/client implementation in the standard library.
| Golang's std implementation on this is really quite nice.
| [deleted]
| kubb wrote:
| Yes, a large team of highly paid engineers at Google produced
| better libraries than that one guy working on Zig as a passion
| project.
|
| And yet that one guy still managed to build in useful features
| to his language that the Google "geniuses" couldn't think of
| despite (or because?) decades of experience.
| young_unixer wrote:
| In my opinion, that's outside the scope of a general-purpose
| programming language.
| moogly wrote:
| A client, at least, will be needed in the standard library
| for their upcoming package manager.
| throwaway17_17 wrote:
| Do you feel like http server/client is 'mandatory' in a
| standard library in 2021? I don't really do any web adjacent
| programming so it's not something I ever think about. However,
| I know I am in a very small group of people who don't have to
| worry about web stuff. I've been toying with a release of the
| personal language I use and was just rolling around the idea of
| what to put in the 'standard' library if I do release it.
| Anything else you think has to be in a std library?
| lostcolony wrote:
| It's very much a nice to have for a new language nowadays, as
| even if web dev isn't the key niche of the language, any
| success the language has is likely to still include a need
| for it. Adding it also creates interfaces and conventions
| that any third party ones can choose to adopt, to ensure it's
| a drop in replacement (and even if they don't fully, they'll
| likely still follow the same paradigm). This is really
| beneficial as, while the stdlib's version may be very
| middling, it ensures adopting the language and a third
| party's http implementation isn't going to trap you into
| something that becomes unmaintained, and which doesn't have a
| clean migration path away from; you can always fall back to
| using the stdlib's http library, since there's an expectation
| it will be maintained along with the language.
|
| That said, if you're putting your language up as a "see the
| neat thing I did that's helpful in this very specific
| domain", and not general purpose, with the intent of
| supporting, it's probably immaterial to you.
| chakkepolja wrote:
| I don't think zig is aiming in that category. I see it as a
| system language.
|
| Although these days people want to apply their favorite
| language to everything, I don't think zig will be a main
| language for writing web backends or http services. it's
| place is game engines, computer graphics, kernels, drivers
| etc..
| dnautics wrote:
| To some degree if you really needed the client, it would be
| almost trivial to import libcurl "as it is" into zig.
| throwaway17_17 wrote:
| It's less a specific domain thing and more an overly
| opinionated exploration framework for me. Not that it's
| really important, but the language is a modal dependent
| type theory with a compositional (even though most people
| would call it concatenative) syntax that compiles to C,
| C++, and JavaScript. So I can always just reuse the
| underlying platform http and the rest of the stdlib.
| naasking wrote:
| > Do you feel like http server/client is 'mandatory' in a
| standard library in 2021?
|
| A server isn't necessary, but 100% yes for a client. There's
| a lot of eating your own dog food needed for an http client,
| like string handling with encodings, network bindings,
| various collection types, async I/O and/or binary streams,
| error handling. The resulting client showcases the strengths
| of the language and its standard library, and most data is on
| the web today.
| c-cube wrote:
| High level bindings to cURL would be better imo. You don't
| reinvent this tricky wheel, and you get a lot of features
| (even async I think?) on top of a strong implementation.
| And a http server really doesn't belong in the stdlib of a
| system language.
| koeng wrote:
| Basic string manipulation, JSON encoding, file
| reading/writing, some type of hashing/checksum, and an HTTP
| client/server. Those things I've really appreciated about Go
| lately as I get it to control robots (controlling them over a
| REST api on local network writing commands to a serial port).
| jks wrote:
| They're discussing this in
| https://github.com/ziglang/zig/issues/910 (server) and
| https://github.com/ziglang/zig/issues/2007 (client).
| tored wrote:
| Great article. I mostly do PHP, PHP has support for FFI and I
| have some private projects where I call C libraries directly over
| FFI. I have been thinking of using zig to implement my own C
| libraries when needed. Zig looks like a more sane approach than
| using C, another alternative would be D.
| danielparks wrote:
| He posted a follow up about error handling in Zig that I thought
| was interesting: https://ayende.com/blog/194466-A/looking-into-
| odin-and-zig-m...
|
| I've seen the "clean up errors yourself" argument before, but,
| like the author, I don't think it holds water. Often the correct
| response to errors is to panic() or pass it up the stack so the
| caller can deal with it or--more likely--panic() itself.
| tored wrote:
| I agree with the author that _errdefer_ seems like the winning
| feature of zig. Proper error handling is the most important
| part of any language or system.
|
| Unfortunately most common languages does not prioritize this.
| As a contractor I have dug myself thru a lot of awful code in
| different languages and the most common denominator is improper
| error handling.
| Zababa wrote:
| I think it's nice to have two mechanisms for errors like in ML:
| sum types for errors that the calling function can
| realistically recover from, and exceptions for the rest.
| Gaelan wrote:
| This is Rust's approach, too: realistically recoverable
| errors are handled with Result<T, E>, and other are handled
| through panics. (Panics are generally implemented as
| exceptions, i.e. they unwind the stack, but the compiler can
| also be configured to make them just abort.)
| dnautics wrote:
| You can do that in zig with @panic and even convert from sum
| type error to an irrecoverable exception: `catch
| @panic("oops");`
| Zababa wrote:
| That's nice. Are the sum types checked by the compiler to
| ensure that you didn't miss any case?
| squeek502 wrote:
| If I understand you correctly, then yes.
| fn canError(foo: bool) !void { if (foo) {
| return error.Foo; } else {
| return error.Bar; } }
| test "canError" { canError(true) catch |e|
| switch (e) { error.Foo => @panic("foo!"),
| }; }
|
| Running `zig test` on that file would give:
| ./tmp/errors.zig:10:30: error: error.Bar not handled in
| switch canError(true) catch |e| switch (e) {
| ^
| Zababa wrote:
| You did understand it correctly. That's a really nice
| feature.
| AndyKelley wrote:
| Yes, and you can even handle some errors, and then
| capture an error whose type is the subset of unhandled
| errors, and return that, limiting the error set of the
| current function to not include the handled ones. Here
| are a couple examples: https://github.com/ziglang/zig/blo
| b/7d0de54ad44832589379a4bc...
|
| You get compile errors if you try to handle an impossible
| error, or don't include an `else` prong (in which case
| the compiler tells you the full set of unhandled errors).
| Zababa wrote:
| That's a great feature. I'm constantly impressed by what
| Zig can do.
| ksec wrote:
| Off Topic:
|
| >He posted a follow up about error handling......
|
| When I was reading the original blog I was thinking if he had
| any follow up, so I decide to click on archive and the
| homepage. And this article, somehow doesn't show up in both
| list. As a matter of fact I couldn't even find how to get to
| this blog post without your direct linking. Then it turns out
| it is a "FUTURE POSTS".
|
| How does that work and why? Is this suppose to be some sort of
| preview before it is officially published?
| danielparks wrote:
| Yeah, it's weird. I tried stripping the key= parameter from
| the link when I commented, but it's required.
|
| The author posted the link in the comments of the original
| post.
| yakubin wrote:
| Zig looks overall interesting to me, but I don't like that it
| reproduces one of the pains of C++ templates, i.e. their dynamic
| typing. What I mean is, C++ templates aren't checked before being
| executed, and instead you get compilation errors (at c++
| templates runtime) which mangle the use and definition of
| templates, e.g. template<typename T>
| concept HasId = requires (T a) { T::kId; // "the
| expression T::kId is a valid expression that will compile"
| }; // A and B are expected to be structs, where each
| has an associated integer constant kId and a field "int value".
| template <HasId A, HasId B> int min_id(const A a, const B
| b) { if (A::kId < B::kIs) { return a.value;
| } else { return b.value; } }
| struct A0 { static constexpr int kId = 1; int
| value; }; struct A1 { static constexpr
| int kId = 2; int value; }; // etc.
| struct A180 { static constexpr int kId = 2; int
| value; }; int main() {
| (void)min_id(A0(), A1()); (void)min_id(A1(), A2());
| // etc. ending with: (void)min_id(A179(), A180());
| }
|
| And now you get 180 errors about your typo (if not for max error
| number limits in the compiler), when really there is only one
| error in the definition of min_id. I used concepts to show that
| in the long tradition of C++, they're an additional feature that
| doesn't really help (quantity over quality of features).
|
| Haskell solves that with typeclasses, Rust solves that with
| traits. What's really important about these solutions is that
| when you write a function generic over a trait or a typeclass,
| you are limited to using what is defined in the trait/typeclass.
| The trait/typeclass function both as documentation and as
| something that gets you better compilation errors.
|
| "typename" in C++ is basically "any", but for values of template
| execution. Typeclasses/traits on the other hand are a sort of
| types for those values (which we normally call "types"). And
| similarly, in Zig there is an "any" type for types, just like in
| C++ --- it's called "type", and AFAIK there is no way to
| constrain your types with types of types.
| chakkepolja wrote:
| Is the problem about C++ templates it's error messages or not
| being able to strictly type the arguments in type signature?
|
| I have a question to the compiler / IDE people here. In case of
| C++ templates, is it possible to output one error like: eg
| "class UserData needs to implement operator< to be used in
| min() function" instead of 200 lines errors? I mean, complex
| cases it's not possible but at least for simple ones like using
| an iterator variable directly instead of dereferencing it?
| yakubin wrote:
| Those two are connected. Without strict typing the compiler
| doesn't know really whether the error is in the definition of
| min() or in its use, so the compiler mangles the two together
| and lets the programmer figure it out.
|
| _> In case of C++ templates, is it possible to output one
| error like: eg "class UserData needs to implement operator<
| to be used in min() function" instead of 200 lines errors?_
|
| This is already handled by concepts, but concepts solve only
| half the problem. E.g. in my snippet, in the comment you
| replied to, if any of the structs didn't have the kId
| constant, the errors would be about that. Concepts correctly
| detect when someone passes to them things that don't
| implement required functionality (as long as this
| functionality is specified in the concept). The other half of
| the problem, which they do not solve, is checking the
| correctness of the definition of the template against the
| concept. E.g. in my snippet I could use the "value" field,
| even though the concept that I used didn't declare it
| anywhere. At that point, if I passed a struct, which doesn't
| have that field, the compiler wouldn't be able to tell where
| the error is: in the template, or in its use --- so it would
| emit one error for each template instantiation, just as it
| did for "kIs" (because it can't know that it's just one typo
| in one place).
| chakkepolja wrote:
| I was asking about the no-concept case.
|
| I was thinking something like this:
|
| Compiler encounters operator<(T) on argument (type T) is
| called.
|
| In best case it sees it was a function parameter. In worst
| case it at least sees concrete type of the parameter. Let's
| say that type is UserData
|
| It will say that UserData type needs to implement
| UserData::operator<(UserData) to be able to use min()
| function.
|
| Of course I can see this getting complex as nesting etc..
| increase. But I am wondering if clang (since it's selling
| points include error messages, though gcc is catching up),
| hasn't tried something like this, there must be a
| fundamental technical difficulty for generalizing such a
| technique.
| tialaramex wrote:
| > Concepts correctly detect when someone passes to them
| things that don't implement required functionality
|
| Unfortunately C++ Concepts check _syntax_ even though as
| you 'd expect the intention of the feature is to reflect
| _semantics_ there is deliberately no way to capture that.
|
| So e.g. Rust has traits PartialEq and Eq reflecting things
| that claim to be partial or full equivalence relations.
| There's no syntactic difference, a Rust type can't
| _syntactically_ be impossible to check for equivalence with
| some values and not others but e.g. Rust 's f32 implements
| PartialEq not Eq due to NaNs whereas u16 has both since
| integers all exhibit equivalence.
|
| But in C++ there's just std::equality_comparable and it
| matches both integers and floats _even though NaNs aren 't
| in fact comparable_ because the float type syntactically
| has the == operator.
|
| So this means in C++ concepts matching means your program
| _compiles_ but it might blow up at runtime thanks to a
| difference in functionality rather than syntax.
|
| To C++ programmers this is positioned as yet further
| responsibility on their shoulders. They must check that the
| data they're using _actually_ models the concept that was
| required, it 's not anybody else's job and if they get it
| wrong the program blows up.
| aseipp wrote:
| I mean, I feel this particular example is really more of
| standard library design wart that occurs with any kind of
| syntactic overloading mechanism, e.g. Haskell has the
| exact same problem as C++ does here even though the
| overloading mechanism is rather different (Eq is defined
| for Float and there is no notion of a PartialEq in the
| standard library, even though there really should be),
| and there are numerous more advanced examples of that
| (every few years someone writes a fun library that
| violates the Monad laws, for instance). The fundamental
| question is: does an instance of an overloading mechanism
| respect the "properties" you expect of it, algebraic ones
| or not? Your program will often behave weirdly if the
| answer is "no" but the extent of the weirdness
| permissible is a spectrum. Basically no languages
| actually allow you to validate those semantics; it's
| expected that the "validity" of those instances is proven
| or known _a priori_ , and bad ones don't exist.
|
| IMO, the bigger problem with this particular example is
| just that the numeric and algebraic hierarchies in most
| languages are littered with various edge cases just like
| this one, and that makes it an easy and convenient
| nitpick to point out. But I think the parent comment is
| largely correct in that the goal of a concept (or trait,
| or typeclass) is roughly to reflect a property or action
| of some object or type or what have you, even if C++
| wasn't as originally as forward thinking as other
| languages today are with invariant safety.
| tialaramex wrote:
| The practical difference between C++ Concepts and Rust
| Traits is that Rust Traits get to have semantics _by
| declaration_ and you can 't do that with C++ Concepts.
|
| A Rust type gets to choose whether to be Eq or just
| PartialEq. I can wrap floats up in a new type, MyFloat,
| provide an implementation of == to qualify it as
| PartialEq and then I can choose whether to just _declare_
| that it 's Eq. The _compiler_ cannot check I told the
| truth, but as implementer I can decide whether to promise
| that or not.
|
| In C++ you do not get a choice. C++ concepts refer to
| syntax and _only_ that. I can write a concept named
| hates_balloons and have it depend on types implementing a
| zero argument method named "pop". But if your stack
| class with a pop method doesn't in fact hate balloons too
| bad, my concept says that since the syntax matches you
| have no choice, your stack hates_balloons and there is
| nothing you can do about it.
|
| I understand exactly why C++ did this. There is a _lot_
| of legacy C++ code out there. If you make every _new_ C++
| iterator say it implements the iterator concept and don
| 't grandfather the existing ones, nobody uses the
| feature. But, even though they had a good reason to do
| this, it's still a considerable weakness.
| pharrington wrote:
| I completely do not understand why the author thinks Rust is a C
| replacement. I can understand Rust as a C++ replacement.
|
| If he was looking for a better C, Zig definitely fits the bill.
| masklinn wrote:
| Rust is a C replacement not in the "tactical" sense of "I like
| C but it's a bit shit", it's a C replacement in the "strategic"
| sense: it aims to displace C in most of its core usages e.g.
| writing low-level or portable libraries, CLI utilities,
| daemons, kernel and kernel modules, etc... places where only C
| (and C++ somewhat more debatably) would be an option and
| continuously causes issues.
|
| It _also_ aims to displace C++ when that 's used in the same
| space, but in the sense that that's ground C++ gained from C,
| well C is the real target, if it can displace C there it can
| quite naturally displace C++ as well.
| richardanaya wrote:
| Probably has something to do with Rust being used in embedded
| and kernel operating systems due to it's high level of memory
| control and zero runtime capabilities.
| Zababa wrote:
| Rust is already used as a C replacement in some cases. However,
| as I said (https://news.ycombinator.com/item?id=28094998), just
| talking about a C replacement without mentionning why you were
| using C in the first place and what you value in a replacement
| isn't really productive.
| pjmlp wrote:
| Rust needs decades to catch up with domains that C++ has
| managed to keep for itself, like GPGPU, GUI composition
| engines, machine learning, HPC.
|
| The other domains where C++ was strong for general purpose
| applications have been taken over by managed compiled languages
| like Java and .NET, which anyway make use of C++ libraries
| alongside their AOT/JIT compiled stacks.
|
| There is little value to add from Rust in such scenarios, e.g.
| it won't make my WinUI application, CUDA shader or weather
| simulation model, any more safer than they already are.
| andi999 wrote:
| C++ for gpgpu was more of an afterthought in nvcc, wasn't it.
| I would be surprised if not most cuda kernels are written in
| plain C.
| pjmlp wrote:
| Not at all, it was one of the reasons why OpenCL lost, by
| staying too long focused on C.
|
| CUDA supports C++ since version 3.0, and NVidia designs the
| cards to follow C++ semantics, regardless of the polyglot
| capabilities from PTX.
|
| Hardly an afterthought, it was Khronos that became
| surprised that most researchers don't want to use plain old
| C on their research efforts.
| andi999 wrote:
| Good to know. Do you have further reading material on
| this?
| pjmlp wrote:
| Sure,
|
| "CppCon 2016: "Bringing Clang and C++ to GPUs: An Open-
| Source, CUDA-Compatible GPU C++ Compiler"
|
| https://www.youtube.com/watch?v=KHa-OSrZPGo
|
| "CppCon 2019: Olivier Giroux "The One-Decade Task:
| Putting std::atomic in CUDA.""
|
| https://www.youtube.com/watch?v=VogqOscJYvk
|
| "Octane render. The Future of GPU Rendering: Real-Time
| Raytracing" (with CUDA)
|
| https://www.youtube.com/watch?v=wGTIGjgXs6M
|
| NVIDIA HPC SDK
|
| https://developer.nvidia.com/hpc-sdk
| richardanaya wrote:
| Every time I read about Zig, I feel like I see a nice language
| that's only an incremental improvement to C mostly in terms of
| ergonomics. It's hard for me to imagine people giving up C for
| only incremental gain.
| sharikone wrote:
| You could argue the opposite and say that because it is
| incremental and easy to mix with C, it will be more easily
| used.
|
| When I program on my own I often write an idea in C and then
| convert it to C++ when complexity rises, precisely because C++,
| in terms of syntax, is an incremental update to C. Using say
| Rust would entail a more serious rewrite.
|
| Unfortunately Zig and Rust are quite different in syntax. I
| would love to change my workflow from C->C++ to Zig->Rust but
| the transition is not as nice.
| flohofwoe wrote:
| I thought that too in the beginning, but the comptime features,
| type reflection and error handling really go beyond C, while
| still being a simple and elegant language (in a way even
| simpler than C). Also Zig is a nicer C/C++/ObjC toolchain than
| most C/C++ toolchains (because of simple cross-compilation and
| integrated build system).
| naasking wrote:
| Compile type computations, trivial cross-platform building and
| linking, vastly better error handling, and more. Honestly, I'm
| having a hard time seeing how these are only "incremental"
| improvements over C.
| defen wrote:
| An alternative perspective is that you don't have to give up C
| to use Zig - they are extraordinarily easy to mix together in
| one project. So you can incrementally move an existing project
| to Zig without rewriting the world.
| sintezcs wrote:
| I highly recommend the last episode of the "Corecursive" podcast.
| The guest of the episode is Zig creator - Andrew Kelly, and he
| tells about the history of Zig, it's really interesting!
| https://corecursive.com/067-zig-with-andrew-kelley/
| ngrilly wrote:
| I really like Zig, but it's difficult to compare it with Rust
| without mentioning Rust memory safety and data race freedom.
| philprx wrote:
| Thanks a lot, TIL this about zig:
|
| https://scattered-thoughts.net/writing/how-safe-is-zig/
| pjmlp wrote:
| I have three main issues with Zig:
|
| - @ everywhere, for that I would keep using Objective-C
|
| - Compiled languages shouldn't be using text file imports as
| modules
|
| - I already have C and C++ for use after free/move errors
|
| Free to disagree, it just means I am not part of the target
| audience.
| defen wrote:
| > - Compiled languages shouldn't be using text file imports as
| modules
|
| Zig doesn't use C-style textual includes, if that's what you
| mean.
| pjmlp wrote:
| Sure it does, @import expects a text file that is then parsed
| into a struct like data structure.
|
| I expect a proper binary module, with native code and symbol
| table.
| flohofwoe wrote:
| The important part is that (unlike C/C++ headers) included
| modules can't be polluted with code that's coming before
| the @import(). Everything else is just an implementation
| detail.
|
| @import also has a second mode where the string isn't a Zig
| source file path, but a package name. AFAIK currently this
| also just resolves to a package-root zig file, but it could
| just as well be extended to some sort of binary format, the
| question is just: why?
| pjmlp wrote:
| Because many business situations we only want to
| distribute binary libraries.
|
| If I want to distribute source code I would be using
| scripting languages.
|
| It is also a nagging point for me when I play around with
| cargo, which contrary to conan and vcpkg, doesn't do
| binary libraries.
|
| By the way, C++ modules might get a binary format
| definition by C++26 (too little time to sort it out by
| C++23), based on BMI/IFC formats already being deployed
| in GCC and VC++ respectively.
| papaf wrote:
| _@ everywhere, for that I would keep using Objective-C_
|
| If you are triggered by the AT character, I recommend that you
| stay away from Slack and Microsoft Teams.
| pjmlp wrote:
| I really try hard to, but there are these things called job
| and customers.
___________________________________________________________________
(page generated 2021-08-07 23:02 UTC)