News for hackers. Stuff that matters.
Re:Twelve Years of Go by fpoling on Wednesday November 10, 2021 @02:56PM (#29179765)
Most perceived verboseness of Go comes not from the language or libraries but from the formater that does not allow to compress 3 lines of the error check down to single

if err != nil { return err }

Re:Twelve Years of Go by stouset on Wednesday November 10, 2021 @04:53PM (#29181436)
Worse,

    if res, err := actually_important_bits(...); err != nil {
        return nil, err
    }
The actually important bits are hidden in the middle of line noise. In the "common case" where `actually_important_bits` is just a simple function call it's not necessarily as bad, but the problem is when you have ten successive instances of this and one is slightly different. It's impossible to notice the important difference at a glance.

For an industry that is just starting to understand that code is read hundreds of times more often than it's written, golang fails at the few things we actually know for certain about what makes it easier to understand code at a glance.

Re:Twelve Years of Go by jrockway on Wednesday November 10, 2021 @07:03PM (#29182677)
If you're using `res`, then you aren't going to scope it to the `if` statement. That is maybe another problem, sometimes you have to do this:

    res, err := actuallyImportantBits(...)
    if err != nil { 
        return nil, fmt.Errorf("actually important bits: %w", err)
    }
And other times you have to do this:

   if err := actuallyImportantBits(...); err != nil {
       return nil, fmt.Errorf("actually important bits: %w", err)
   }
The problem here is that you really don't want "err" to leak to the outer scope, so the second case is preferable from an absolute reliability and least-surprise perspective... but you can only do that in certain arbitrary cases. I think it's a bit of a wart.

You can certainly handle "res" in an else block, or even write "err == nil" and handle it there, but that is surprsing. I would say it's simply not done, ever, but the Go codebase itself does it (src/go/parser/interface.go.ParseDir was the first example I found; but my search returned many screenfuls of candidates so there are probably more cases lurking in there).

The fact that you have a choice is not ideal, basically.

But, having actually important bits in if err := ...; err != nil {} blocks is not detrimental to readability. You will know how to read that after 5 minutes of reading any Go program.

Re:Twelve Years of Go by jerf on Wednesday November 10, 2021 @10:00PM (#29183985)
I almost never use that in my code, I almost always use

    res, err := ...
    if err != nil {
        return nil, fmt.Errorf("...: %w", err)
    }
for that exact reason. This doesn't scan any worse than any other text-based code. (Page in the people selling visual programming here.)
Re:Twelve Years of Go by Zababa on Wednesday November 10, 2021 @04:04PM (#29180763)
> if err != nil { return err }

I'm far from a Go expert, but I feel like this line is a bit pointless, especially if you write it a lot. At this point, why not just not handle the error, or panic?

Re:Twelve Years of Go by boloust on Wednesday November 10, 2021 @07:45PM (#29183041)
Because when you're writing a reusable, self-contained function, you often don't know enough of the context to "handle" the error.

Let's say you've got a function that reads from a file. If the file doesn't exist, what do you do? That entirely depends on the context the function is called in. If it's in a web server, you might return a 404. If it's a background task polling for some data, you might sleep for a while until the file is uploaded. Or you might want to create the file yourself.

Re:Twelve Years of Go by jhgb on Wednesday November 10, 2021 @10:56PM (#29184277)
Common Lispers in the back are excitedly waving their hands and whispering: "Restarts! Restarts!"
Re:Twelve Years of Go by closeparen on Wednesday November 10, 2021 @04:10PM (#29180860)
The community strongly discourages panic.
Re:Twelve Years of Go by Zababa on Wednesday November 10, 2021 @04:13PM (#29180904)
I think a panic is still better than a chain of if err != nil { return err } that bubbles up and does nothing. Of course the best solution would be proper error handling but not everyone does that (and it's not always obvious what to do).
Re:Twelve Years of Go by merb on Wednesday November 10, 2021 @04:49PM (#29181394)
and most of the time you can't handle it anyway. I mean consider you are having a database query and it fails because the connection error'd (network split). what to do know? restart the network switches and wait? of course not in http you will just print a 5xx err and hope it comes back. in go you need to bubble up these errors to your middleware and handle it there.
Re:Twelve Years of Go by Karrot_Kream on Thursday November 11, 2021 @12:07AM (#29184616)
If this is seriously what you do when something underneath you fails, then you aren't writing in the domain of software where errors really matter, and you're probably better off in a language that has a gigantic try/catch handler around everything. In that case you may as well just log (or not) and ignore the error in Go as well then.

At high scale, you want to perhaps try your query a few more times, backing off exponentially, maybe even round-robining (or more complicated load balancing) among different targets. Throwing up your hands and 5xx-ing a request that easily is not something you can afford at high scales of traffic where small outages happen _all the time_.

Re:Twelve Years of Go by merb on Tuesday November 23, 2021 @06:52PM (#29325184)
> At high scale

so basically you mean that this only applies to like 0.001% of all websites/apps.

thus it's stupid to do it. I mean even than you would have an error that you need to bubble up or circuit break it somwhere but probably not at this layer.

also KISS and MVP, never ever overcomplicate something when you do not know anything yet, so most people don't need to built for scale at day 1 and it also is stupid to do it.

Re:Twelve Years of Go by Karrot_Kream on Tuesday December 07, 2021 @03:55AM (#29470360)
You can get off-the-shelf libraries that do this for you with zero-effort sane defaults. Most of them let you tweak the settings. I'm talking about Python's `requests` and Rust's `reqwest` here btw, two of the most popular HTTP client libraries out there. Python's `urlopen3`, which `requests` uses, exposes options for backoff strategies. `aiohttp` has a lot of these parameters as well. Unfortunately Rust's equivalent, `hyper`, isn't nearly as ergonomic/easy to use.
Re:Twelve Years of Go by closeparen on Thursday November 11, 2021 @12:29PM (#29190584)
That’s something new handle as close as possible to the outbound client, which is several layers in from the inbound request. Much of it is in gRPC middlewares, so by the time a gRPC client returns an error to the gateway it’s already over.
Re:Twelve Years of Go by sangnoir on Wednesday November 10, 2021 @07:43PM (#29183025)
At the very least, you have to log that error.
Re:Twelve Years of Go by closeparen on Wednesday November 10, 2021 @10:12PM (#29184062)
Our coding convention (and I happen to agree) is that the outermost layer to touch the error is the one to log it. In this case the HTTP handler, or perhaps a gRPC middleware. You don't want to be logging errors as you propagate them, or the logs will show the same error at a bunch of different call sites vs. one complete picture of what happened.
Re:Twelve Years of Go by ohCh6zos on Wednesday November 10, 2021 @04:37PM (#29181233)
A huge issue with Go is ‘idiomatic’ Go.
Re:Twelve Years of Go by throwaway894345 on Wednesday November 10, 2021 @02:58PM (#29179796)
If this is the case, I think the fault here lies with flawed perception and not the formatter.
Re:Twelve Years of Go by fpoling on Wednesday November 10, 2021 @04:44PM (#29181336)
The formater in many cases essentially doubles the number of lines. That requires to scroll much more frequently than with more compact formatting.
Re:Twelve Years of Go by throwaway894345 on Wednesday November 10, 2021 @04:53PM (#29181440)
I understand, but I take issue with the implication that compression makes code more readable.
Re:Twelve Years of Go by pxue on Wednesday November 10, 2021 @03:50PM (#29180566)
Compressing this into 1 line provides absolutely nothing for the reader, in fact, it absolutely takes away reability.
Re:Twelve Years of Go by The_Colonel on Wednesday November 10, 2021 @03:54PM (#29180621)
Readability absolutely suffers when almost everything you see on your screen is boilerplate.
Re:Twelve Years of Go by thatswrong0 on Wednesday November 10, 2021 @04:17PM (#29180951)
Seriously. I see so many functions in my code see that consist of 1 line of thing I actually care about followed by 3 lines of boilerplate if err not nil… over and over again.

IMO if Go didn’t have its tooling, no one would care about it.

Re:Twelve Years of Go by pxue on Wednesday November 10, 2021 @06:17PM (#29182294)
i have the completely opposite take.

every if err != nil; return err let's me mentally draw a line in the sand and not worry about exception handling for code above that line. It lets me start fresh and restart my mental model with the line of codes below the error handling block.

it doesn't take years of writing Go to understand this, all you need is a open mind to how Go does things.

Re:Twelve Years of Go by thatswrong0 on Friday November 12, 2021 @04:36PM (#29204827)
> It lets me start fresh and restart my mental model with the line of codes below the error handling block.

My code is almost exactly:

err := doThing()

if err != nil {

  return err
}

err = doAnotherThing()

if err != nil {

  return err
}

etc.

There's no need for me to "start fresh". Each line of actual stuff doing might return an error which needs to be returned. That's it. It's a complete waste of space and inhibits readability to absolutely no benefit. And this is extremely common across our code base.