Live data from Hacker News

Why I’m not leaving Python for Go

uberpython.wordpress.com

141–150 of 245 posts

Re: Why I’m not leaving Python for Go

#141
post #131

Earlier quoted context omitted.

I'm not sure how, C doesn't have multiple return values either. I also don't really understand the second part. How is that any worse than the current situation of not checking the error side and reading an undefined (or whatever it is?) value?

>> when a Left value is accidentally read as a Right one, you don't get a "random" bit pattern due to type punning, but a correct (albeit meaningless) value such as NULL > How is that any worse than the current situation of not checking the error side and reading an undefined (or whatever it is?) value? You get deterministic failure modes instead of dragons flying out of your nose. Also assigning error in a variable…

> You get deterministic failure modes instead of dragons flying out of your nose

What Go currently has does not solve this problem, which is what I'm pointing out. Your argument is basically "not handling the error Looks Bad". Mine is "It should be impossible to do wrong". Something like ADT's would have been very welcomed, then we could just have a classy option type or either type.

Re: Why I’m not leaving Python for Go

#142
post #120

I have mixed feelings about errors as return codes. Then again, I have mixed feelings about exceptions. There are two general use cases for exceptions: 1. Unexpected (typically fatal) problems; 2. As an alternative to multiple return values. (1) is things like out of memory errors. (2) is things like you're trying to parse a user input into a number and it fails. I despise (2) for exceptions. It means writing code li…

I agree that exceptions can be cumbersome at times. And I do prefer the Go parsing float example to the try/catch one if my entire program is only one line.

But in order to live in peace you have to either:

* Force every programmer to always check all the error values.

or

* Allow errors to pass silently.

So either you accept Go as a heavy-duty, heavy boilerplate error handling laden language. Or you accept it as a flaky, risky language.

Exceptions are the better compromise in my opinion. You get much cleaner code.

If this is the more common pattern for your programming life:

    try:
        f = float(someText)
        use_it_here(f)
        use_it_there(f)
    catch Exception:
        # I wanted to do things, but something went wrong.
        # Here's what to do now, this is easy
Then you're better off using exceptions. If you need to check every single call (e.g. NASA or Kernel programming) then you might prefer this:

    if f, err := strconv.ParseFloat(text); err != nil {
      // do something
    }
    if f, err := use_it_here(text); err != nil {
      // do something
    }
    if f, err := use_it_there(text); err != nil {
      // do something
    }

Re: Why I’m not leaving Python for Go

#143

Earlier quoted context omitted.

I basically agree with you. I think return codes are simpler, and exceptions appear simpler because we're used to them. In reality they are a magical, out-of-band mechanism compared to plain old return. I contend that local and explicit is more strongly correlated with simplicity than remote and implicit. Put another way, verbose code can be simpler if it is direct and explicit — what happens is what's on the page —…

Say you need to migrate a database to a new schema. You need 10 SQL statements to do this. Each statement may fail, in which case you want to write stuff in a log and abort the transaction. In this case, wouldn't you agree that writing your statements in a try/catch/finally block would result in clean, easy to understand code, as opposed to adding explicit error handling after each statement?

I wouldn't agree, as when I'd code it in C I'd have a function callSql which returns false and write the code you describe as:

    if (    callSql( s1 )
         && callSql( s2 )
         && callSql( s3 )
         && callSql( s4 )
         && callSql( s5 )
         && callSql( s6 )
         && callSql( s7 )
         && callSql( s8 )
         && callSql( s9 )
         && callSql( s10 ) ) {
        endTransaction();
        return true;
    }
    logAndAbortTransaction();
    return false;

No need for exceptions at all, and it's very clean and clear what's going on.

I wrote the same code to my young exceptions-indoctrinated colleague who asked the same thing like you, and he couldn't believe at the start that that's all -- that much he wasn't used to a plain control flow. It's even obvious how it can be generalized for any sequence of commands:

    for ( int i = 0; i 

Re: Why I’m not leaving Python for Go

#144
post #143

Earlier quoted context omitted.

Say you need to migrate a database to a new schema. You need 10 SQL statements to do this. Each statement may fail, in which case you want to write stuff in a log and abort the transaction. In this case, wouldn't you agree that writing your statements in a try/catch/finally block would result in clean, easy to understand code, as opposed to adding explicit error handling after each statement?

I wouldn't agree, as when I'd code it in C I'd have a function callSql which returns false and write the code you describe as: if ( callSql( s1 ) && callSql( s2 ) && callSql( s3 ) && callSql( s4 ) && callSql( s5 ) && callSql( s6 ) && callSql( s7 ) && callSql( s8 ) && callSql( s9 ) && callSql( s10 ) ) { endTransaction(); return true; } logAndAbortTransaction(); return false; No need for exceptions at all, and it's ver…

While this code is nice and concise, the problem is that you don't automatically know which call failed or what the error was.

Re: Why I’m not leaving Python for Go

#145
post #53

If you use a language that uses error codes, then you're forced to explicitly think about what to do in every single error case (or not, and accept the consequences). This can add a lot of mental overhead, but can result in a much more robust and well-thought-out program. But because more logic is involved period (to handle the robustness), the program is necessarily more complex. If you use exception handling, then…

I would guess that most (99%) of C programmers are lazy or has an rapid programming style then. Its a rare thing to see C source code that even do the simple thing like wrapping every write/read/print call with a loop that detects eintr. In my years of programming, I have yet to stumble on a other programer who even knows that one should be doing this. Looking at c libraries and their example code, almost every time,…

In my years of programming, I have yet to stumble on a other programer who even knows that one should be doing this

That's a bold statement. Nice to meet ya! I'm no PC-Luser! ;-)

The PC-lusering problem is mentioned in "worse is better", so I would hope a fair number of folks know about it. Every good code base I've seen uses EINTR wrappers, but it is true that many folks I've met don't know about it.

Hey now.. it's not just C programmers, though. We have to use the same EINTR-retry loops in python too, sometimes:

https://github.com/git-cola/git-cola/blob/master/cola/decora...

I like C, Python, and Go. There's no reason to take sides, IMO. These are all highly effective tools.

Re: Why I’m not leaving Python for Go

#146

Earlier quoted context omitted.

I'm not sure how, C doesn't have multiple return values either. I also don't really understand the second part. How is that any worse than the current situation of not checking the error side and reading an undefined (or whatever it is?) value?

Well, the choice is between structures or tagged unions. I'm not a Go user, but if I understand correctly ("It's like an Either that always has Left and Right."), functions return a structure with both an error code and a value. To wrap a C function into a Go function with this signature, you can initialize a structure with { code: success; value:f() }; and then of course error checking has to be done C-style (errno,…

Go actually returns true multiple values, not a structure. You can't assign it to a single variable, for example, you actually have to assign it to N variables, with N being the number of values the function returns.

Re: Why I’m not leaving Python for Go

#147
post #83

I am eternally asking myself how do people handle exception in multi-threading programs ? Not that error code solve the issue at all, but it look easier (less complex) to handle thread error with error code

The same way you handle error return values in multi-threaded programs. Exceptions don't mean you simply ignore all errors all the time. They're just a different mechanism for communicating failures across function calls. You can code with exceptions the same way you do with errors.

Really the two styles of error communication are very similar. The default behavior for exceptions is to abort and let the parent deal with it, but you have the option of continuing on instead (catch). The default behavior for returned errors is to keep going, but you have the option of aborting and informing the caller. In either case you have to examine the code you're calling or its documentation to find out the details of what could happen when things go wrong.

Exceptions have the advantage of the abort-behavior requiring zero code, but it may be less obvious to beginners what is going on. In either case, people just don't like to be surprised, so they prefer what is familiar.

In C#, which has Tasks for concurrency (very similar to goroutines), an uncaught exception in a Task will bring down the entire program at some non-deterministic time, unless you make sure to observe it somewhere. So generally you're using some extension method so that invoking doSomething() in a Task looks like:

  Task.Factory.StartNew(() => { doSomething(); }).OnException((ex) => { /*log it*/ });
Either that or you just make sure to catch anything at the root of your Task block.

Re: Why I’m not leaving Python for Go

#148
post #107
post #105

Earlier quoted context omitted.

No other approach to error handling is less fraught. CL's condition system is less fraught: http://www.gigamonkeys.com/book/beyond-exception-handling-co...

Do you mean that restarts help the clutter and distraction that error handling brings? Or is there something else that makes the condition system less fraught than exceptions?

It's less fraught than exceptions in the sense that it offers more options for recovery. With "regular" exceptions by the time your handler executes the stack's been unwound and the context of the error vanished; you only have what information the exception itself provides. Not so with CL's exceptions.

Re: Why I’m not leaving Python for Go

#149
post #133
post #120

I have mixed feelings about errors as return codes. Then again, I have mixed feelings about exceptions. There are two general use cases for exceptions: 1. Unexpected (typically fatal) problems; 2. As an alternative to multiple return values. (1) is things like out of memory errors. (2) is things like you're trying to parse a user input into a number and it fails. I despise (2) for exceptions. It means writing code li…

Java 7 has AutoCloseables for resource cleanup: try (FileInputStream f = new FileInputStream(path)) { // do stuff }

The python mechanism is more general, you can use the /with/ construct with locks for example.

Re: Why I’m not leaving Python for Go

#150
post #144
post #143

Earlier quoted context omitted.

I wouldn't agree, as when I'd code it in C I'd have a function callSql which returns false and write the code you describe as: if ( callSql( s1 ) && callSql( s2 ) && callSql( s3 ) && callSql( s4 ) && callSql( s5 ) && callSql( s6 ) && callSql( s7 ) && callSql( s8 ) && callSql( s9 ) && callSql( s10 ) ) { endTransaction(); return true; } logAndAbortTransaction(); return false; No need for exceptions at all, and it's ver…

While this code is nice and concise, the problem is that you don't automatically know which call failed or what the error was.

If you can, write a more concise code with exceptions which will automatically show you which call failed and what the error was. If we include all the declarations, I claim that your solution wouldn't be shorter or more readable than my C variant I'll write, which would only declare error code values, or even return strings as error reports.

There's no advantage in exceptions, except when you use them for "hardware-like" generated exceptions (which is where they belong).

Post reply on HN