Live data from Hacker News

I want off Mr. Golang’s Wild Ride (2020)

fasterthanli.me

471–477 of 477 posts

Re: I want off Mr. Golang’s Wild Ride (2020)

#471
post #370

Earlier quoted context omitted.

> It does not deliver on "speed of coding", precisely because everyone, even seasoned Go developers, keep hitting its many design pitfalls. Well that’s a subjective statement. Are you basing that data or just your own feeling? I love writing Go and I’m way faster in Go than Rust. If I need more acceleration, of course Rust is the place to be, but if I just need to hammer out an API, Go is going to be much easier to d…

As someone who don't work actively in both Go and Rust, I perceive Rust to be readable and I feel more comfortable writing in Rust due to how strict it is in term of correctness. If I have to write go, I need to have an IDE well setup. And I had to do it a couple of times to tweak a simple restapi. Rust is surprisingly faster to write more complex things, down to the details such as when I want strings to be obfuscat…

> The problem is, not every go developer is you.

This is pretty common sentiment, the borrow checker is hard, you will be slowed down by it

Re: I want off Mr. Golang’s Wild Ride (2020)

#472

Earlier quoted context omitted.

> Errors-as-return values are less readable than conditions, not more - there's literally more visual noise on the screen. No. When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller. Happy-path and sad-path are two equivalent states that both need to be accommodated by the program logic. Error handling code is not "noise". It is…

> No. Yes. There is literally more visual noise on the screen. This is not up for debate - more pixels are lit on the monitor you are looking at. > When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller. False - the direct caller is not responsible for error-handling, in general - some transitive super-caller will be. Errors as r…

Error handling is not visual noise. It is equally important to non-error-handling code paths.

The direct caller is _absolutely_ responsible for error handling.

> What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk.

No. Falliable operations must be managed by the thing which calls them. Anything else is shadow control flow, which subverts understanding and negatively impacts reliability.

Re: I want off Mr. Golang’s Wild Ride (2020)

#473

Earlier quoted context omitted.

Error handling is basically orthogonal to performance. If a function call can fail, it should return an error, and that error should be managed by its caller. Any other approach means callstacks are unpredictable, which makes a program way way harder to model.

> that error should be managed by its caller Objectively false. Correct answer: the error should be managed by the code that makes sense to handle the error. > Any other approach means callstacks are unpredictable Also false. I use conditions regularly, and my callstacks are very predictable - errors bubble upward through the call tree until they're handled. There's nothing simpler. > which makes a program way way ha…

You're wrong on every point. I don't know how to speak to you given the strength of your conviction, so shrug

Re: I want off Mr. Golang’s Wild Ride (2020)

#474

Earlier quoted context omitted.

> that error should be managed by its caller Objectively false. Correct answer: the error should be managed by the code that makes sense to handle the error. > Any other approach means callstacks are unpredictable Also false. I use conditions regularly, and my callstacks are very predictable - errors bubble upward through the call tree until they're handled. There's nothing simpler. > which makes a program way way ha…

You're wrong on every point. I don't know how to speak to you given the strength of your conviction, so shrug

I think the fact that you didn't actually refute any of my points speaks volumes about which of us is correct.

Re: I want off Mr. Golang’s Wild Ride (2020)

#475

Earlier quoted context omitted.

You're wrong on every point. I don't know how to speak to you given the strength of your conviction, so shrug

I think the fact that you didn't actually refute any of my points speaks volumes about which of us is correct.

What do you mean by "conditions"?

> errors bubble upward through the call tree until they're handled. There's nothing simpler

Between

    output_a := f1(input_a)  // f1 throws exceptions on error
    output_b := f2(output_a) // f2 throws exceptions on error
and

    output_a, err := f1(input_a)
    // inspect and deal with err
    output_b, err := f2(output_a)
    // inspect and deal with err
it seems uncontroversial to me that the latter is less complicated than the former, and easier to model control flow paths.

Exceptions make sense in a lot of contexts! Just not services, servers, or long-lived processes.

Re: I want off Mr. Golang’s Wild Ride (2020)

#476

Earlier quoted context omitted.

> No. Yes. There is literally more visual noise on the screen. This is not up for debate - more pixels are lit on the monitor you are looking at. > When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller. False - the direct caller is not responsible for error-handling, in general - some transitive super-caller will be. Errors as r…

Error handling is not visual noise. It is equally important to non-error-handling code paths. The direct caller is _absolutely_ responsible for error handling. > What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk. No. Falliable operations must be managed by the thing which calls them. Anything else is shadow control flow,…

> Error handling is not visual noise.

You clearly did not actually read my previous comment before replying to it. Let me quote it:

"I never said that error-handling code is noise - it isn't. What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk. When there's an error, you should see exactly two things in your codebase: some stuff at the point where the error is thrown, and some stuff at the point where the error is handled - and, given that the place where the error should be handled is rarely the direct caller, you should see nothing in between."

Please read this carefully and respond to it.

> The direct caller is _absolutely_ responsible for error handling.

This is objectively false, both on an empirical level, and on a theoretical one.

On the empirical level, it's trivial to find dozens of instances of code on the internet where it's crystal clear that the direct caller of an erroring function is not responsible for error-handling.

Here's one: on line 1471 of emacsclient.c[1], a call to connect() may fail - yet the caller, set_local_socket(), is clearly not responsible for e.g. quitting the application, because only its caller, set_socket()[2], has the contextual information necessary to know that quitting should not happen unless the attempts to open local UNIX domain and network sockets to the Emacs server also fail.

That's it - counter-evidence to your claim. It's straight-up false.

But, let's go and find a few more examples.

Here[3] is a random screenshot of a Python error trace that I found on the internet. You see that bottom frame, listen()? It's calling the erroring function sock.bind(addr). Yet, it's pretty clear that listen() isn't the right place to handle the error - it's in the user's application, "ryu", because again, only that code has the contextual information necessary to determine the correct way to handle the error.

Here[4] is another Python error trace - again, it's pretty clear that the place to handle the erroring getattr() call is not in its direct caller bind() in socket.py, but in the user application in siriServer.py.

Finally, here's some Lisp code. The Hunchentoot web server has a ENSURE-PARSE-INTEGER function[5], which can fail if it receives a non-integer to parse. But, it simply doesn't have the contextual information necessary to handle the error, because it's called by URL-DECODE[6], which is called by FORM-URL-ENCODED-LIST-TO-ALIST[7], which is called by MAYBE-READ-POST-PARAMETERS[8], and that is where the error handling can, should, and must occur.

It's crystal clear - errors are not required to be (or always capable of being) handled at the call site of the erroring function, and the reason for this is simply because context gets lost as you travel down the call stack, so that the point at which an error occurs often simply doesn't have the necessary context to recover from it correctly.

> Falliable operations must be managed by the thing which calls them.

Also false. Look at every one of the code examples I've linked. Go and look at code in general, actually.

> Anything else is shadow control flow, which subverts understanding and negatively impacts reliability.

It sounds like you don't understand exceptions very well. Go and read some code with exceptions - you'll see that the idea is extremely straightforward. Exceptions are very simple - they bubble up through the stack until handled, and that's it. They're far easier to understand than first-class functions, coroutines, monads, or any of another dozen different software engineering concepts that are also being put to extremely good use.

[1] https://github.com/emacs-mirror/emacs/blob/3af9e84ff59811734...

[2] https://github.com/emacs-mirror/emacs/blob/3af9e84ff59811734...

[3] https://i.ytimg.com/vi/CryQPaz8UO0/maxresdefault.jpg

[4] https://serverfault.com/questions/476715/python-socket-error...

[5] https://github.com/edicl/hunchentoot/blob/0023dd3927e5840f1f...

[6] https://github.com/edicl/hunchentoot/blob/0023dd3927e5840f1f...

[7] https://github.com/edicl/hunchentoot/blob/0023dd3927e5840f1f...

[8] https://github.com/edicl/hunchentoot/blob/18d76801150330a579...

Re: I want off Mr. Golang’s Wild Ride (2020)

#477

Earlier quoted context omitted.

Error handling is not visual noise. It is equally important to non-error-handling code paths. The direct caller is _absolutely_ responsible for error handling. > What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk. No. Falliable operations must be managed by the thing which calls them. Anything else is shadow control flow,…

> Error handling is not visual noise. You clearly did not actually read my previous comment before replying to it. Let me quote it: "I never said that error-handling code is noise - it isn't. What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk . When there's an error, you should see exactly two things in your codebase: some…

> on line 1471 of emacsclient.c[1], a call to connect() may fail - yet the caller, set_local_socket(), is clearly not responsible for e.g. quitting the application, because only its caller, set_socket()[2], has the contextual information necessary to know that quitting should not happen unless the attempts to open local UNIX domain and network sockets to the Emacs server also fail.

Line 1471 describes a failure condition, which is returned to the caller of the encapsulating function, which in this case is is line 1374 set_local_socket. The caller which invokes the function set_local_socket absolutely is responsible for handling that failure condition. The caller is not set_local_socket, the caller is the code which invokes set_local_socket. And if set_local_socket fails, the code which invoked set_local_socket is absolutely responsible for determining what to do. Quitting the application is a decision that only `func main` can choose to do! All other points in the call stack can only bubble the error up to their caller. That's the only rational course of action.

> Exceptions are very simple - they bubble up through the stack until handled . . .

I agree that this is "simple" in one sense. The problem is that this "simplicity" means that there are two mechanisms of call stack control flow. One is the code as it exists "on the page" -- function calls and return statements -- and another is the exception control flow -- everything expressed as throw/catch statements. This is two control flow paths: one visible in the code, and another invisible, or implicit, to the code as written. It should not be controversial to say that removing the concept of exceptions makes control flow easier to understand, to model, to predict, and therefore easier to model the behavior of programs in general.

Post reply on HN