8 ms·
This is the first time I can see Zig lang [1]. (Self-proclaimed?) C successor with manual memory management, ironed out edge cases, new take on error handling (
by mirekrusin 9y ago
This is the first time I can see Zig lang [1]. (Self-proclaimed?) C successor with manual memory management, ironed out edge cases, new take on error handling (that resembles well written error handling in C), generics, compile time reflection/execution (macros?), import .h works directly, exporting to C works directly, nullable types etc... all sound quite interesting actually. Anybody has experience/comments on the Zig lang, please?
[1] http://ziglang.org/ http://ziglang.org/
- jandrese 9y agoInteresting. I've been somewhat disappointed with Rust thus far and this looks a lot more like what I was hoping for.
- kbenson 9y agoWhat did you find disappointing? What were you hoping for (so I can compare it to my own hopes)? Rust is the one (out of Rust, Nim and D) that looks most promising to me from the outside for my goals[1], but I haven't really settled on one to devote my very limited free time to. 1: If I'm going to drop down from a high level dynamic interpreted language to a low level strongly typed compiled one, I might as well got the extra distance Rust is asking for the gains it promises.
- jandrese 9y agoMostly I ran into a lot of friction with shared data structures that are being accessed by multiple threads. Stuff like ring buffers, flow state databases, and similar systems. There's probably Rust ways to do that stuff, but it was not obvious to me.
- littlestymaar 9y agoIf you're able to write a robust shared ring buffer in C, you should be able to do the exact same implementation in unsafe Rust using raw pointers, declare it as Sync and use it from safe Rust with no issue. Or am I missing something ? Or, if you're like me and not confident enough to do this, you could check on crates.io[1] to see if no available lib already does what you need. In which case you basically have it for free. [1] https://crates.io/keywords/ring-buffer https://crates.io/keywords/ring-buffer
- gcp 9y agoI'm pretty sure that's intentional friction (having to prove what you're doing is safe).
- jandrese 9y agoFiguring out how to prove it is safe to the compiler is definitely a challenge.
- chubot 9y agoPrevious threads: https://news.ycombinator.com/item?id=12378922 https://news.ycombinator.com/item?id=12378922 https://news.ycombinator.com/item?id=11060282 https://news.ycombinator.com/item?id=11060282 Actually I'm surprised that Zig didn't come up on the "Some Were Meant for C" thread, because this strategy is exactly what I wished something like Rust had support for (importing header files directly, more direct support for unit-by-unit translation, etc.): https://news.ycombinator.com/item?id=15179941 https://news.ycombinator.com/item?id=15179941
- bluejekyll 9y agoAre you familiar with this? https://github.com/rust-lang-nursery/rust-bindgen https://github.com/rust-lang-nursery/rust-bindgen It will translate a C header into Rust for all your bindings. Something could probably be built to do this more on the fly. If it doesn't already exist. edit: docs link https://docs.rs/bindgen/0.30.0/bindgen/ https://docs.rs/bindgen/0.30.0/bindgen/ edit2: and I should mention the inverse, Rust to C bindings, https://github.com/eqrion/cbindgen https://github.com/eqrion/cbindgen https://docs.rs/cbindgen/0.1.23/cbindgen/ https://docs.rs/cbindgen/0.1.23/cbindgen/
- johncolanduoni 9y agoBindgen is excellent with C APIs but what I've found really impressive is that it can handle C++ pretty well too. Most of my issues with using C++ code via bindgen are due to deviations in calling conventions that are hard to solve at that level.
- JoshTriplett 9y agoAnd as soon as procedural macros are stabilized, I'm sure that someone will provide a bindgen macro that would let you do something like bindgen!("somelib.h").
- chubot 9y agoYeah that is part of it, but I also like the lighter design philosophy I see Zig. It's the difference between thinking about compatibility up front vs. clean-slate design + compatibility. If you look at the Python vs. Lua C API you can see that difference. Lua was designed to interoperate with C (albeit after breaking the language 4+ times); Python just took whatever their implementation happened to be, and then exposed that API to users. With thousands of functions and macros and GIL and whatnot. Then a bunch of people came along later and wrote 5 different binding generators, and all of them solved some the problem, but not all of the problem. And some of them created new problems (SWIG). Also (to child comment), is it really possible to do bindgen as a macro rather than as a separate code generating tool? Because I assume bindgen has to invoke a C++ parser like Clang. I looked at Zig and it indeed uses libclang to parse C. I don't know about Rust's macro system but it would be somewhat surprising if it can invoke external tools or run C++ code at compile time.
- kbenson 9y agoZig competes with C instead of depending on it. The Zig Standard Library does not depend on libc. That's an interesting choice. I'm sure there are other semi-recent languages that have made the same choice, it would be interesting to hear the benefits and problems of that approach. I say semi-recent, because there are of course many from before C or that competed with C and Unix initially, but unless they are still used much (Lisp?) it's not necessarily the best for a comparison of modern issues.
- badsectoracula 9y agoFree Pascal has its own standard library that talks directly with the underlying OS too.
- anonymousDan 9y agoGo
- kbenson 9y agoAre you sure? I'm seeing reports that go sometimes wouldn't run with musl instead of GNU libc, with a runtime segfault[1]. That seems to depend on libc. Are you saying that Go's standard library primitives are not shims (or more complex structures) built on top of libc? 1: https://github.com/golang/go/issues/14476 https://github.com/golang/go/issues/14476
- Matthias247 9y agoGo uses libc optionally (for some things like DNS resolving). You can build Go programs which do not utilize libc by disabling cgo and building static binaries. By default the biggest part of Gos stdlib isn't based on libc, but some small parts are.
- tiehuis 9y agoA useful thing of this is also the portability story. Go for example is pretty good as far as I'm aware of cross-compiling to a different target. The main problem would probably be the extra implementation needed, instead of just writing a binding to libc. It also is more popular lately to prefer static linking vs. dynamic for deployment ease too, which not requiring linking to libc may help. For zig it is not all or nothing of course. It is pretty easy to link and use c if wanted. The following for example asks the compiler to link against libc. zig build_exe main.zig --library c One other benefit that zig gets is more compile-time execution opportunity. The math library for example being written in zig means that we can determine `math.log(7)` and use it for compile calculations when using libm we couldn't.
- minxomat 9y agoWow, that looks awesome. The syntax is pretty much what I look for in a language, much more approachable to me than Rust. Will tinker with it.
- Rusky 9y agoThe syntax actually looks fairly similar to Rust, just with generics replaced with `comptime`. What do you find more approachable about it?
- deleted 9y ago[deleted]
- tiehuis 9y agoI've been writing a fair bit since a few months ago, and have written a few things for the stdlib. Here are some examples I like about it. Hassle-free error management Consider you write a function fn div(a: u8, b: u8) -> u8 { a / b } If later you find an error case that needs to be handled updating the code usually will not require much extra addition. error DivideByZero; fn div(a: u8, b: u8) -> %u8 { if (b == 0) { error.divideByZero } else { a / b } } The caller can choose to ignore errors using `%%div(5, 1)` or can propagate errors to the caller, similar to Rust's `try!`, `?` using `%return div(5, 2)`. I find this so easy that I'm much more inclined to think about edge cases and handle errors up front. I find when writing Rust the extra setup and management of errors adds a fair bit of tedium (although to be fair, with error-chain and proper setup at the beginning of a project this isn't too bad). Compile-time programming Zig has pretty strong compile-time programming support. For example, its printf formatting capability is all written in userland code [1]. It doesn't at this moment support code-generation like D's mixins but I personally have not found this too problematic. Generic functions can be written in a duck-typing fashion. With compile-time assertions the inputs can be limited to what they need pretty clearly and the errors during usage are pretty self-explanatory. error Overflow; pub fn absInt(x: var) -> %@typeOf(x) { const T = @typeOf(x); comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt comptime assert(T.is_signed); // must pass a signed integer to absInt if (x == @minValue(@typeOf(x))) { return error.Overflow; } else { @setDebugSafety(this, false); return if (x < 0) -x else x; } } Zig doesn't have any form of macros. Everything is done in the language itself. [1]: http://ziglang.org/documentation/#case-study-printf http://ziglang.org/documentation/#case-study-printf
- bluejekyll 9y ago>The caller can choose to ignore errors using `%%div(5, 1)` or can propagate errors to the caller, similar to Rust's `try!`, `?` using `%return div(5, 2)`. >I find this so easy that I'm much more inclined to think about edge cases and handle errors up front. I find when writing Rust the extra setup and management of errors adds a fair bit of tedium (although to be fair, with error-chain and proper setup at the beginning of a project this isn't too bad). How is this different than say: 5_u8.checked_div(1).unwrap() That unwrap() is performing the same thing as your %% example, if I understand it correctly. Are the Error types in Zig on the stack or the heap? By default Rust puts everything, including errors, on the stack, which means that the size of the return type always needs to be known. To make this easier you can return Boxed errors: fn this_errors() -> Result<u32, Box<Error>> { ... } And then error types can be very simple. Also, I recommend people getting into Rust really checkout error_chain!, which is a macro that helps in combining all the errors that your library might need to deal with: https://docs.rs/error-chain/0.11.0/error_chain/ https://docs.rs/error-chain/0.11.0/error_chain/
- hasenj 9y agoWow, nice find! I've been looking recently for a language like that. I like Swift but I dislike the heavy coupling with macOS/iOS and ObjC. I like D but dislike its somewhat arcane syntax and bloat, plus it has a GC so it's not the same category. I like Rust but the borrow checker is brutal. I will give ziglang a try!
- Mindless2112 9y agoD now has "Better C" mode, which might interest you. https://dlang.org/blog/2017/08/23/d-as-a-better-c/ https://dlang.org/blog/2017/08/23/d-as-a-better-c/