
Zig: software should be perfect [video] - luu
https://www.youtube.com/watch?v=Z4oYSByyRak
======
perlgeek
There's a certain irony that the presenter quickly dismisses exception-based
error handling, and then the first example handles an error by printing a
message and exiting -- exactly what an unhandled exception does.

This is more than a small piece of irony with a somewhat artificial example.
Often, there simply isn't very much you can do with an error. In a SaaS world,
you might not be able to tell the user what wrong, in order to not disclose
some private information. You can log the error, but only if the network is
available, and you can only log it to disk if the disk isn't full.

And then there are cases where you could try to explain the error to the user,
but the reasons are very complicated and/or require intimate knowledge of the
architecture to make sense, and/or require intimate subject knowledge to
understand, or even obscure legal reasons.

~~~
AndyKelley
I made this argument in the talk: the only problem with exception-based
handling is the lack of explicitness. It's too easy to call functions without
being aware of the set of possible errors. Many c++ projects disable
exceptions entirely. Writing "exception safe" code is tricky and non-obvious.
Functions which should be guaranteed to never fail often can throw
std::bad_alloc. Try-catch syntax forces incorrect nesting.

Related: Only zig has fast errors with traces. Other languages have no traces
or a high performance cost. Look up error return traces in the docs.

~~~
platz
> the only problem with exception-based handling is the lack of explicitness -
> It's too easy to call functions without being aware of the set of possible
> errors.

i.e. checked-exceptions?

~~~
marmaduke
yep! there was a sort of epiphany for me, the first I wrote Java, from Python,
when I realized that I can be sure that my code could handle anything the
callee could throw at it.

~~~
sqrt17
There are still plenty of exceptions that are unchecked, i.e. subtypes of
RuntimeException, which do not have to be declared on the callee. As well as
people who think it's a good idea to throw instances of Exception and just
tack a "throws Exception" on their methods.

~~~
loeg
Right — that's a failing of Java the language; not the concept of checked
exceptions. At least one problem with Java's exception model that Zig does not
have is that some exceptions are "unchecked."

~~~
Jach
The 'failing' of checked exceptions comes from essentially being forced to
couple the type signatures of your methods' successful results with their
error results. A more explicit way to do this is with Optional/Either types,
and now you don't need the checked exceptions feature nor need to get people
to remember to check for a global errno or some other data convention like an
empty string / null. There's a lot of boilerplate though, just like with
checked exceptions.

I prefer a more decoupled/late-binding approach to error handling; so far
Common Lisp does it the best I've seen.[0] The key insight CL people had was
that often in the face of an error, you need help from somewhere away from
your local context to figure out how to resolve it, but then for many cases,
you want to return back to where the error has occurred and take the
resolution path with your local context. In other languages that automatically
unwind the stack to the exception handler, it's too late.

[0] [http://www.nhplace.com/kent/Papers/Condition-
Handling-2001.h...](http://www.nhplace.com/kent/Papers/Condition-
Handling-2001.html)

------
visualstudio
I'm watching Zig and Jai closely. We need a better C and C++ isn't it. Good
luck!

~~~
muthdra
I'm betting on Jai.

~~~
skrebbel
I hadn't heard of Jai yet, but wow! That's a lot of hype (and even _tool
support_ ) for something that doesn't work yet.

At first glance, Zig vs Jai reminds me a lot of the Linux vs GNU Hurd thing
(or a lot of other "worse is better" examples). A couple of geniuses locking
themselves up telling the world "Just wait! It'll be awesome!" seldomly
produces something that lasts.

~~~
gameswithgo
>seldomly produces something that lasts.

of course, but sometimes it does.

~~~
skrebbel
True, but we're casting bets here :-)

------
loeg
Re: performance claims, I wonder if the C sha256 implementation would have
been more competitive with -march=native -mtune=native?

~~~
Avamander
Why isn't `-march=native -mtune=native` enabled by-default for every piece of
software compiled unless explicitly specified otherwise?

~~~
ndesaulniers
Because your cpu has a base ISA, plus extensions. The compiler doesn't know if
you're going to only run this binary on your machine, or distribute it to
others that may share your base ISA but possibly not your extensions, so it
takes the conservative approach and doesn't use them unless signaled to do so
via those compiler flags. Also, I think -march implies -mtune.

~~~
AndyKelley
In Zig the default target is native, which turns on all the applicable CPU
features. If you want to target something other than the native machine you
can use --target-os --target-arch parameters. I haven't exposed extra CPU
options for cross compiling yet.

~~~
saagarjha
Do you consider the default architecture targetted by GCC (e.g. some old
Intel) to be cross compiling? That is, can I make a binary that supports most
x86 processors rather than just those with the particular extensions I
support, with the current Zig compiler?

~~~
AndyKelley
Yes. You can pass the native OS and native arch as the cross compilation
target, and produce a binary that runs on your machine and others that don't
have the same extra CPU features.

------
mschwaig
The definition of 'perfect software' used in the talk is 'it gives you the
correct output for every input in the input domain'. To that end no funny
business like hidden allocations or hidden control flow should happen behind
your back, because an out of memory error or some exception your code does not
deal with explicitly would not be a correct output according to that
definition. Of course you do not need that level of control for most projects.

~~~
electrograv
While I agree with the content of your post literally, I think we often
underestimate the importance of software reliability and performance, and end
up giving it less attention than it deserves.

I understand the place for rapid prototyping etc., and that not every software
application deals with life-and-death situations — but even those that aren’t,
I think our industry suffers a bit here. For example, to this day the Windows
10 start menu refuses to open sometimes (randomly) when I click on it, even
multiple times. You could argue that this isn’t a huge deal, because within 30
seconds it usually “fixes itself” (or something like that), but it still
doesn’t shake the overall feeling that we’re tolerating way too much shoddy
software in 2018 than we should.

Or in terms of performance: I know not every application needs bare-to-the-
metal speed, but something feels wrong with the world when my “supercomputer”
(compared to a 1990s PC, for example) literally lags when I’m typing or
scrolling in some apps, when a 1990s era PC could respond to essentially the
same content interaction with almost zero latency.

Some few decades ago, we had far more klunkier programming languages, far
slower hardware, and yet somehow yielded better tangible/functional results in
some cases. Therefore, I’m very much in favor of anything that moves us
towards higher quality software, and Zig (and Rust, and others) are all
exciting examples of that.

~~~
euyyn
In over 6 years working in this industry, in projects with anywhere from
dozens of users to millions of users, not a single bug I have encountered was
caused by a "hidden allocation" causing the process to go OOM. Not one
instance.

One of the two examples he cited in his introduction, the Android one, wasn't
even caused by an unhandled OOM error. Android by design will kill unused
processes if they're occupying memory that the foreground process needs.

If we want software without bugs, removing hidden allocations in languages is
far down in the priority list.

~~~
theparanoid
The vast majority of bugs aren't are due to corner cases that the programmer
didn't think about. Quickcheck and related techniques expose many more bugs
than eliminating OOM bugs.

------
ajennings
I've wanted a language like this. Java's checked exceptions with some way to
offload the bookkeeping to the compiler.

What about other run-time exceptions, like divide by zero? Are they checked?

What about Hoare's billion-dollar mistake (null pointer exceptions)? Does Zig
have non-nullable references?

~~~
AndyKelley
Zig has a bunch of runtime safety checking. It applies to divide by zero as
well as integer overflow, using the wrong union field, and many more. The
runtime safety checks are enabled in Debug and ReleaseSafe mode and disabled
in ReleaseFast and ReleaseSmall mode. (Actually they are used as assertions to
the optimizer so that it can rely on extra stuff being undefined behavior.)

Pointers can not be null. However you can have optional pointers which are
guaranteed to use the 0x0 value as null and have the same size as normal
pointers.

------
Tempest1981
Definitely nice to have tools (compiler warnings, static analyzers) that can
keep you from hurting yourself.

Of course many projects don’t use them, for various reasons.

I wonder: is turning on full compiler warnings, then fixing them - is it
making my software better, or just satisfying some type of neuroticism?

~~~
clarry
There are stupid warnings about nothing to fix, at least in gcc. It's not
making the software better.

One warning I recently disabled on $workproject is -Wtrigraphs.

~~~
berti
Trigraphs can readily be formed unintentionally, so having a warning when they
change the meaning of the program seems valuable. There is a good reason they
were removed entirely in C++17.

~~~
clarry
They are as good as removed from C.

No compiler I care about has had them enabled by default in more than two
decades.

------
gbuk2013
From the video:

> Documentation is about 80% done

And yet there is not standard library documentation. :(

[https://github.com/ziglang/zig/issues/965](https://github.com/ziglang/zig/issues/965)

------
throwaway487548
Many very bright people in the major sects of ML and Scheme tried to achieve
perfection, and they have concluded, many times, that perfection implies a
mostly-functional strongly (and, perhaps, even statically typed but with
optional annotations only, like it is in Haskell) language, possibly with
uniform pattern-matching, annotated laziness, and high-order channels, and
select and receive in the language itself.

Such a language could be visualized as strict-by-default Haskell (with type-
classes, uniform pattern-matching, minimalist syntax - everything, except
monads) _plus_ ideas from Erlang, Go and Ocaml.

Perfection and imperativeness, it seems, does not match.

~~~
vortico
Also, perfection and practicality do not match either, since imperative
languages are the most practical for many applications. Pushing software
toward perfection gives diminishing returns, and after some threshold, a
company will have negative profit due to expensive development costs.

~~~
throwaway487548
ML is very practical. The only reasons why it did not became popular (or has
not been chosen as, say, the basis for Java) are social rather than technical
and actually are insults to intelligence.

------
avip
It is actually a nice informative video, but the title is as dumb as dumbness
itself. Software should not be perfect. It should be useful. In places where
perfection increases usefulness (s.a autopilot), go ahead make it perfect. In
most cases, striving for "perfection" is a profound misallocation of
resources.

~~~
dj-wonk
Upvoted since this is a useful comment and worth mentioning.

I'd expect some downvotes are based on negative reactions to this part of the
comment: "the title is as dumb as dumbness itself." (Dear avip: if your
comment said "the title is off-base" you would have made your point just as
effectively and without the downvotes.)

~~~
avip
Thanks, I really appreciate that (the message, not the upvote).

------
tomp
So... the perfect programming language has error-prone manual memory
management and rampant undefined behaviour (well at least it can build the
code to crash instead of “nasal deamons”)? Yeah right.

~~~
c3534l
No one said the language was perfect. The language is to help you write
perfect cod which was immediately defined at the start as code which does not
produce errors on any valid inputs.

~~~
tomp
Isn’t that by definition? After all, if the code produces an error, then
obviously the inputs weren’t valid...

------
justicezyx
Oh come on, we already know that logical systems cannot even self reconcile
it's own promises, as Gödel proved, now someone claim software should be
perfect?!

Edit: the original title does not mention perfect.

~~~
audunw
Come on, a title like that isn’t meant to be taken too seriously.

And you’re reaching a bit far. You can write a perfect function that adds two
32 bit integers. There is a subset of code that can be written perfectly.
Especially if you don’t need Turing completeness to write it.

Zig just tries it’s best to make it easy to write as much as possible of low
level code in a perfect way.

~~~
jcelerier
> You can write a perfect function that adds two 32 bit integers.

how ? the _problem_ of adding two 32 bits integers is itself imperfect since
you may at some point have big integers to sum, so any solution is inherently
flawed, too

~~~
int_19h
The problem can be perfect depending on how it's stated. If you spell out the
contract right, then it can be perfect. Some examples:

Given two 32-bit signed integers, produce a 32-bit signed integer that is a
sum of the inputs; if the sum doesn't fit into 32 bits, wrap modulo 32 bits.

Given two 32-bit signed integers, produce a 64-bit signed integer that is a
sum of the inputs.

Given two 32-bit signed integers, produce either a 32-bit signed integer that
is a sum of the inputs if it fits into 32 bits, or an error code indicating
that it did not fit.

The problem with languages like C is that they let you be imprecise and get
away with in. If you just run with "add two signed 32-bit integers", and
implement it as "x + y" in C, it will compile, and it will run, but the result
is _undefined behavior_ if it overflows (note: it doesn't even mean that you
get the wrong value - it can literally do anything at all). In Zig, if you
write it as "x + y", it will panic on overflow, which is at least well-defined
and fails fast; and the language provides you with tools to implement any of
the three properly defined scenarios above in straightforward ways (i.e. you
can add with wraparound, or you can add with an overflow check).

------
viach
There is a typo in title in word "profit"

------
revskill
Javascript (programming language) and Browser (runtime environment) is a
perfect piece of combination. With JS, you have many choices of
implementation. With Browser, runtime error doesn't crash user's device.

~~~
nerdponx
Same is true for the JVM or Python, no?

~~~
Ace17
Yeah. BTW it's also true for native apps running in user-mode.

