
Zig: a system language which prioritizes optimality, safety, and readability - vmorgulis
http://ziglang.org/
======
kzhahou
Almost half the comments here are just to remind everyone that C can/will
never be replaced. Is that really the most insightful we can be? Is HN so
pedantic now that we can't analyze an interesting language idea, but just
nitpick at its existence?

~~~
AndyKelley
My plan to replace C is simple and pragmatic.

1\. Make a language and compiler that fills the same niche as C but does it
significantly better, taking into account all the lessons we've learned in the
last 44 years.

2\. Make a build tool that competes with autotools, cmake, make, etc. Similar
to Python build.py, you'll have a build.zig, import a library and use it. The
library does everything configure/make does except better.

3\. Package management on par with NPM and Cargo. Minimal overhead to
publishing reusable code. Although I don't plan to have a central repository,
rather the ability to put a URL or source control URL with a hash.

4\. Zig can import and export .h files, and you can target .o files that are
compatible with the rest of your C codebase.

5\. Now there is minimal cost to replace bits and pieces of your codebase with
Zig.

~~~
pjc50
1-3 are a _tremendous_ amount of work, especially if you want to replicate
"everything" that automake does.

~~~
IshKebab
You don't need to replace everything that automake does. 90% of it is
obsolete, and 9% only applies to weird C compilers.

------
girvo
Interesting language. Somewhat reminds of me "ooc"[0], though I believe ooc is
ref-counted/garbage-collected (? I think. I can't remember, been a while since
I've touched it); but being able to easy use C libraries from a relatively
low-level language that has nicer high-level constructs is still a beautiful
idea, in my opinion.

The language I'm using these days for that exact feature set though is Nim[1]
-- being able to use {.compile.} pragmas and bring in header/source files,
along with the great C type support is wonderful; but again, garbage collector
(albeit one that can be tuned and/or turned off). Zig seems to be targeting
the "true C replacement" niche, which I'm going to have to keep an eye on!

[0] [http://ooc-lang.org/](http://ooc-lang.org/)

[1] [http://nim-lang.org/](http://nim-lang.org/)

------
ocschwar
Once you've made the decision to leave C for a systems programming project,
why would one not just go over to Rust?

~~~
Koshkin
Rust? Maybe. But then, why not Go or Swift or Lisp? Personally, if I were to
be expelled from C/C++ paradise, I would try Oberon - the only language I know
that can compete with C in its simplicity and, despite normally being
perceived as garbage-collected, the ability to serve as a truly systems
programming language.

~~~
mordocai
As far as vs Go or Swift or Lisp, Rust is much "closer to the hardware"(as
discussed in other threads nothing is really close to the hardware anymore)
than the other languages, go and most lisps use GC which causes problems in
many systems language situations, and last I heard swift still has lackluster
cross platform support.

I don't really know anything about Oberon so can't speak to that.

P.S. Personally, all my hobby projects are in lisp. I write applications
though, not system stuff.

~~~
pjmlp
Oberon was used for writing a complete graphical workstation OS used during
the mid-90 at the ETHZ in Switzerland.

It was a language and OS, following the same spirit of Xerox PARC OSes.

------
kennell
This is interesting from a technical point of view, but looking at the Hello
World example [0] really makes me wonder... who wants to write code like this?
I have been a touch typer for half my life now, but things like

> %% unreachable{};

> main(args: [][]u8) -> %void

really make my fingers and eyes itch.

[0] [https://github.com/jmi2k/zig-
playground/blob/master/src/hell...](https://github.com/jmi2k/zig-
playground/blob/master/src/hello_world.zig)

~~~
abricot
Try that on a nordic keyboard:

    
    
      % - SHIFT + 5
      { - ALT + 7
      } - ALT + 0
      ; - SHIFT + ,
      ( - SHIFT + 8
      : - SHIFT + .
      [ - ALT + 8
      ] - ALT + 9
      ) - SHIFT + 9
      > - SHIFT + <
      % - SHIFT + 5
    

Just for the bit you quoted.

------
dsego
This man is a prolific genius.

[http://genesisdaw.org](http://genesisdaw.org)

[http://libsound.io](http://libsound.io)

[http://groovebasin.com](http://groovebasin.com)

~~~
a-nikolaev
Yeah, he is awesome~ cannot upvote this twice. And I think, his design
decisions are very clear and straightforward too.

------
CaliforniaKarl
I don't know. C is very close to the hardware, and it's pretty portable, too.

I'd suggest doing what some other languages do, and get yourself to the point
where almost all of the code for Zig is written in Zig.

In other words, you'd first write a `microzig` that's written in C++, and
microzig knows enough to make `minizig`, which knows enough to make the rest
of zig. This is what Perl does, and I expect other languages do the same
thing.

On the other hand, zig is supposed to be able to cross-compile really well, so
maybe you can skip that: Have version 0.9.9 be the last version written in
C++. Then, for version 1.0, re-write the entire toolchain in Zig, and use the
0.9.9 compiler to compile Zig 1.0. At that point you are in full dogfood mode.

Finally, since it's called Zig, I get to close with this sentence: "You have
no chance to survive make your time."

~~~
dllthomas
> C is very close to the hardware

At this point, I'd more say that the hardware does an awful lot of work trying
to look like it's close to C.

~~~
bradhe
It's an interesting phenomenon, specifically how processor companies (erm,
Intel), who make "general purpose" CPUs, have clearly made trade offs to
optimize for OSes that behave like UNIX or Windows varients!

~~~
dbcurtis
Well, in fact, Intel and all the other major makers spend a huge amount of
effort benchmarking important workloads. It isn't a decision to optimize for
Unix or Windows, it is a decision to chase dollars. They will optimize
processors for your favorite workload, too. Just demonstrate how many millions
of dollars of business your workload represents, and create some sound
benchmarks for it. Easy.

~~~
dman
Any information on how many millions before a workload becomes interesting to
Intel/AMD/Nvidia?

------
adrianratnapala
Well I am impressed. And I am very glad to see more and more languages in this
space. I particularly like that Zig seems to be minimalistic -- a lot more fun
to look at (for me) than C++ or Rust.

But I didn't see anything in Zig similar to Rust's lifetimes. Well it's nice
to be rid of that complexity, but I don't see how you are going to do C-like
pointer stuff safely without them.

Can anyone explain what these languages (e.g. Zig, Myrddin, Nim) do instead?

~~~
steveklabnik
Nim has a GC.

Myrddin doesn't, but I can't quite remember what it does for safety, if
anything. The language spec does say "pointer arithmetic is not allowed."

For Zig, see here:
[https://news.ycombinator.com/item?id=12380078](https://news.ycombinator.com/item?id=12380078)

------
wyager
> Maybe type instead of null pointers.

It's often a bad sign when a language advertises this high up on its features
list. It means that they didn't really get the true takeaway of the Maybe type
(which is that you should support algebraic data types to properly constraint
data to valid states), but instead saw a single specific use case of ADTs
(Maybe) and thought that's all there was to it.

I've run into this with Java 8. Optional is pretty common now and has
eliminated the need for the null pointer in much of everyday code, but they
still don't have something like Either to eliminate the need for exceptions.
Maybe is extremely useful, but it's a small fraction of the usefulness you get
with true ADT support.

~~~
AndyKelley
Zig also has algebraic data types.

~~~
fspeech
Are they ML like ADTs with pattern matching? That would be awesome.

------
parenthephobia
Syntax looks very Rust-inspired, but it lacks Rust's OCD. I also catch hints
of other syntaxes, like Ruby/Smalltalk-style block parameters, and a defer
very much like go's.

I find it interesting that it implements generics by passing types as normal
arguments. Say, `list(i32, 1, 2, 3)` rather than `list<i32>(1, 2, 3)`.

~~~
dilap
i _love_ this

------
Gankro
I can't seem to find any details on safety other than

> Safe: Optimality may be sitting in the driver's seat, but safety is sitting
> in the passenger's seat, wearing its seatbelt, and asking nicely for the
> other passengers to do the same.

Is Zig memory-safe? How? (Specifically, is there some useful safe subset
ignoring the obvious FFI and "explicitly unsafe operations" exceptions every
language gets?)

If it's not, is that even a goal?

~~~
AndyKelley
It's not memory safe.

There is some compile time safety and some runtime safety, but it's not
comprehensive.

Nullable pointers are handled by the type system at compile time.

Integer wrapping (signed or unsigned) will crash at runtime, unless you use
explicit wrapping operators.

Array out of bounds will crash at runtime for slices.

There is no direct pointer arithmetic, but you can convert a pointer to a
slice, and then index into the slice (which has array bounds checking). This
is an example where the language is unsafe but it sort of guides the
programmer into writing safe code.

~~~
Gankro
Not being memory-safe is a bit of a bummer. Do you have a story for taking
advantage of all the tooling thats been built up to defend against C's
pervasive unsafety? Sanitizers being the most notable.

On balance even without them this'll _probably_ be safer than C (as long as
you're avoiding like, 90% of its pitfalls).

Either way, hope this works out for ya!

------
pmontra
How is the goal of readability being addressed? I didn't find it particularly
readable. Basically it's C with better types.

A few suggestions about the syntax, based on what many languages did in the
last 25 years.

1) No mandatory () around conditionals. Make {} mandatory even for one liners
instead. They remove bugs and are a common suggestion in the style guides of
several languages.

2) The multine string syntax is verbose and uninviting. Use heredocs or a
string delimiter reserved for that purpose.

3) Try to do without the ; line terminator

As a huge bonus, to reduce clutter, try to implement automatic import. I don't
know of any language doing it, it's IDE territory right now (or editor's [1]).
Still it's very useful because there is little as boring as going through a
long list of imports at the beginning of each file. They should be there only
when there is an ambiguity to resolve.

About readability, those {var v; while (cond) {}} blocks in the examples are
puzzling. Finding a }} alone on a line was an "is this a syntax error?"
moment, or just bad style.

Anyway, it seems to have generics so it's already ahead than Go, which seems
to be stuck in the 60s regarding this feature (they've been pioneered by ML in
1973 according to [2]). For the rest, it's in the average of what we've seen
in the past decades, so not shiny but not bad. Plenty of successful languages
are like that and maybe it's a reason for their success: being average they
don't scare away people. I'm thinking especially of Python, which smells oddly
of C with its __underscores__ and the explicit self argument, reminding me of
how we used to do OO in C passing around struct pointers (those structs were
the objects, holding data and function pointers to methods).

[1]
[http://www.vim.org/scripts/script.php?script_id=325](http://www.vim.org/scripts/script.php?script_id=325)

[2]
[https://en.wikipedia.org/wiki/Generic_programming](https://en.wikipedia.org/wiki/Generic_programming)

~~~
tom_mellior
One more syntax issue:

[http://andrewkelley.me/post/intro-to-
zig.html](http://andrewkelley.me/post/intro-to-zig.html) shows the

    
    
        const number = parse_u64(str, 10) %% |err| return err;
    

pattern and then goes on to say that you can avoid repeating "%% |err| return
err" all the time by writing

    
    
        const number = %return parse_u64(str, 10);
    

instead. I don't think that's particularly nice; it looks too much like
"return the result of the call" when that's only what happens in the error
case. I would have expected something more like this:

    
    
        const number = parse_u64(str, 10) %% return error;
    

where the compiler would turn "return error" into "|_some_var| return
_some_var".

~~~
pmontra
Agreed, %return is confusing and sends the reader down a wrong path.

Your last example could work if error is the default name for the error
variable, which makes sense.

------
Matthias247
Error handling mostly with error codes seems like an OK compromise for me
since it doesn't require any dynamic memory allocation (like Gos error
interfaces). I guess one would use some custom return type or a GetLastError
equivalent if more details are required.

However I'm not sure if purely compiler assigned error numbers will work out
for a systems language. Of course it works when you build the whole
application, but if you build only a part of it (a library, an application
that (dynamically) links against a library, ..., where do you get the
information from which error codes are already occupied by them?

------
z0xcd
One question: Why is Zig implemented in C++? What was the reason behind the
choice?

~~~
AndyKelley
It's mostly C, with some templates sprinkled in.

Zig depends on libclang and LLVM. Both of these are C++ APIs. Both expose a C
API wrapper, but with not all features exposed that zig needs to use.

------
lisper
You lost me at hello world. Or maybe I should say you lost me @ %hello
%%world. If you want to prioritize for readability the first thing you have to
do is get rid of all that weird non-standard punctuation.

------
qwertyuiop924
The thing is, you will never replace C. Supplement it, extend it, yes, but not
replace it

The fact is, C is still probably the lowest level HLL still used. It's the
lowest level you _can_ be, while still providing the HL constructs we're all
used to. There is always going to be code that wants or needs to be there.
Code where anything further up either can't give the performance, or provides
impedance to the design or actual goal.

You still want to replace C? Fine. What will you write your bootstrapping
compiler in? :-D.

~~~
versteegen
> It's the lowest level you can be, while still providing the HL constructs
> we're all used to.

I disagree completely. A language much better than C will come along in its
niche, and I'll be switching.

C isn't low level enough. It has too much undefined behaviour (and tries to be
too portable), each instance of which denies you access to real machine
behaviour. Signed ints don't even wrap around! Effectively, C does not even
support twos-complement signed integers, as exist on all modern computers
since decades ago, without a special compiler flag! You have to resort to
tonnes of compiler-specific extensions to get things like leading-zero-count,
SIMD, and computed-goto. Even with GCC's zillion extensions that were added
for people who have to do _really_ low level work, C is still hopeless for
writing maximum-performance VMs, that's why Mike Pall wrote the LuaJIT2
interpreters (one for each architecture) in assembly. Here's one of his
explanations why C shouldn't be used for such a thing [1]. I've also tried
writing a high performance interpreter in C, and I found that I wasted 80% of
my time trying to get the C compiler to output the sequence of instructions I
wanted. Next time, maybe I'll just use assembly and save myself a lot of
trouble.

Secondly, C is not high-level enough. A low level language like C needs a
powerful macro system to let you abstract away the details of your object
system or whatever. C's preprocessor has many flaws [2] and is one of the
worst in existence. A good macro facility allows compile-time generation of
code in a readable (or at least type safe) way, like D and Lisp do. C and C++
users don't realise they have the preprocessor equivalent of a Blub language
[3]. Sure, C++ is an extension of C with high-level features, and was a good
attempt, but it's too complex and C++'s template meta-programming just about
the only compile-time codegen solution worse than C's preprocessor.

[1]
[https://web.archive.org/web/20160209102431/http://article.gm...](https://web.archive.org/web/20160209102431/http://article.gmane.org/gmane.comp.lang.lua.general/75426)

[2] Read any rant, e.g.
[http://c2.com/cgi/wiki?CeePreprocessor](http://c2.com/cgi/wiki?CeePreprocessor)

[3] [http://www.paulgraham.com/avg.html](http://www.paulgraham.com/avg.html)

~~~
qwertyuiop924
Yes, C's preprocessor is weak, but that's a quality of life thing, not a
necessity by any stretch.

And as for C not being low-level enough, that was my point - C is as low level
as you can be, before you become unportable.

~~~
naasking
> And as for C not being low-level enough, that was my point - C is as low
> level as you can be, before you become unportable.

I don't think that's true. You can add first-class support for bitdata [1],
much better than C's bit flags and portable, better support for alignment
declarations, better/safer support for absolute addresses, native SIMD-like
vectors [2], exposing arithmetic carry flags, and more without losing
portability.

[1] [http://web.cecs.pdx.edu/~mpj/pubs/bitdata-
icfp05.pdf](http://web.cecs.pdx.edu/~mpj/pubs/bitdata-icfp05.pdf)

[2] [https://gcc.gnu.org/onlinedocs/gcc/Vector-
Extensions.html](https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html)

~~~
qwertyuiop924
Well, now we know what to ask for in C17.

------
Koshkin
C is beautiful in its way and it is rather minimalist from the syntax point of
view (especially the pre-C99 variants). Judging by the code examples shown on
the page, this new language has a pretty noisy (compared to C, downright ugly)
syntax. Granted, it may be dictated by some logic and possibly even its inner
beauty, but on the surface it does not seem to be much of an improvement
compared to the languages we already know and love (or love to hate),
including Perl and JavaScript.

------
wmu
I would love to see a comparison to C, C++, Ada, Rust, maybe Cyclone. After
reading the page I can't find an answer why Zig is better than any of
established languages. (Haven't read comments yet)

Speaking of readability... well, still smells like C. And multiline string
syntax is weird. :)

------
renox
While I find interesting the idea of a new C (instead of a new C++ like D,
Nim, etc), I'm a bit sad that there is both the Zig AND the Jay projects.. It
reminds me why Pascal lost (IMHO): too many incompatible Pascal 'clone'.

------
web007

        return if (value >= radix) error.InvalidChar else value;
    

That is just painful to parse. Suffix-If sometimes makes sense and simplifies
things, but it always makes code flow more difficult to understand.

~~~
perfunctory
I don't think this has anything to do with "suffix-if".

~~~
web007
True, which only makes my poorly-targeted point on bad parsability.

Reading the code requires backtracking around a conditonal control statement,
and in a format more verbose than ternary. Most places I've worked have bans
or limits on ternary to single boolean cases for the same reason: It's hard
for people to understand the control flow of operations around conditional
assignment. A new language that lets you perpetuate painful code isn't helping
as much as it could.

It's much simpler for people to parse the more verbose case with an IF and two
return blocks, and the compiler shouldn't care since it can generate the same
code either way.

~~~
gliptic
I think that is quite subjective. I prefer this version with one return. I
don't want more returns than necessary, and I want them as far up in the
nesting as possible so they are easy to see. Returns are, after all, control-
flow altering.

------
fspeech
The first thing I would want to use something like this for is to write C API
for a C++ library. Is that possible with the current state of Zig?

~~~
AndyKelley
I think the best language to do that in is C++. You write a C .h file, and
then a C++ .cpp file that implements the C functions using the C++ API.

Zig doesn't know how to use the C++ ABI. It's pretty complicated.

~~~
fspeech
You are right that C++ methods need to be invoked in C++ code. However C
container types are too weak/inconvenient to wrap C++ code. I am wondering if
something like Zig can be used to create STL like containers that can be used
at the API level?

------
ajarmst
Intend in one hand, and ... well, you get the picture.

------
sotojuan
Cool to see a fellow Recurser in HN!

------
dschiptsov
Modern amateur language designers usually are not aware of decades of research
and breakthroughs in old-timer's languages, such as Algol, Scheme, Common
Lisp, Standard ML and recently Haskell. They miss the beautiful specialized
syntactic sugars in Standard ML (for defining and calling curried functions),
Octave/Matlab matrix syntax, and the beautiful Common Lisp's looping and SETF
macros, which inspired Python's for loop syntax for iterable collections and
assignment operator overloading. Instead of spending time to learn and
understand pros and cons and nuances they rush headlong to implement
everything from scratch.

Really smart guys, however, are trying to leverage old-school languages, to
climb on the shoulders of Titans.

David Moon created the PLOT language that leverages Lisps
[http://users.rcn.com/david-moon/PLOT3/](http://users.rcn.com/david-
moon/PLOT3/) , Rich Hickey did _almost_ the same with Clojure. Scala has been
a leverage of Standard ML, similar to Ocaml. Now Swift is trying to distillate
Scala, at least in terms of standard idioms and syntax choices. Julia has been
build upon the big ideas from CLOS.

Python incorporated lots of good ideas and bits of syntax and managed _to
balance the syntax and unify semantics_ and since 3.5+ earned reputation of a
well-designed language (clear, balanced, complementing each other semantics
from the Lisp world, and carefully chosen syntax). It is also famous for its
_culture_.

So, for those who wish to change the world by developing a new language, it
might be a good idea to look at Standard ML and its derivatives and try to
relax some constraints and balance the syntax according to modern conventions.

I personally would prefer to start from David Moon's PLOT3 and, perhaps, try
to marry it with some lightweight type-system based with optional annotations.

Btw, Haskell's choice of not mixing type information and function definitions
and use annotations with its own DSL for types is a really big idea. It
reduces cognitive load, makes code extremely readable, and in general, it
seems, the best of both worlds. Python's optional type annotations are clever,
but less elegant.

------
gragas
Obligatory: why is Zig meant to replace C? Why is it a better replacement than
Rust (when Rust is considered a C replacement)?

Interesting work nonetheless.

~~~
parenthephobia
_I 'd_ rather use Zig than Rust because I wouldn't have to learn about how to
work with Rust's memory management model. Even though I understand Rust at a
technical level, actually getting my brain to work that way has proven
difficult.

Being able to directly import existing C header files is also attractive.

Having said that, I'd rather Zig had been Go-inspired than Rust-inspired. Go
plus Zig's approach to generics and error handling would be nearly perfect!
(Notwithstanding that Zig's error handling is basically Rust's with added
syntax sugar!)

------
matthewhall
Not with that logo it won't.

~~~
AndyKelley
hahaha. I would gratefully accept an improved logo if anyone is willing to
take the time to make one.

~~~
majewsky
You still have a few hours to submit Zig into
[https://news.ycombinator.com/item?id=12372118](https://news.ycombinator.com/item?id=12372118)

------
necessity
Don't fix what's not broken.

~~~
wolf550e
Basically every deployed C codebase contains "undefined behavior".

~~~
necessity
Which is intended. Suggested reading:
[http://blog.regehr.org/archives/213](http://blog.regehr.org/archives/213)

~~~
majewsky
But I will still always argue that it's a bad trade-off to make compiler
construction slightly easier at the expense of insecure code all over the
place.

------
yyhhsj0521
Is Zig compatible with C? No? End of the story.

Edit: I know that you can include a C header in Zig, and cross-compilation is
possible and made easy. But you can't continue develop on current C projects
if you switch to Zig. I guess that you have to change the Makefiles too.

~~~
parenthephobia
But... Zig _is_ compatible with C. It goes to some lengths to make sure of it.

~~~
emmelaich
I guess @yyhhsj0521 means source compatible. Which was my thought too.

I mean, as source compatible as possible; which may not be much.

