On Sun, Jun 7, 2015 at 2:19 PM, Nick Wellnhofer <[email protected]> wrote:
> From a quick look, Proton doesn't propagate OOM errors all the way down, but
> exhibits unspecified behavior. It doesn't crash but it treats OOM errors
> rather randomly. Just look at how NULL returns from pn_strdup are handled,
> for example.
It is true that Proton's behavior is inconsistent. My understanding is that
Proton was originally coded under similar assumptions as Clownfish, but that
the Microsoft folks, who are using Proton in an embedded environment, have
been contributing patches to harden it.
> I hope we can at least agree that exceptions indicating an irrecoverable
> programming error (changing a Hash during iteration, for example) should not
> be propagated via return values.
I definitely agree that from host languages other than C and Go, such
error conditions should trigger an exception.
For Go, it would make sense to map some error conditions to return values and
some to panic. Most if not all of the existing THROW calls within the
Clownfish runtime represent unrecoverable situations and should panic. But
things such as I/O errors would be handled with an exception in Python and a
return value in Go. Here's a guide to idiomatic error handling in Go:
http://golang.org/doc/effective_go.html#errors
For C, though, it's an interesting question. The C standard library will
never throw an exception. It's possible to offer the same guarantee for the
Clownfish runtime. Here's a blog post which illustrates why such guarantees
can be valuable:
http://250bpm.com/blog:4
Why should I have written ZeroMQ in C, not C++ (part I)
[...]
First, it's important to take into account that ZeroMQ was intended to be
a piece of infrastructure with continuous uptime. It should never fail and
never exhibit undefined behaviour. Thus, the error handling was of utmost
importance. It had to be very explicit and unforgiving.
C++ exceptions just didn't fill the bill. They are great for guaranteeing
that program doesn't fail — just wrap the main function in try/catch block
and you can handle all the errors in a single place.
However, what's great for avoiding straightforward failures becomes a
nightmare when your goal is to guarantee that no undefined behaviour
happens. The decoupling between raising of the exception and handling it,
that makes avoiding failures so easy in C++, makes it virtually impossible
to guarantee that the program never runs info undefined behaviour.
With C, the raising of the error and handling it are tightly couped and
reside at the same place in the source code. This makes it easy to
understand what happens if error happens:
Ensuring that the Clownfish runtime itself never throws exceptions -- even
though it may support them -- allows us to accommodate both this use case and
the similar Microsoft/Proton use case.
> I argue that even with C, it's better to abort in an OOM situation than to
> return an error.
>
> * OOM errors are rare.
> * Most of the time, OOM errors are irrecoverable, anyway.
> * They affect almost every code path.
> * Checking for return values requires a lot of discipline from
> all programmers down the call stack. If an error isn't handled,
> debugging can become really hard. Especially, because OOM
> errors often result from other programming errors that become
> even harder to debug if an OOM condition is silently ignored.
> * abort()ing gives a nice backtrace directly from the source of
> the problem.
>
> The nice thing about your proposal is that is forces the caller to handle
> errors if a return value is used. For void methods, we could add the
> warn_unused_result attribute. But I'd really like to free users of the
> Clownfish runtime from handling OOM errors. We should make it optional, at
> least. For example with a macro that makes methods unwrap MAYBE return types
> automatically.
This is a reasonable position and describes the set of assumptions under which
the Clownfish runtime was originally written. (Here's another blog post which
illustrates certain advantages of exceptions over status returns:
<http://nedbatchelder.com/text/exceptions-vs-status.html>.) The idea of using
return codes to signal failure was not considered because Lucy's call stacks
were too deep to pass error information back up the call stack without adding
a stupid context pointer argument everwhere.
MAYBE types change the equation and make it possible to support the
no-exceptions use case. The cost is to make programming with
Clownfish-flavored C more cumbersome -- though programming with
Clownfish-powered libraries from any other host language would remain
unchanged.
None of this is going to happen, though, before the release of Lucy and
Clownfish 0.5.0, which I hope can happen once reasonably complete provisional
Go bindings are in place.
Marvin Humphrey