Zig Programming Language 0.1.1: First beta release
ziglang.org
ziglang.org
I like how error handling is structured, though I’m undecided on if I prefer a specific case of a more extensible system. Pretty sure it’s right for 80% of cases though.
- The %% operator and the %return expression used to simplify error handling.
- The concept of compile-time parameters used to implement generic functions and generic data structures.
It's very much in the Go style of "do the minimum needed to solve specific problems" but at first glance Zig looks much more cohesive than Go.
[1]: https://blog.golang.org/toward-go
"I'm focusing today on possible major changes, such as
additional support for error handling, or introducing
immutable or read-only values,
or adding some form of generics,
or other important topics not yet suggested.
We can do only a few of those major changes.
We will have to choose carefully."Maybe because it provides compile-time type safety and reduces the amount of boilerplate that would otherwise be required. Yet they can't see the usefulness outside of this single case?
Seems disingenuous to me.
https://github.com/zig-lang/zig/blob/master/example/cat/main...
For unary case:
// original:
%%io.stdout.printf("Hello, world!\n");
// my favorite ideas:
try io.stdout.printf("Hello, world!\n");
dare io.stdout.printf("Hello, world!\n");
// others:
err io.stdout.printf("Hello, world!\n");
ex io.stdout.printf("Hello, world!\n");
bet io.stdout.printf("Hello, world!\n");
bid io.stdout.printf("Hello, world!\n");
For the binary operator: // my favorite ideas:
a yet b
a odd b
a but b
a ex b // extra or except
a err b
a bail b
// others:
a else b // Would overloading the meaning have sense?
a esc b // escape
a alt b // alternate
a aux b // auxiliary
a sub b // substitute
a prox b // proxy
a then b
a eor b // error or
a repl b // replacement
a supp b // supplemental
a %or bKeywords can also benefit from the fact that 99% of programmers know at least the basic English words, while special characters are not necessarily international. They might not be used, they might not have the same meaning. I'm speaking more about "&" here, but it applies to other characters as well.
%defer %return
For %defer:
error defer deallocateFoo(foo);
but defer deallocateFoo(foo);
ex defer deallocateFoo(foo);
failsafe deallocateFoo(foo);
bail defer deallocateFoo(foo);
For %return: fn doAThing(str: []u8) -> %void {
const number = try parseU64(str, 10);
// ...
}
"try" could mean "return an error in case of an error" aka "%return". Then "dare"
could mean "panic in case of an error" aka "%%foo();".Or use "ex" or "but" everywhere:
ex foo();
const num = foo() ex 42;
const num = ex foo();
ex defer bar(baz);
but foo();
const num = foo() but 42;
const num = but foo();
but defer bar(baz);I really like the use of keywords, leveraging our extensive understanding and intuition of language to make a language more clear and intuitive.
Symbolic operators work well if they are borrowed from math (e.g. third grade), making up new ones often results in a painful learning phase.
catch defer dealloc(foo);I think things like "a|b" and "a&b" for or/and is fine - but when you need to stack them two and three deep, keywords starts to look more attractive... I think this holds true even for the relatively benign tripple-equal (===) used as a kind of stand-in for "a is b".
BTW, did I miss an obvious short intro to what these things are supposed to mean in zig? I feel I've overlooked an obvious quick-start document?
[ed: never mind - the post is just a bit hard to read on a cellphone - but nothing reader mode in Firefox can't fix]
const number = parseU64(str, 10) %% |err| return err;
Keeping the %% syntax, how about: const number = parseU64(str, 10) %% throw;
(Or "raise" maybe)I think that ordering is more readable than having the %return tucked away in the middle of the line (even more so if it becomes a plain keyword, no % sign).
Edit to add: a "throw" keyword could also be used to shorten normal error returns too:
return error.InvalidChar;
Becomes: throw InvalidChar;For "%return", perhaps "should" or "handle", as in, "This function should return without an error, but if it does, handle it."
If this were generally true then C wouldn't be used in numerical applications which is clearly not the case.
I think this is the wrong way to look at it. Where C still has advantages over many languages is where the developer's primary mental model is the machine the program is running on. That's why it's used for device drivers and low level library work.
Over the last couple of decades, C has become less and less good at this task as the C model and the machine have steadily diverged. At the same time, it's limitations have been exposed more and more.
In my view, Zig is aiming at this space i.e. where the developer is primarily interested in what the machine is doing. What they have done is kept the C model (largely) but mitigated or removed some of the egregious failings of C.
Zig may not be unique in doing this but it's definitely quite rare. Rust, Go, Swift et al aren't attempting to do this. This isn't a criticism just a perfectly legitimate difference of priority.
As I failed my soothsaying exam, I'm in no position to predict which, if any, will succeed. I hope (without much justification) that having language diversity will encourage natural selection.
Zig is a C replacement: a dead simple language for low-level development, partly disregarding memory safety (there seems to be some improvements, but only where it doesn't make the language more complex).
Could you ever imagine writing something like Tiny C-Compiler for Rust? C is like fancy assembly. Zig seems to fit into that niche quite well, but doing it in a more disciplined and modern way.
To elaborate a bit:
Right now, the standard library relies on an allocator. The language itself does not. If you want to write your own types and back them up by your own allocator, you can 100% do that today. But that doesn't help you with any of the stuff in the stdlib.
We have work on:
1. A trait for allocation, so that allocators can have the same APIs. https://github.com/rust-lang/rust/issues/32838
2. Swapping out that allocator entirely, wholesale. Tor and Firefox both want this. https://github.com/rust-lang/rust/issues/27389
3. Allowing you to swap out the allocator of stdlib types on a per-instance basis; this almost had an RFC for the needed machinery, but was postponed. Will probably come up again in the coming year after #1 & #2 get resolved.
If you see quick compilation as an advantage Go has over Rust, but want Rust’s robust error checking and you don’t like Go’s reliance on garbage collection, Zig might be interesting.
What about memory management ? They say there is no GC so manual memory management? Any memory safety features ?
Rephrasing the parent's question: does Zig try to ensure memory safety (e.g. no use-after-free, dangling pointers, iterator invalidation, data races)?
this seems to be the best description of it: http://andrewkelley.me/post/a-better-way-to-implement-bit-fi...
CL-USER> (the (unsigned-byte 5) 31)
31
CL-USER> (the (unsigned-byte 5) 32)
; Evaluation aborted on #<SIMPLE-TYPE-ERROR expected-type: (UNSIGNED-BYTE 5) datum: 32>.There's nothing new under the sun. What Zig brings to the table is high quality engineering and bringing the ideas together in a way that makes sense.
It seems as there have been some attempts to revitalize it [2] but these are targeting older versions and would probably require a lot more work to ever get back in-tree.
(I see you have a call for Android devs to help make it better! But I’m wondering if there’s some awkward hacky way to use it right now)
sorry
I think that if you are going to spend years creating a new language, you ought at least to try something new. Otherwise, you become just another amateur landscape artists. Maybe you're paintings will look nice, but they'll never really be of any great value to society.
Historically, incrementalism is pretty much the only way that languages can reach mainstream status e.g. C/ObjC/Javascript/C++/Java/C#/Kotlin.
Of course, having languages that break away from the mainstream is equally important to generate new avenues of research, but it's clear to me both approaches are a requirement for a healthy PLT field.
Almost all widely used languages today (c++, php, ruby, java, python, javascript, etc...) are incremental improvements on old ideas.
I think your opinion that the most used programming languages today are not “of any great value” to be bumpkis.
using async = Task<string>;
class BadIdea {
public async async async(async async) { }
} union union<'union> {
union: &'union union<'union>,
}
https://github.com/rust-lang/rust/blob/59675d29eb47eb743026d...To understand what evil_lincoln is doing, you have to understand very old Rust. Here's the commit that introduced it: https://github.com/rust-lang/rust/commit/664b0ad3fcead4fe4d2...
fn evil_lincoln() {
let evil <- log "lincoln";
}
log was a keyword to print stuff to the screen. Hence the joke, https://en.wikipedia.org/wiki/Lincoln_LogsNow that log is the println! macro, the joke is lost.
It doesn't say explicitly why this is "weird", but given some other comments in the file,
// FIXME: Doesn't compile
//let _x = log true == (ret 0);
I am assuming that using the return value of log was buggy, and so this tested that you could save it in a variable. I don't remember the exact semantics of log, but if it's like println!, it returns (), which is useless, so binding it to a variable is something you'd never write in real code, so it's "weird" in that sense.x = [[1,2], [3,4], [5,6]] [x for x in x for x in x]
For more details see:
https://jugad2.blogspot.in/2014/03/flatten-list-of-lists-wit...
function in() { echo $@; }
for for in in; do in for; doneWe don't need a radically different language, really. We just need a language that combines some of the best ideas that have been developing recently in a clean way while keeping the language simple, not complex.
D was trying to do that but then it exploded and became a monster just like C++. It's kind of just a slightly cleaner C++, but it's still a monster.
LLVM is a great effort in this direction and now language designers can target multiple architectures and get a ton of optimizations essentially for free. And it's great to see things like coroutines get added at that level. But more could be built at that level and on top of it to give higher-level language features in that same essentially free manner. It'd be cool to see stuff like borrow checking and garbage collection get added in a similarly reusable way.
The end result of this would be that syntax, the stuff that's mostly easy and yet most prone to bike shedding and developer aesthetics, could be mostly decoupled from the serious work normally associated with creating a language and compiler. And developers with less expertise could build quality languages that appeal to an unmet syntactical aesthetic without having to reinvent as much of the wheel as is currently necessary. Instead of having one language that brings together the best ideas, we'd just make those best ideas reusable so that any language could easily bring them together using whatever syntax shakes out of the bike shedding process.
- The string handling is braindead
- The compiler and stdlib is immature. This seems like the first programming language the guy has written. You should have a few failures to learn from before you make a Serious Programming Language imo.
- Code run at compile time is a neat idea but has a weird syntax and really really complicates the internals of the compiler and related tooling.
Unfortunately this is no C replacement IMO.
I'm getting a 403 on your docs page: http://ziglang.org/documentation/
I don't know of a single modern alternative to C. I wouldn't count Rust, because a replacement for C should be a dead simple language. Rust is a C++ alternative.
C works pretty well, but it could definitely be improved in a meaningful way.
Personally, I think it's just about time for a good C replacement, and Zig's goals are perfect for that.
If big companies can't move the needle for C, how can a single developer do it?
Not saying this is a good thing, just that it happens (at least, in my experience).
I assume you already know why but, in case you don't, let me put it in simple terms for you: it's easier to create something from scratch than to extend existing code base.
Have you every tried to fix a bug in or make an improvement to GCC? I did; I tried many times and I failed. Maybe it's just that I am not hacker enough (I'd say it's exactly the reason), but... The size of the code is enormous, the documentation scarce and of limited use to new people - sort of like with man(1) pages: if you already know what you're looking for they're great, but if you don't and need real help then I'm sorry, but tough luck. You'd better know where to look for parser, optimiser, code generator, etc. and how they interact with each other; where to get information about source code you're translating (keep in mind that there are "new" and "old" ways, and for some constructs only one is available). Unless you have tons of time on your hands (don't have to work, or are lucky enough to go to a University which has some people working on the code), or work for one of the companies developing GCC then you have pretty slim chances of actually getting through.
I don't know how it is with LLVM/Clang. Maybe there it's easier to contribute.
But HELL YES it's easier for a lone developer to "(...) create a whole new language, complete with a module system, a proof system, a constraint system, a parser/lexer (...)" and it is ridiculously hard to "(...) extend C by adding new flags to the compiler that are optional and don't necessarily break anything from old code and lets you selectively upgrade your sources.".
I know this from experience as well as, I'm sure, many others. I am building a parallel VM: I designed its instruction set, built a compiler and static analyser for it, went with it to a conference, etc. etc. It's not that hard and I bet you could do it too. But to take an existing language (read it as "an existing compiler") and "add new stuff without breaking anything" or just "add new stuff"? Man, that's orders of magnitude more difficult.
There's also the satisfaction factor at work: when working on new project you get instant gratification - "Test pass!", "New feature!", "A bug fixed!", and "I get to implement this cool idea I had and nobody's gonna stop me!". When you work on an existing project (especially one as big as GCC or Clang) you have to brace yourself for several hours of reading the code before you can begin to think about where to start. If you did read the code and tinker with it every day then it will get easier, but you have to have the will power to burn through all that code, and not everyone does.
Just my $0.02.
I've had my own share of ICEs and patches back in gcc3 days where Debian mailing lists were being used as a gcc issue tracker :-) and these days you just fork and work from there. And if people really need your patches, they will integrate it willingly. No need to "get through" anyone.
If you need some confidence boost, start off with reading semi-old patches from other contributors. That will immediately take you to the cogs of the machinery so to speak. Also, debugger is your friend. I hope you have one for your parallel VM.
I maintain 15+ year old delphi code bases as a profession, so I guess your rant just flew out of the window for me. The "tests passed all green checks" insta-gratification is a lost memory. The freedom to implement whatever you want is kinda constrained but still there.
To really change C, you need to at least get your changes in clang, not only in gcc. And let's not even talk about msvc. Or God forbid, actually creating a new standard version.