Live data from Hacker News

Why I’m not leaving Python for Go

uberpython.wordpress.com

111–120 of 245 posts

Re: Why I’m not leaving Python for Go

#111
post #44

On the topic of when to use error-returns vs. when to use panic: I struggled with this aspect of Go coding too and what I decided was that, in order to choose your approach to errors, you should think about how important it is that your function can be composed into an expression: x := foo(a) + bar(b) vs. c, err := foo(a) if err != nil { ... } d, err := bar(b) if err != nil { ... } x := c + d It's a trade-off. By usi…

As I understand it, it is about severity. I think "panic" and "error" are meant to handle situations where there is no obvious, correct answer, like with array indexing. A nil pointer is another gimme example. Some languages have unchecked exceptions — maybe conceptualize it somewhat like that. panics() are for disasters, for serious program errors. By contrast, a network timeout is not a disaster. It's not "normal"…

I would argue that there is an obvious correct answer for array indexing and nil pointer dereference. Go could have been designed to work like the following:

    x, err := *p
Where err is nil unless p is nil. And for array indexing:

    x, err := a[n]
The runtime could do its bounds check and return (zero, IndexOutOfBoundsError) if the check fails, where zero is the zero-value for the type. It seems to me that these solutions are perfectly workable except for the massive code-size/verbosity explosion they would induce.

In such cases, the code should effectively prove that p is not nil and n is within bounds before performing the risky operations. Maybe a good plan is to always validate input first so that you can write expression-oriented code that only fails in the case of programmer error.

A situation from my experience was a recursive transformation where an intermediate call had no good way to deal with an error except pass it along to its caller--so I used a panic within the package for that. In hindsight, I think a better solution may have been to validate the input in an earlier pass so that the recursive transformation should always succeed.

So, in cases where the program can validate inputs first, it should do so and then be free to use compositional code that panics when the validation was broken. In cases where validation cannot remove error conditions, error-returns should be used.

Reserving panic for programmer-error, as luriel recommends in his reply, seems like a good maxim. I think I'll try to use that from now on.

Re: Why I’m not leaving Python for Go

#112
My opinion: I'm not a fan of Python.

* It's really slow. * Most people write their code statically, but it's dynamically typed language anyway. * Things like '__init__'... what? * Having something you can see (whitespace) be significant is a bad idea. * Even worse, the community likes to use spaces instead of tabs, which makes the 'significant whitespace' a significant problem. * With the exception of Flask, important design patterns and lessons: DRY, SOC, DI, SRP, etc are largely ignored and called "Java-like."

Anyway, that's my $0.02

Re: Why I’m not leaving Python for Go

#113
>That problem is errors are handled in return values. 70′s style.

>This is one of the things I can’t stand in C.

Having to check error values for every function call is indeed a pain. But C has macros and I think it is a nice and elegant way to handle errors. I personally prefer MACROS to exceptions when writing C/C++ code. But to each his own.

Does anyone know if go supports macros ? If they do not, it is one ugly problem to have!

EDIT I just realized you can write custom exceptions that can provide similar information about line numbers, functions etc. So removed a line saying that was a plus for macros.

Re: Why I’m not leaving Python for Go

#114

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…

The difference for me is whether I'm trying to reduce MTBF (mean time between failures) or MTTR (mean time to recovery). I'm in the first mode when I'm writing high-quality code to solve stable, well-understood problems. I'm in the latter when I'm doing almost anything else. E.g., prototyping, exploring, pushing out a MVP for user testing, adding a quick-and-dirty version of a feature to get real-world feedback. In t…

Very nice point, right on the money.

I believe I'm correct as no one has yet refuted the central problem discussed. The replies have mainly been justifying it.

Re: Why I’m not leaving Python for Go

#115
post #80

As usual in these threads about Go, I really wish people would consider Haskell as a nice alternative. A lot of people write Haskell off as "academic" or "impractical", which I feel is not an entirely fair assessment. Particularly: Haskell is fast, concurrent by design (whatever that means, I'm sure Haskell is :P), typed but not cumbersome or ugly (less cumbersome and ugly than Go's types, even) and--most importantly…

This kind of comment kinda misses the point.

Haskell (IMHO) won't ever be mainstream for much the same reasons Lisp never was (or will be?): it has an incredibly high learning curve (eg [1]).

This is really the problem of the "pure" functional languages. Functional programming is suited to some tasks. With others the fit is almost tortuous. Imperative programming is well-suited to how we think and how we break down tasks.

If you look at the popular languages they're pretty much all multi-paradigm (eg Ruby, Python, Go, C#, arguably even C++/Java) meaning they give you the low-hanging fruit of functional programming while still being in a relative sweet spot of being easy to learn yet reasonably expressive.

Why I think Go has a very bright future ahead of it is that it is the first of these multi-paradigm language to combine all these features:

- easy to learn (seriously, go look at how short [2] is; you can knock that out in an afternoon);

- it is minimal. I LOVE Go's minimal OO model for example; and

- it is statically typed.

If you look at the other statically typed multi-paradigm languages you have C#, which is generally well-regarded... except (Mono notwithstanding) it is very Windows-centric. Java is, well, Java. C++ is incredibly complicated.

The only thing Go is missing is a mode for (semi-)manual memory management. I'm thinking something like Obj-C's ARC (in iOS 5+) and it could well supplant C/C++ for the vast majority of their (already shriking) use cases... eventually (Go has some work to do on speed).

[1]: http://stackoverflow.com/questions/377082/how-long-does-it-t...

[2]: http://www.miek.nl/projects/learninggo/

Re: Why I’m not leaving Python for Go

#116
The principle behind Go's design decision is based on actual experience and need to be understood by amateurs.

The idea is quite simple: errors are not some rare special cases, they are ordinary, general events.

That means there are no need to some special mechanism for handling them. They should be handled as ordinary events within common FSM.

There is no contradiction in using the general mechanism of examining returned values to determine the state of procedure execution.

Any FSM requires if (or cond) statements. It is the essence of a program's logic.

The mechanism of exceptions was wrong. It is wrong in Java, it is wrong in C++. It is just a bad design.

The good design is using the same mechanism the underlying OS uses. In case of UNIX-derivatives it is the explicit checking of a return value. Because errors are common and ordinary events.

Amateurs believe that errors are rare, and they will avoid them. This is over-optimistic - in practice errors are of nothing special. It is just an alternative branch of a condition, where a consequent assumed to be a success.

Re: Why I’m not leaving Python for Go

#117
post #115
post #80

As usual in these threads about Go, I really wish people would consider Haskell as a nice alternative. A lot of people write Haskell off as "academic" or "impractical", which I feel is not an entirely fair assessment. Particularly: Haskell is fast, concurrent by design (whatever that means, I'm sure Haskell is :P), typed but not cumbersome or ugly (less cumbersome and ugly than Go's types, even) and--most importantly…

This kind of comment kinda misses the point. Haskell (IMHO) won't ever be mainstream for much the same reasons Lisp never was (or will be?): it has an incredibly high learning curve (eg [1]). This is really the problem of the "pure" functional languages. Functional programming is suited to some tasks. With others the fit is almost tortuous. Imperative programming is well-suited to how we think and how we break down t…

Haskell (IMHO) won't ever be mainstream for much the same reasons Lisp never was (or will be?): it has an incredibly high learning curve (eg [1]).

Bingo. Anybody that thinks Haskell will ever escape its niche has not spent enough time working with rank & file programmers. That doesn't mean you shouldn't consider it or that it can't find a large enough niche to sustain itself but it does mean that it's unlikely to ever overcome what Carmack refers to as "externalities" for a lot of prospective users.

Re: Why I’m not leaving Python for Go

#118
post #29

I'm not in love with this aspect of Go either, and I also find that the idiom for dealing with it (multiple return values and multi-statement if conditional clauses) doesn't play well with Go's scoping rules, so that I find myself regularly having to decide between cleaner conditional or an explicit variable declaration. I also don't love how it makes my code look like my teenage-years C code. But I also think this i…

> No other approach to error handling is less fraught.

The thing that kills me about Go's error handling is you return error AND value all the time. It's like an Either that always has Left and Right. I think it's a bummer, especially coming from a group that has developed languages in the past.

Re: Why I’m not leaving Python for Go

#119
post #29

I'm not in love with this aspect of Go either, and I also find that the idiom for dealing with it (multiple return values and multi-statement if conditional clauses) doesn't play well with Go's scoping rules, so that I find myself regularly having to decide between cleaner conditional or an explicit variable declaration. I also don't love how it makes my code look like my teenage-years C code. But I also think this i…

> No other approach to error handling is less fraught. The thing that kills me about Go's error handling is you return error AND value all the time. It's like an Either that always has Left and Right. I think it's a bummer, especially coming from a group that has developed languages in the past.

I imagine that this is to keep compatibility with C. And also, this ensures that 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.

Re: Why I’m not leaving Python for Go

#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 like:

    try:
      f = float(someText)
    catch ValueError:
      # I just parsed you, this is crazy,
      # here's an exception, throw it maybe?
where this gets particularly irritating is when you start writing code like this:

    try:
      doSomething()
    catch ValueError:
      pass
I nearly always end up writing wrapper functions around that crap.

Java is worse for this because some libraries (including standard ones) abuse checked exceptions for this. I actually prefer:

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

    f, _ := strconv.ParseFloat(text);
for this kind of scenario.

For the truly bad--typically fatal--error conditions and cleanup, IMHO defer/panic actually works quite well. I certainly prefer this:

    f := File.Open('foo')
    defer f.Close()
    // do stuff
to:

    try:
      f = open('foo')
      # do stuff
    finally:
      if f:
        f.close()
as Go puts the two relevant things together.

Don't get me wrong: I like Python too but I do think Go has a lot going for it and has a bright future.

Post reply on HN