Live data from Hacker News

Twelve Go Best Practices

talks.golang.org

121–130 of 153 posts

Re: Twelve Go Best Practices

#121
post #80

if err == nil { _, err := w.Write([]byte(g.Name)) if err == nil { err := binary.Write(w, binary.LittleEndian, g.Age) if err == nil { return binary.Write(w, binary.LittleEndian, g.FurColor) } return err } return err } Why does anyone have to tell people not to do this? How does it enter anyone's mind as a thing to do in the first place? I've been known to go too far to minimize nesting. I get twitchy at the second lev…

Short circuit returns are the devil - they make it much harder to factor out part of a function into a smaller function. A function should have one entry point and one exit point; that's the whole point of structured programming. If you're going to return from some random point in the middle of your function you might as well be using goto. (Of course, good programming languages provide a better solution than pyramid…

No, no, no. That's what college professors with no real world experience tell you. In the real world, professionals use guard clauses to exit early all the time.

Re: Twelve Go Best Practices

#122
post #59
post #14

Earlier quoted context omitted.

They allow dynamically typed methods when you need them. Why does that make you sad?

Loss of strong typing and runtime type detection is what makes me sad. Well, Go 1 has some of the problems of Java 1: no generics, typecasts from interface{} here and there, simplistic GC. Reasons are probably similar: this all is good enough for version 1, and can later be improved upon.

"Well, Go 1 has some of the problems of Java 1: no generics, typecasts from interface{} here and there, simplistic GC. Reasons are probably similar: this all is good enough for version 1, and can later be improved upon."

Except I doubt we're going to see generics in Go version 2, whenever that may be. The sentiment against it has been pretty strong in the golang-nuts mailing list.

Re: Twelve Go Best Practices

#123
post #19

if err == nil { _, err := w.Write([]byte(g.Name)) if err == nil { err := binary.Write(w, binary.LittleEndian, g.Age) if err == nil { return binary.Write(w, binary.LittleEndian, g.FurColor) } return err } return err } Why does anyone have to tell people not to do this? How does it enter anyone's mind as a thing to do in the first place? I've been known to go too far to minimize nesting. I get twitchy at the second lev…

I do it in C code instinctively; it's very useful for instrumentation, debugging, and resource management in straight C to have a single return point. When I get too far to the right, that's a signal that it's time to further decompose my functions; that signal is also useful, which is another thing that keeps me doing it. But that style doesn't make much sense in Golang. It makes even less sense in Ruby and Python,…

do you know of any languages that have a sort of inverted switch statement to clean up a list of if statements like this?

something like:

    invswitch err !=nil {
    case 'err := binary.Write(w, binary.LittleEndian, int32(len(g.Name)))': return err
    case _, err = w.Write([]byte(g.Name)): return err
    case err = binary.Write(w, binary.LittleEndian, g.Age): return err
    default: return binary.Write(w, binary.LittleEndian, g.FurColor)
    }

Re: Twelve Go Best Practices

#124
post #23

Interesting that this snippet: func (g *Gopher) DumpBinary(w io.Writer) error { err := binary.Write(w, binary.LittleEndian, int32(len(g.Name))) if err != nil { return err } _, err = w.Write([]byte(g.Name)) if err != nil { return err } err = binary.Write(w, binary.LittleEndian, g.Age) if err != nil { return err } return binary.Write(w, binary.LittleEndian, g.FurColor) } could be written like this: func (g *Gopher) Dum…

If the language supported exceptions, how would you write this func? func (g *Gopher) DumpBinary(w io.Writer) { // Ignore all errors _ = binary.Write(w, binary.LittleEndian, int32(len(g.Name))) _, _ = w.Write([]byte(g.Name)) _ = binary.Write(w, binary.LittleEndian, g.Age) _ = binary.Write(w, binary.LittleEndian, g.FurColor) }

Laziness and irresponsibility aside, why would you be writing code without even a minimal level of error checking?

Re: Twelve Go Best Practices

#125
post #123
post #19

Earlier quoted context omitted.

I do it in C code instinctively; it's very useful for instrumentation, debugging, and resource management in straight C to have a single return point. When I get too far to the right, that's a signal that it's time to further decompose my functions; that signal is also useful, which is another thing that keeps me doing it. But that style doesn't make much sense in Golang. It makes even less sense in Ruby and Python,…

do you know of any languages that have a sort of inverted switch statement to clean up a list of if statements like this? something like: invswitch err !=nil { case 'err := binary.Write(w, binary.LittleEndian, int32(len(g.Name)))': return err case _, err = w.Write([]byte(g.Name)): return err case err = binary.Write(w, binary.LittleEndian, g.Age): return err default: return binary.Write(w, binary.LittleEndian, g.FurCo…

Yes, CPS is essentially that and available in any modern language, or can be emuated by setcontext(2)/getcontext(2). However, it can become a mess very quickly.

Another option is monadic style, which will pass error checking along. I believe it will work well for this example, and can be implemented in Go, most likely (I don't know Go, bur it seems so).

Of course, the real problem with this code is that it is not decomposed properly. Nested error checking is the first sign of it, as somebody else already rightfully noted in the thread.

Re: Twelve Go Best Practices

#126

Earlier quoted context omitted.

> Short circuit returns are the devil vi! Naïve, absolutist positions in areas of long-standing debate between programmers of great experience and the highest imaginable competence just makes you look ridiculous.

Naive, absolutist positions in areas of long-standing consensus between programmers of great experience and the highest imaginable competence makes one look even more ridiculous. By and large, the best programmers eschew nesting in favor of early returns. Invariably (in my experience) those who argue against early returns are inferior programmers (and not only by virtue of lacking taste in this particular debate).

Where did you get that idea of consensus? A lot of languages do not even have a return statement, neither does lambda calculus. Furthermore, CS community has long abandoned statement based languages in favor of expressions and relations which do not feature "return" for onvious reasons in forms other than equalent to jump.

Re: Twelve Go Best Practices

#127
post #8

if err == nil { _, err := w.Write([]byte(g.Name)) if err == nil { err := binary.Write(w, binary.LittleEndian, g.Age) if err == nil { return binary.Write(w, binary.LittleEndian, g.FurColor) } return err } return err } Why does anyone have to tell people not to do this? How does it enter anyone's mind as a thing to do in the first place? I've been known to go too far to minimize nesting. I get twitchy at the second lev…

I normally see a form of it from people that don't like early returns. But if you try to do that with code that explicitly passes pack errors, you end up having to twist the code to avoid early returns. I guess this form pushes all the returns into a list at the bottom, which makes them more comfortable?

People don't like early returns because sometimes they return before some basic cleanup / must have function component is run. Normally added by someone unfamiliar with the function accidentally. Go's defer statement makes this much less of an issue, you bind your work piece with your defer piece so that early returns are fine.

Re: Twelve Go Best Practices

#128
post #40
post #38

Earlier quoted context omitted.

Less than 5% of your coworkers understand decorators? I don't want to sound snooty but this is a pretty trivial application of higher order functions.

I guess I work a lot with average developers. Not every corp is Google.

Since you're a developer let's assume it's just that your estimate is way off :) Multiply it by 3 and pad it with an extra 10% or so.

Re: Twelve Go Best Practices

#129
post #8

Earlier quoted context omitted.

I normally see a form of it from people that don't like early returns. But if you try to do that with code that explicitly passes pack errors, you end up having to twist the code to avoid early returns. I guess this form pushes all the returns into a list at the bottom, which makes them more comfortable?

People don't like early returns because sometimes they return before some basic cleanup / must have function component is run. Normally added by someone unfamiliar with the function accidentally. Go's defer statement makes this much less of an issue, you bind your work piece with your defer piece so that early returns are fine.

Historically some people were against early returns, loop flow control, and the like as part of structured programming's overreaction to the widespread unstructured use of goto for flow of control. They wanted every body of code, be it a function or a loop, to have one entry point and one exit point.

Over time programmers have learned that one entry point, multiple exit points, is OK. But I feel that it is a good habit to flag that with a comment in capital letters so that someone skimming the code can't miss it.

Re: Twelve Go Best Practices

#130

if err == nil { _, err := w.Write([]byte(g.Name)) if err == nil { err := binary.Write(w, binary.LittleEndian, g.Age) if err == nil { return binary.Write(w, binary.LittleEndian, g.FurColor) } return err } return err } Why does anyone have to tell people not to do this? How does it enter anyone's mind as a thing to do in the first place? I've been known to go too far to minimize nesting. I get twitchy at the second lev…

Because the alternative is worse. If you test-and-return after every call, your function has multiple exit points and is far less maintainable. If you nest like this, you at least have a chance of maintaining a single exit point in your function (even though this example fails to do so). This is why the Lord invented exceptions, which it seems that Go does not use. This one example is enough to convince me to never u…

I always use a single exit point in my functions and also a goto to get there from the middle.
Post reply on HN