[HN Gopher] Go Developer Survey 2022 Q2 Results
       ___________________________________________________________________
        
       Go Developer Survey 2022 Q2 Results
        
       Author : tapanjk
       Score  : 146 points
       Date   : 2022-09-08 15:45 UTC (7 hours ago)
        
 (HTM) web link (go.dev)
 (TXT) w3m dump (go.dev)
        
       | throwaway893031 wrote:
       | I begrudgingly use Go.
       | 
       | Go really fucked us by not having sum types or exhaustive type-
       | safe switches or pattern matching. It doesn't even have
       | optionals, or type-safe nillables. The error handling is the
       | least of my concerns.
       | 
       | Moving on, I'd like to see an ML-like language (with hindly
       | milner) that has M:N threading, with pre-emptive multitasking,
       | and safe concurrency with borrow checker like Rust, with both
       | structural and nominal typing.
       | 
       | Something of a mix of Rust, Go, Erlang, and OCaml.
       | 
       | Not sure about error handling, maybe just use exceptions (ala
       | swift), polymorphic variants (ala ocaml), or error unions (ala
       | zig).
       | 
       | Most importantly in the next language iterations, we need to stop
       | with the async/await nonsense, and let the runtime and/or compile
       | handle that.
        
         | [deleted]
        
         | BoorishBears wrote:
         | Have you tried Kotlin?
        
         | mardifoufs wrote:
         | I'm curious about your last point. What's the problem with
         | async/await?
        
       | zinclozenge wrote:
       | I'm glad generics saw good adoption. My wish is that they improve
       | the efficiency of closures so that we can use generic functions
       | to efficiently operate on slices and maps. Writing a for loop
       | just for checking membership is quite tedious.
        
       | kbd wrote:
       | Surprised to see language satisfaction so high. Error handling is
       | very painful, and Go's own tools don't work together (eg. go mod
       | tidy doesn't work properly with `go.work` since being released in
       | 1.18). So many things in the language feel bad for no reason. At
       | least they finally added generics!
        
         | the_gipsy wrote:
         | Compiler simpleness is the reason, and in return it's fast.
         | Still sucks, though.
        
           | _wolfie_ wrote:
           | > and in return it's fast
           | 
           | I'm still curious where this came from. There are slower
           | compilers, sure, but golang's compiler is not that fast. It
           | is very smart about caching, but that is not the same
           | thing...
        
         | randomdata wrote:
         | _> Error handling is very painful_
         | 
         | Wait until you try Typescript. First you have to try/catch and
         | then you _also_ need an if statement to type assert the error
         | in order to do anything with it. Now that 's painful. If errors
         | were commonly returned as values you could beautifully reduce
         | it to if statements alone.
        
           | mekster wrote:
           | If the called function only returns a specific type, how is
           | there a need to type check the returning value?
        
             | randomdata wrote:
             | Thrown errors are always of type unknown, so you have to
             | assert them back into a known type.
             | 
             | Or throw caution to the wind and arbitrarily cast them to a
             | type of your choosing, but that never ends well. A robust
             | and maintainable system can't reasonably do that.
        
         | [deleted]
        
         | 5d8767c68926 wrote:
         | >Surprised to see language satisfaction so high.
         | 
         | Who else do you think responds to these surveys? I have a long
         | list of grievances against Go, so I don't use it, and am not
         | qualified to participate in a survey.
        
           | bheadmaster wrote:
           | To be honest, many other languages have a lot of users that
           | are quite unsatisfied with it, despite using it regularly
           | (Java comes to mind). The fact that most of the people who
           | _use_ Go are happy with it isn 't that insignificant.
        
             | maximus-decimus wrote:
             | "There are two types of languages, the ones no one complain
             | about and the ones no one uses"
             | 
             | -- C++ dude
        
         | beltsazar wrote:
         | Selection bias. Those who are dissatisfied with Go either have
         | abandoned using Go or--if they have to use it at work--wouldn't
         | bother to participate in the survey.
        
       | cletus wrote:
       | I was glad to see Go get generics. Not because it was super-
       | important but rather so we didn't have to hear about it anymore.
       | 
       | I think exceptions are a false economy so I have no real issue
       | with Go's error handling. It could be cleaner. Rust's match
       | expressions are better. Multiple returns are a bit awkward.
       | Something like a result or error union type would be better and
       | could fit in with the type system. Standard errors might allow
       | more automatic (or at least less boilerplate on) propagating
       | errors.
       | 
       | Go's dependency management is the real weak point. Putting domain
       | names in import statements is a massive mistake. Java's Maven
       | repos are simply better. Just ignore the XML for declaring
       | dependencies). Thing slike being able to specify version is what
       | you want. Having someone be able to verify dependencies is what
       | you want. The latter may be necessary in a corporate environment
       | where it may be too much of a security risk to allow open
       | imports.
        
         | nominusllc wrote:
         | > so we didn't have to hear about it anymore
         | 
         | Generics were a mistake, and this is spot on.
        
           | stouset wrote:
           | Almost 40% of respondents either use generics or want to use
           | generics, after having been released 6 months ago in 1.18.
           | That's... a pretty incredible adoption rate for something
           | that I've repeatedly heard wasn't necessary or was a mistake.
        
         | geodel wrote:
         | Maven configuration is a cottage industry in itself. I have not
         | seen developers who know maven from first principles. Despite
         | taking many courses, books, tutorials etc I just dare not touch
         | pom.xml beyond adding/deleting/updating dependencies.
         | 
         | Even then every couple of months maven and IDE combination will
         | run into obscure build issues that will not resolve until all
         | the local maven repos are nuked from desktop.
        
         | icholy wrote:
         | > Putting domain names in import statements is a massive
         | mistake.
         | 
         | Why do you say that? I appreciate the lack of indirection.
        
           | convolvatron wrote:
           | seems to me like a worldview problem. are remote resources
           | really persistent and associated with long lived commercial
           | organizations like github? or are they more like urls that
           | come and go.
           | 
           | it would suck to have to deal with another location service,
           | although one could imagine using something like DNS were it
           | sufficiently secure.
           | 
           | but on the other hand, I'm personally kind of offended that
           | there is a rent-seeking intermediary in the middle of my
           | development process
        
             | arccy wrote:
             | you can run a http(s) server allowing you to disentangle
             | names from hosting
        
           | cletus wrote:
           | Several reasons:
           | 
           | 1. Finding dependencies with tooling now requires parsing
           | code. Luckily Go's syntax is relatively simple and doesn't
           | have conditional includes like C++ does but it'd be better if
           | you could simply inspect a depedency configuration;
           | 
           | 2. You're directly importing potentially untrusted code that
           | will often be of the form "github.io/someuser/reponame" so
           | you now have a depedency on some random user's security
           | practices or even just whims (eg making the repo private;
           | IIRC this has happened in the node.js ecosystem);
           | 
           | 3. These aren't versioned. You may want to stick to a
           | particular version. A new version may break your code. You
           | should be able to be explicit about that. Now you can "go
           | get" particular versions but how do you specify that such
           | that someone can just check out your code and build it?
           | 
           | 4. Managing your own dependency repo (eg in an enterprise
           | environment) is more limited.
        
             | morelisp wrote:
             | 2) doesn't get better just because you put a name that maps
             | to a url in some XML file.
             | 
             | 3) we're six versions into go.mod by default. Nobody has
             | this problem anymore.
             | 
             | 4) Just untrue. Go proxies have been _by far_ the easiest
             | thing to deploy and secure because they're so transparent
             | in the toolchain.
        
       | awb wrote:
       | As a developer, Go seemed so promising 5-10 years ago. But as a
       | recruiter, I never saw any kind of stable movement towards Go
       | adoption among startups.
       | 
       | Hard to tell why that was because functionally and
       | programmatically it's a really clean, efficient language and
       | tooling stack.
        
         | [deleted]
        
         | icy wrote:
         | I would think otherwise, actually. Go seems to be the most
         | popular choice at startups--anecdotally, of course. I have no
         | data to back this, just what I've seen.
        
           | H1Supreme wrote:
           | While I was interviewing a few months ago, there were plenty
           | of startups looking for Go developers. Plus, startups
           | reaching out to me about Go jobs.
        
             | pdimitar wrote:
             | Semi-counterpoint: I tried interviewing for Go jobs and
             | asked the inconvenient questions early.
             | 
             | TL;DR: 11 out of the 12 preliminary interviews were about
             | companies seeking maintainers of "legacy" Go code after
             | important contributors left.
             | 
             | Like with you, not an actual representative sample but
             | quite telling at least from where I am standing.
        
           | [deleted]
        
         | loosescrews wrote:
         | As a recruiter, which languages seemed the most valuable to
         | startups?
        
           | awb wrote:
           | I get constant requests for Node & React (web) and Python (AI
           | / ML) developers.
           | 
           | I do a little recruiting in the mobile space too and there's
           | a small need for React Native but a huge need for native
           | mobile devs.
        
             | rochak wrote:
             | The reason why you are not getting any requests for Go is
             | because you are not asked to find people for backend.
        
               | awb wrote:
               | No, I am. Companies just seem to want their web app
               | backend built on a JS stack, and ask for Node devs.
               | 
               | Maybe Go is more systems/ops heavy, of which I'm not
               | recruiting actively for.
        
               | Aduket wrote:
               | what do you mean by this?
        
         | gregwebs wrote:
         | Anecdotally I just switched from one job using Go to another
         | and saw lots of job openings for companies using Golang. Python
         | definitely has its staying power in the marketplace and Rust
         | seems like it might be on a greater upward trajectory now but
         | is starting from a smaller usage base. Ruby seemed the big
         | loser with companies switching from Ruby to Go and Elixir.
        
         | silisili wrote:
         | I recently spent about 3 weeks looking for new Go positions,
         | just by advertising open for work on LinkedIn.
         | 
         | There are plenty of companies interested, many of them
         | startups. I don't think anyone with a strong Go background
         | looking for a job right now would have any trouble at all.
        
           | cityzen wrote:
           | What is your process for this? Do you have a lot of Go
           | related content in your LI profile or just have your title as
           | Go developer? Any chance I could email you a few questions?
        
             | silisili wrote:
             | I actually don't. I haven't checked in a while, but just
             | looked and my position is just listed as Principal Software
             | Eng. I have no posts, nor any job details. In Skills
             | section I have Linux, Go, Golang, among a few other things,
             | with endorsements.
             | 
             | I think recruiters are perhaps able to scrape skills for
             | keywords? I don't want my identity tied to HN, but if you
             | drop me your email(or add it to your profile) i'll make a
             | throwaway to reach out if you want.
        
       | melony wrote:
       | My main gripe with Go is that a large percentage of first-party
       | documentation is not kept up to date well. If you dive deeply
       | into Go's concurrency patterns, many of the recommended readings
       | are old blogposts from 2014-2016. When the behaviour of the
       | internals change, these blogposts are not clearly marked as
       | deprecated either.
       | 
       | For example this post
       | 
       | https://go.dev/blog/pipelines
       | 
       | should clearly mention that it can still be considered current up
       | to the latest version of Go. First-party documentation needs to
       | be held to higher standards.
        
         | nappy-doo wrote:
         | I don't understand. You're upset that Go's documentation from
         | 2014 is adequate, and that the language hasn't changed to make
         | it obsolete?
        
           | Macha wrote:
           | I think the problem is there is enough stale documentation
           | and valid-but-not-recent documentation that you regularly
           | encounter both which makes distinguishing the two cases
           | difficult
        
           | hbogert wrote:
           | I find the op's perspective weird as well, though I have
           | colleagues which reason like this at well when I point to
           | those blogs/talks of 2014-2016 during reviews -- "that can't
           | be the way to do it 8 years later right?"
        
             | melony wrote:
             | You are missing the point, documentation is either
             | evergreen, or it is not. If you don't clearly state whether
             | your documentation is current, then it leads to a lot of
             | confusion.
        
               | geodel wrote:
               | I'd like to other blogs which of announcement of being
               | current. There are deprecated notice I have seen, else
               | things are considered current by default.
        
       | mfer wrote:
       | I wish they would ask what makes it difficult to work with
       | dependencies in Go.
        
         | numbsafari wrote:
         | I agree with the sibling: go dependencies generally work
         | exactly they way I want them to, and I find it very refreshing
         | relative to other ecosystems.
         | 
         | My guess is that folks coming from those other ecosystems are
         | frustrated that it doesn't work exactly like NPM, which is the
         | general model other ecosystems have decided to follow, despite
         | it being unstable and insecure by design.
         | 
         | Internally, we use a build tool called Please that is very
         | similar to Bazel. We have some internal tooling to automate the
         | generation of third-party dependency boilerplate needed by the
         | build tool. The go dependency tooling actually made this
         | reasonably straightforward and super efficient to accomplish
         | relative to other dependency managemers. If you are in a setup
         | where you aren't working with multiple languages or complex
         | builds, and can just use the raw go tooling to build... the
         | story is even easier.
         | 
         | Would be interesting to hear of specific pain points that
         | others face.
        
           | 6figurelenins wrote:
           | > My guess is that folks coming from those other ecosystems
           | are frustrated that it doesn't work exactly like NPM, which
           | is the general model other ecosystems have decided to follow
           | 
           | The general model for package management in other language
           | ecosystems is rubygems and bundler.
           | 
           | Like: a GitHub founder invented semantic versioning.
        
         | verdverm wrote:
         | What is difficult?
         | 
         | I find them very refreshing compared to other dep mgmt systems.
         | They also have a lot of secondary benefits most are not aware
         | of.
         | 
         | https://verdverm.com/go-mods
        
           | bragr wrote:
           | I find go's package system both too cumbersome for
           | small/quick projects, and yet leaving me wanting in more
           | complex scenarios. It's gotten better of the years, but I
           | never really enjoy my encounters with go-mods
        
             | Thaxll wrote:
             | Go mod is one of the best package manager out there, to
             | work daily you need 5-6 commands that it's and it's very
             | fast.
        
             | bheadmaster wrote:
             | I find go's package system very convenient for quick
             | projects:                   go mod init <name>
             | [write code]         go mod tidy         go build
             | 
             | It's definitely more convenient than Python's venv dance.
        
               | just-ok wrote:
               | Python's venv dance only really comes into play if you
               | need a third-party dependency that you haven't installed
               | globally. The Go dance is _always_ necessary, which makes
               | it slightly more annoying for short scripts or tests. I
               | usually resort to the Go playground for them.
        
               | biztos wrote:
               | I use Go and Python both for short scripts and tests in a
               | very similar way, when the Standard Library covers my
               | needs.                    echo 'package main      import
               | "fmt"      func main() { fmt.Println("hello"); }      ' >
               | foo.go && go run foo.go
               | 
               | But once I have to worry about dependencies, I do prefer
               | Go's "pretend you are a module" dance vs. Python's
               | "discover the differences between your install and the
               | author's install" dance.
        
               | bheadmaster wrote:
               | > Python's venv dance only really comes into play if you
               | need a third-party dependency that you haven't installed
               | globally.
               | 
               | True. Though installing third-party dependencies globally
               | is considered bad practice, since it can easily break
               | system packages.
               | 
               | > The Go dance is always necessary, which makes it
               | slightly more annoying for short scripts or tests.
               | 
               | Well, if you just want to compile/run a single file (or a
               | couple of files) without third-party dependencies, `go
               | build main.go` and `go run main.go` will work just fine,
               | too.
        
               | BobbyJo wrote:
               | I can't tell you how many time global dependencies in
               | python have cause me headaches. Do a small project then
               | do another small project 6 months later and the formers
               | dependencies conflict with the latter's.
        
               | bheadmaster wrote:
               | The whole concept of "only one major version of library
               | can be installed at a time" is completely broken and is
               | the direct cause of diamond import issues. Go designers
               | have correctly recognized that two major versions of a
               | library are actually _two different libraries_ , only
               | under the same name and the same team.
               | 
               | The "v2/ subdirectory" practice of versioning Go packages
               | is one of the things I love the most about Go. Combined
               | with the "packages are directories" philosophy, it makes
               | it easy to use as many major versions of the library as
               | you want, without any complications whatsoever.
        
       | tapanjk wrote:
       | TLDR (listed under "key findings" in the post):
       | 
       | - Generics has seen quick adoption.
       | 
       | - Fuzzing is new to most Go developers.
       | 
       | - Third-party dependencies are a top security concern.
       | 
       | - We can do better when announcing new functionality.
       | 
       | - Error handling remains a challenge.
        
         | [deleted]
        
         | ptsneves wrote:
         | Error handling remains a challenge, but as satisfaction is high
         | it gets no answer at all. Not a single paragraph, how
         | unfortunate. It hits at my major quip with Go: that I do not
         | trust it's governance structure.
         | 
         | Otherwise I really like using it, and would replace it
         | everywhere python is used.
        
           | klabb3 wrote:
           | > It hits at my major quip with Go: that I do not trust it's
           | governance structure.
           | 
           | I normally don't hold back against corporate projects and
           | especially Google's list of forgotten or mismanaged ones.
           | However, I've always felt Go has been doing well, compared to
           | other languages. Older languages painted themselves into a
           | corner (Python, C++) and newer ones (no names mentioned)
           | already struggle with painful design-by-commitee compromises
           | and identity crises.
           | 
           | Every year or so I check in to see what's new in Go, and I'm
           | mostly pleasantly surprised. They're addressing long standing
           | feature requests, add meaningfully to the std lib, and tools
           | get a lot of love as well. Sure, things are incredibly slow
           | sometimes, but long term stability of a global and mature
           | language is one of the hardest things to maintain and grow
           | safely. They also don't leave users hanging with gaping
           | ecosystem holes anymore (anyone remember the pre-go mod days
           | and GOPATH hell?), when other languages throw their hands up
           | and say "HTTP isn't our responsibility, that's a 3p issue" or
           | "it's not our fault people misuse our language features, it's
           | devs that are stupid".
        
           | biomcgary wrote:
           | To each their own. I love that Go is slow to change due to
           | their governance. I think the version of generics that was
           | finally adopted is demonstrably better than the previous
           | proposals. Until the current Go leadership steps down, I
           | really trust the backwards compatibility promise, too.
        
       | totallyunknown wrote:
       | It's a pity that there is few progress in http3 or support for
       | Linux KTLS.
        
         | neonsunset wrote:
         | Might be slightly offtopic but C#'s .NET 7 will ship with http3
         | enabled in Linux by default (needs libmsquic dependency). Also,
         | if it's of interest to you, the performance is significantly
         | better at gRPC workloads than Go:
         | https://aka.ms/aspnet/benchmarks (page 9)
        
       | hajile wrote:
       | Almost 40% of respondents either use generics or want to use
       | generics. That's a pretty quick uptake given the decade of loud,
       | prominent voices shouting that go didn't need and shouldn't have
       | generics.
        
         | randomdata wrote:
         | Random internet comments don't mean anything.
         | 
         | Nobody who mattered said that Go didn't need generics. In fact,
         | Ian Lance Taylor, the lead behind getting generics in Go, has
         | been working on adding generics to Go inside Google since
         | before any of us outside of Google had even heard of Go.
         | 
         | It was always explicitly on the table. It just took a long
         | time, after _many_ failed proposals, to find a solution that
         | didn 't come with unacceptable compromises.
        
           | throw_m239339 wrote:
           | > Random internet comments don't mean anything.
           | 
           | These weren't random internet comments, these were a bunch of
           | well known gatekeepers in the main go mailing list trying to
           | gaslight everybody else and threatening to quit Go if Go ever
           | added generics. Obviously that didn't work and now these
           | people have lost any form of power they thought they have.
           | But these are very public people I won't name here.
           | 
           | > Nobody who mattered said that Go didn't need generics.
           | 
           | Well I guess these people clearly don't matter now, since
           | they are still on the mailing list despite their threats...
           | 
           | > It was always explicitly on the table.
           | 
           | No it wasn't, Rob Pike himself was clearly not interested in
           | adding generics and the effort truly began when Pike left the
           | Go team. Let's not try to rewrite history.
        
             | randomdata wrote:
             | _> these were a bunch of well known gatekeepers in the main
             | go mailing list_
             | 
             | Celebrity status doesn't make someone's comments any less
             | random.
             | 
             |  _> Let 's not try to rewrite history._
             | 
             | No need to rewrite anything. It was written right on
             | golang.org for most, if not all, of Go's public life.
             | Though obviously no longer relevant these days.
             | 
             | The various generics proposals (eight of them, if I recall
             | correctly) were also published publicly.
        
           | avgcorrection wrote:
           | A lot of self-selected (not just any random programmer) Go
           | programmers wanted generics according to the survey. So Go
           | programmers who are motivated enough to find and answer such
           | a survey don't matter?
           | 
           | Actually scratch that, I was wrong. The opinions of regular
           | programmers not mattering is after all one of the
           | philosophies behind the invention of Go.
        
         | summerlight wrote:
         | Yeah, I firmly believe that those purist voices have been over-
         | represented. From 2019, they seems to change the keyword
         | aggregation methodology in Go Dev Survey and the portion of
         | generic just skyrocketed
         | (https://go.dev/blog/survey2019-results) to 79%. And even
         | before that generic had been always one of the top complaints.
        
         | [deleted]
        
         | LukeShu wrote:
         | > loud, prominent voices shouting that go didn't need and
         | shouldn't have generics
         | 
         | The party line has always[1] been that generics would be nice
         | to have, but "We haven't yet found a design that gives value
         | proportionate to the complexity, although we continue to think
         | about it." The prominent voices had been saying "the need is
         | overstated", not "there is no need"; but I understand[2] why so
         | many hear it wrong.
         | 
         | [1]: Language FAQ, from Nov 11, 2009; one day after the 1.0
         | release:
         | https://web.archive.org/web/20091113154906/http://golang.org...
         | 
         | [2]: Nuanced communication usually doesn't work at scale:
         | https://news.ycombinator.com/item?id=30128061
        
           | avgcorrection wrote:
           | > Proportionate to the complexity
           | 
           | If many people like it and find it useful then their armchair
           | calculation of the complexity tradeoff might have been
           | totally wrong.
        
       | lvass wrote:
       | I would dislike if my text editor asked me to fill a survey and
       | would definitely not respond, hopefully they find a better way to
       | randomly sample but surely it's nice to have the random vs self-
       | selected split, I wish the charts showed it better. I'm sure the
       | sample is also heavily biased with non-Chinese respondents,
       | golang seems to be getting really popular in China despite being
       | long past peak popularity elsewhere, unfortunately the survey
       | doesn't give many insights on that.
        
       | whb07 wrote:
       | But first, fix your gopath
        
         | saturn_vk wrote:
         | What gopath?
        
       | bilinguliar wrote:
       | I am delighted with the error handling in Go. Overall I would
       | prefer to Go with the current features and not add more, maybe
       | even deleting some inconsistencies in Go v2.
        
         | nerdwaller wrote:
         | What kinds of inconsistencies are on your mind?
        
           | bilinguliar wrote:
           | I never use new(). It gives a way to allocate, that I would
           | prefer to avoid in favor of declaring zero-value explicitly.
           | Maybe I am missing the point of new().
        
             | nerdwaller wrote:
             | I don't particularly find that inconsistent, though it's
             | usage may not be super common (depending on the type of
             | work you do in go). If you ever need to do atomic
             | operations, it's rather helpful. Though they have been
             | adding new features in go 1.19+ that help there (Int32[1]
             | type, for example). As an aside, for those using atomics -
             | Uber's wrapper library[2] is pretty pleasant to use.
             | 
             | [1] - https://pkg.go.dev/sync/atomic#Int32 [2] -
             | https://pkg.go.dev/go.uber.org/atomic
        
             | 37ef_ced3 wrote:
             | It's used like this                 p := new(int)
             | 
             | since you can't say                 p := &int{}
        
               | bilinguliar wrote:
               | Indeed, this may be the use case. I am curious how often
               | you may need a pointer to an int.
        
               | marwatk wrote:
               | In things like rest APIs you need them quite a bit to
               | distinguish between a value being the zero value and not
               | present at all. Most libraries I've seen have an
               | IntPointer or similar function exposed globally.
        
               | bilinguliar wrote:
               | This is true. In the case of REST, it is your
               | "encoding/json" who will allocate for int pointer. So I
               | do not see why new() is needed.
        
               | 37ef_ced3 wrote:
               | Are you seriously suggesting that the language should not
               | have notation for allocating zeroed primitive types and
               | receiving the address of the allocation?
               | var (           p1 = new(int)           p2 = new(*int)
               | p3 = new(**int)           p4 = new(complex64)
               | p5 = new(complex128)       )
               | 
               | I feel like you must be joking. Should we say
               | var (           c complex128           p = &c       )
               | 
               | every time?
        
               | bilinguliar wrote:
               | In five years, I needed to do the latter only once or
               | twice because a library I was using demanded a pointer to
               | a primitive. Forgive my arrogance, but why does one need
               | a pointer to a zero-value primitive in Go? I sincerely
               | believe there is a use case for it, but I never needed
               | this.
        
               | [deleted]
        
         | codegeek wrote:
         | I have been writing Go code as a hobby for 2 years now (built
         | in house tool as well but nothing production critical yet). I
         | have found the verbose error handling to be very easy to
         | understand and I prefer it that way. Checking for
         | if err != nil
         | 
         | is better for me because I know exactly what to do with errors.
         | Am I missing something ? I am also used to Try/Catch in PHP and
         | many years ago, Java.
        
         | closeparen wrote:
         | Do you write primarily HTTP / RPC services? I've found Go's
         | error handling very tedious when "return an error to the
         | caller" is almost always the answer, but for background stuff,
         | daemons, etc. it's nice.
        
           | bilinguliar wrote:
           | I have misread your comment. So, your experience with
           | handling errors that must be returned to the caller is
           | tedious. Hmm, I do not feel it is tedious. I will likely
           | bubble it up the stack, report it and return a relevant code.
           | 
           | I appreciate that this is almost linear, without mental
           | complexity of exception, where you occupy another part of
           | your brain with accounting for exception handling.
        
           | bilinguliar wrote:
           | I write HTTP/RPC and some TCP servers, implementing specs to
           | parse files and data processing pipelines based on PubSub,
           | NATs, etc.
           | 
           | Whenever the server fails to do what is needed - in most
           | cases, it will retry with a backoff. In case it is not
           | retryable - most often, it will exit, an alert will fire, and
           | I will start handling an incident.
           | 
           | Background jobs run in a goroutine and send a non-retryable
           | error to the channel.
           | 
           | go func() { errChan <- s.ProcessData(ctx) }()
           | 
           | Followed by a blocking select:
           | 
           | select { case err := <- errChan: log.Printf("Server failed:
           | %s", err) case <- ctx.Done(): log.Println("Shutting down") }
           | 
           | Something along these lines.
        
             | closeparen wrote:
             | >Whenever the server fails to do what is needed - in most
             | cases, it will retry with a backoff. In case it is not
             | retryable - most often, it will exit, an alert will fire,
             | and I will start handling an incident.
             | 
             | I don't follow. Requests have deadlines, so you can't keep
             | trying forever. Often a persistent failure means the
             | request itself is bad. Either invalid, or exposing an edge
             | case that the system can't currently handle. These kinds of
             | errors are always present at background levels in a high-
             | scalability system; we have SLAs like 99.99% success rate
             | to decide when there's really an incident. Crashing the
             | entire server process because of one failed request sounds
             | crazy.
        
               | bilinguliar wrote:
               | My bad. I misread your comment. Please see the response
               | one level up.
        
         | kitkat_new wrote:
         | I find that interesting, and like the Rust way of error
         | handling much more.
         | 
         | Go error handling blows the code up a lot and makes the code
         | less comprehensible.                   res1, err1 = canFail()
         | if err1 != nil {             return err1         }
         | res2, err2 = canFail()         if err2 != nil {
         | return err2         }              return res1 + res2, nil
         | 
         | becomes                   res1 = canFail()?         res2 =
         | canFail()?         return Ok(res1 + res2)
         | 
         | guess what is more readable
        
           | movedx wrote:
           | As someone who's not a day-to-day developer/software
           | engineer: the Go code is more readable.
           | 
           | The Rust is interesting, for sure, but I don't know what "?"
           | is doing. I like the use of the question mark as it makes the
           | act of calling the function a question - did it work or not?
           | But what's not obvious is what happens if it did not work?
           | What happens then? Where does the error object go? Is there
           | something that represents the error? Hidden magic isn't good
           | magic, in my opinion. Just be explicit.
           | 
           | Another issue with the Rust example is discipline. I don't
           | know Rust, but the example you've given implies I can not
           | include "?" in the call and just ignore any errors entirely?
           | (What happens if I do that and there's an error? This isn't
           | explicit enough.) Go, in comparison, does the opposite: it
           | forces you to handle the error or literally ignore it. You
           | cannot forget to deal with an error in Go.
           | 
           | And of course, Go gives you an error object you can work with
           | (something I'm sure Rust does too, but it's not obvious to me
           | as a none Rust developer.)
           | 
           | I prefer my languages to be statically typed, statically
           | linked, and very explicit in their syntax. It results in a
           | bit of extra work up front for compile and run time safeties,
           | and the ability to easily re-read the code at a later date.
        
             | avgcorrection wrote:
             | > Another issue with the Rust example is discipline. I
             | don't know Rust, but the example you've given implies I can
             | not include "?" in the call and just ignore any errors
             | entirely?
             | 
             | The issue is that you don't know what you're talking about.
        
             | wtetzner wrote:
             | I'm not sure that optimizing readability for someone
             | unfamiliar with the language is the right tradeoff.
             | 
             | Rust code uses a Result<T, E> type for error handling: it
             | can either be Ok(T) or Err(E), never both.
             | 
             | The question mark operator tries to extract the value
             | wrapped in Ok. If the Result is Err and not Ok, it returns
             | the error. It's not "hidden magic", it's a well-defined
             | operator.
             | 
             | > I don't know Rust, but the example you've given implies I
             | can not include "?" in the call and just ignore any errors
             | entirely?
             | 
             | If you don't unwrap the value from the result, then you
             | still have a Result<T, E> instead of a T, and will get a
             | type error.
        
             | kitkat_new wrote:
             | > But what's not obvious is what happens if it did not
             | work? What happens then? Where does the error object go? Is
             | there something that represents the error? Hidden magic
             | isn't good magic, in my opinion. Just be explicit.
             | 
             | the question mark operator simply checks if there was an
             | error, and if there was one, it returns it. Practically, it
             | does the same as the GO Code - and the only reason you
             | don't know is, because you don't know Rust.
             | 
             | > I don't know Rust, but the example you've given implies I
             | can not include "?" in the call and just ignore any errors
             | entirely?
             | 
             | no, omitting the ? will give you a compiler error. You can
             | ignore the error case by writing:                   res1 =
             | canFail().expect("xz didn't work");
             | 
             | or                   res1 = canFail().unwrap();
             | 
             | If there's an error, the program will crash. There are
             | other alternatives, which e.g. allow you to set 'res1' to a
             | default value in the error case.
             | 
             | > Go, in comparison, does the opposite: it forces you to
             | handle the error or literally ignore it. You cannot forget
             | to deal with an error in Go.
             | 
             | As you see, there is no difference to Go... in this regard.
        
             | josephcsible wrote:
             | > As someone who's not a day-to-day developer/software
             | engineer: the Go code is more readable.
             | 
             | COBOL is what you get when you optimize for readability by
             | people who don't know how to program.
             | 
             | > The Rust is interesting, for sure, but I don't know what
             | "?" is doing. I like the use of the question mark as it
             | makes the act of calling the function a question - did it
             | work or not? But what's not obvious is what happens if it
             | did not work? What happens then? Where does the error
             | object go? Is there something that represents the error?
             | Hidden magic isn't good magic, in my opinion. Just be
             | explicit.
             | 
             | It gets returned to the next level up, exactly like in the
             | analogous Go code above. And that's how it always works, so
             | you don't have to try to figure it out separately for each
             | use of it you see.
             | 
             | > Another issue with the Rust example is discipline. I
             | don't know Rust, but the example you've given implies I can
             | not include "?" in the call and just ignore any errors
             | entirely? (What happens if I do that and there's an error?
             | This isn't explicit enough.) Go, in comparison, does the
             | opposite: it forces you to handle the error or literally
             | ignore it. You cannot forget to deal with an error in Go.
             | 
             | You actually can't do that and will get a compiler error if
             | you try. Rust's type system distinguishes between "a
             | number" and "either a number or an error". On the other
             | hand, Go will let you forget to handle an error, if you do
             | "res1, err1 = canFail()" but then forget to return an error
             | yourself in the "err1" case. Rust's sum types prevent that
             | mistake entirely.
             | 
             | > And of course, Go gives you an error object you can work
             | with (something I'm sure Rust does too, but it's not
             | obvious to me as a none Rust developer.)
             | 
             | Indeed it does. I consider it a good thing that you don't
             | have to deal with language features you're not currently
             | using, though.
             | 
             | > I prefer my languages to be statically typed, statically
             | linked, and very explicit in their syntax. It results in a
             | bit of extra work up front for compile and run time
             | safeties, and the ability to easily re-read the code at a
             | later date.
             | 
             | But Rust fits the bill for all of those things, and if you
             | care about compile time safety, it does so _way_ better
             | than Go.
        
             | rad_gruchalski wrote:
             | > The Rust is interesting, for sure, but I don't know what
             | "?" is doing.
             | 
             | But it's very easy to wrap one's head around it. If the
             | code under question mark returns an error, the function
             | within which that code sits returns early with that error.
             | If that function returns Result<T>, the question mark
             | essentially provides short, composable code.
             | 
             | I never personally had a problem with Go error handling but
             | having prior experience with scala where I often used
             | Try(...).toEither, I love Rust's ?.
        
         | rahen wrote:
         | Likewise. Go was engineered for simplicity mostly in reaction
         | to the complexity of C++. As anticipated, now that we got
         | generics, some developers keep asking for more and more
         | features. Let's not turn Go into another C++ when its goal is
         | to stay a straightforward, simple, modernized C.
        
       | aniforprez wrote:
       | I'm genuinely hoping that after generics, the focus will be on
       | error handling from the survey results
       | 
       | Go devs in a lot of communities love to put their heads in the
       | sand going "error handling is perfectly fine". But it's not fine.
       | Not even close. And I'm very happy there's a lot of demand for
       | some solution in this space. It's just plain too verbose without
       | any of the actual benefits of that verbosity. You don't have
       | compile time checks for errors. Ignoring errors continues to be
       | incredibly easy. The lack of exhaustive switch case statements
       | makes this worse because the compiler doesn't care if you're
       | handling all the expected error types (or unexpected ones). If
       | you simply want to push errors up the chain to be handled
       | elsewhere you're adding 3 lines of code in every function that
       | just does `if err != nil { return nil, err }`. This much
       | verbosity means almost every developer's eyes just glaze over all
       | this code during review which I find to be quite dangerous. If
       | this one thing is adequately fixed in Go, it wouldn't make the
       | language perfect but it would probably make for the most pleasant
       | development experience for building APIs and services
        
         | H1Supreme wrote:
         | > You don't have compile time checks for errors.
         | 
         | I don't quite understand this statement. The compiler finds
         | errors in my code all the time. Should it be evaluating
         | something like `if err != nil`?
        
           | metaltyphoon wrote:
           | I guess what he is saying is that
           | 
           | x, _ := someFunc() shouldn't compile if someFunc has error
           | returns.
        
             | H1Supreme wrote:
             | Ah, that makes sense. I wonder if a compiler flag would be
             | a good compromise? As a way to report unhandled errors, but
             | still let it compile.
        
             | jerf wrote:
             | That syntax basically means "I am deliberately not handling
             | error returns". I always pair it with a comment that
             | explains why I can do that. It comes up. A common one for
             | me for instance is using .Write([]byte) (int, error) on a
             | bytes.Buffer. Because that .Write implements an interface
             | that has an error return, there's an error return, but a
             | byte buffer can never fail to .Write. (If it does due to
             | memory running out, I don't think it ever comes back as an
             | error, just the process terminating.)
             | 
             | There's no point being more particular about it... there's
             | no practical way to _force_ a programmer to handle an
             | error, especially in light of the fact that  "do nothing
             | with the error" is also a perfectly acceptable thing to do!
             | (Example: Writing a JSON document out as the result of an
             | HTTP API call. I don't _want_ to log every such error,
             | because that just crufts up my logs, I don 't need metrics
             | on this particular system, and once the HTTP stream is
             | broken there's nowhere left to write an error out to the
             | user, so... discard it is.)
        
           | [deleted]
        
           | nemothekid wrote:
           | A real problem is when something like this occurs
           | x, err := thisFuncFails();         // some other lines of
           | code, but err is not checked         x.callMethod(); // this
           | crashes at runtime
           | 
           | unless you explicitly ignore `err`, the compiler shouldn't
           | allow you to use `x` without checking err. In Rust/Zig this
           | is accomplished with the union types, which doesn't allow to
           | use `x` until you have checked it's not an error. This is
           | also very useful for Option types; and I wish it was in Go
           | since the beginning as having `nil` in the language is a huge
           | mistake.
        
             | Macha wrote:
             | The problem is worst with procedural functions
             | 
             | os.Mkdir("foo")
             | 
             | looks pretty innocent but with no return value to use, the
             | compiler is no help in reminding you this is a fallible
             | function
        
               | nathants wrote:
               | add errcheck and ineffassign to your build script. the
               | compiler should really do this itself.
        
         | randomdata wrote:
         | Go doesn't have errors, only values. Value handling could be
         | improved, I'm sure, but anything that focuses on values that
         | humans attach error meaning to is fundamentally flawed and will
         | leave broken half-solutions.
         | 
         | Each problem people say Go has with error handling is actually
         | a more general problem with value handling and/or interfaces
         | and the right solution would solve for those problems across
         | the board. The problems are real, but not related to errors
         | specifically.
        
           | erik_seaberg wrote:
           | There are always going to be cases where the happy path call
           | tree should be abandoned because no useful value meeting
           | requirements is going to be possible. What's needed is to
           | persuade Go devs to use panics instead of obscuring every
           | function reinventing them by hand.
        
             | randomdata wrote:
             | The happy path should at least have a value that we oft
             | categorize as error to branch on meaningfully. If the code
             | has no purpose it wouldn't need to be called.
             | 
             | panic is certainly appropriate if programmer error left the
             | application in an inconsistent state (an exceptional state,
             | or exception for short as it is often referred to). I've
             | never seen a Go developer, or developer in any other
             | language for that matter, try to deal with these cases by
             | hand.
        
         | [deleted]
        
         | gregwebs wrote:
         | I am quite convinced that Zig's approach to error handling
         | would apply well to Golang. At least adding a "try" prefix
         | would be an easy change. Add the ability to enable/disable an
         | error return trace and that would do a good enough job handling
         | the majority of error handling boilerplate.                   *
         | https://ziglang.org/documentation/master/#try         *
         | https://ziglang.org/documentation/master/#Error-Return-Traces
         | 
         | I am working on adding this to the compiler now but I know of
         | no actual process for getting such an improvement officially
         | into the Go language.
         | 
         | There are several other concepts in Zig that enhance safety
         | that Go can consider adopting. I personally prefer the
         | soundness of Rust, but Zig is much more philosophically aligned
         | with Go. In error handling alone, we can consider adopting a
         | "catch" suffix as Zig has for when "try" is insufficient as
         | well as error sets. Additionally optional types seem like they
         | would work well in Go.                   *
         | https://ziglang.org/documentation/master/#Optionals         *
         | https://ziglang.org/documentation/master/#Error-Set-Type
        
         | pipe_connector wrote:
         | If I'm reading your feedback correctly it sounds like you want:
         | 
         | 1) Syntactic sugar for if err != nil { return err }; similar to
         | ? in Rust
         | 
         | 2) The errcheck linter to be enforced (part of go vet, maybe?)
         | 
         | 3) Exhaustive switch statements
         | 
         | The first point was looked at and no one has proposed a
         | solution enough of the community could agree was an improvement
         | while maintaining sufficient explicitness. If someone has a
         | really good proposal for this I am sure it would be considered.
         | 
         | The second point could probably happen with enough lobbying.
         | So, verbosity is still there but at least every project will do
         | _something_ with their errors.
         | 
         | The third point I don't believe is possible today because of
         | the way interfaces work. If Go added sum types then this should
         | be possible, but I could be mistaken about that.
        
           | aniforprez wrote:
           | 1) Yes I didn't want to make the tired comparisons to Rust
           | but Rust does have the excellent syntactic sugar for
           | returning errors. Of course, something like this is hampered
           | by the lack of sum types and the ambiguous zero values in Go
           | which makes it more difficult for the compiler to know what
           | to return but I hope we eventually get there or we find
           | another way to do this
           | 
           | 2) I'm not a fan of leaving error checking to linting. It
           | would be fantastic if the compiler would stop for mishandled
           | errors. It already doesn't compile for banal things like
           | unused imports and variables
           | 
           | 3) It's not really a matter of wanting exhaustive switch
           | statements as such but if this was present, it would make
           | error handling much simpler, again a la Rust (I'm sorry)
           | 
           | These are all hopes and wishes to make the language better to
           | work with and I'm sure if we get anything close to any of
           | this, it would be a while. The Go governance seems to move
           | very slowly and deliberately considering how long it took
           | them to wake up to adding generics but we can still dream
        
             | cesarb wrote:
             | > > Syntactic sugar for if err != nil { return err };
             | similar to ? in Rust
             | 
             | > Yes I didn't want to make the tired comparisons to Rust
             | but Rust does have the excellent syntactic sugar for
             | returning errors.
             | 
             | Many people seem to forget that Rust didn't start (even in
             | its 1.0 release) with the ? operator. It started with the
             | try!() macro, which expanded to something not unlike Go's
             | "if err != nil { return err }". The ? operator was added
             | later, as a shortcut to the same semantics as the macro
             | except for also being able to work with Option instead of
             | just Result, based on developer experience with the macro
             | (the two major annoyances being not being able to use the
             | macro with Option, and the nesting when chaining several
             | uses of the macro).
             | 
             | If Rust was able to create the ? operator based on
             | developer experience with its try!() macro, I don't see why
             | Go won't be able to create its own error propagation
             | operator based on developer experience with its "if err !=
             | nil { return err }" idioms.
        
               | masklinn wrote:
               | > If Rust was able to create the ? operator based on
               | developer experience with its try!() macro, I don't see
               | why Go won't be able to create its own error propagation
               | operator based on developer experience with its "if err
               | != nil { return err }" idioms.
               | 
               | Because Go does not have declarative macros. So while
               | Rust got something like 25 versions out of try! before
               | considering that it's worth an operator (but it could
               | well have gone with an other pattern if one had arisen)
               | that's not really an option for go.
        
           | eikenberry wrote:
           | > 1) Syntactic sugar for if err != nil { return err };
           | similar to ? in Rust
           | 
           | IMO they could exactly use what you wrote, ie. change gofmt
           | to have it all on one line like that. The biggest annoyance
           | with the error return boilerplate is the waste of vertical
           | space and just squashing it into 1 line would fix that.
        
             | metaltyphoon wrote:
             | Or perhaps allow variable assignment to be used in the same
             | scope.
             | 
             | if x, err := someMethod(); err != nil { return err }
             | 
             | x <- is usable here.
        
         | klodolph wrote:
         | I would love to see some in-depth discussion about this. Even
         | in 2022, I don't think it's clear what we want error handling
         | to look like. You can ask for correctness guarantees from the
         | compiler, but it's easy to ask, it's harder to design a system
         | that actually works.
         | 
         | > The lack of exhaustive switch case statements makes this
         | worse because the compiler doesn't care if you're handling all
         | the expected error types (or unexpected ones).
         | 
         | I would love to see how this is supposed to work.
         | 
         | My first thought here is checked exceptions in Java. With
         | checked exceptions, you have a specific set of exceptions that
         | a function is supposed to generate, and a compile-time error if
         | those exceptions are not either handled or propagated. This
         | turned out to be a bit of a disaster in actual practice, and
         | I'm not sure what the fix would look like here.
         | 
         | I'm generally a bit miserable when I try to deal with error
         | handling in Rust, believe it or not.
         | 
         | As for the err != nil boilerplate, I've seen some proposals but
         | I haven't seen anything that was clearly a _good_ proposal. The
         | generics proposal was clearly good, IMO, just for a point of
         | reference.
        
           | gregwebs wrote:
           | In Rust you can use the anyhow library if you want a similar
           | level of overhead to Go and similarly aren't worried about
           | differentiating error cases.
           | 
           | What do you think of adopting Zig's error handling approaches
           | to Go?
        
             | klodolph wrote:
             | > [...] and similarly aren't worried about differentiating
             | error cases.
             | 
             | I differentiate error cases in Go, so I'm not sure what
             | you're talking about. Sometimes it's done with ==, other
             | times it's done with type assertions, type switches, and
             | some helper functions in the errors package.
             | 
             | I've barely touched Zig.
             | 
             | I think it's contributing some important ideas, and maybe
             | those ideas will get further developed in newer languages.
        
           | indemnity wrote:
           | > I'm generally a bit miserable when I try to deal with error
           | handling in Rust, believe it or not.
           | 
           | Likewise. I'm a big Rust user, use it for all my personal
           | projects, but error handling is totally unsolved there.
           | 
           | - Friction around mapping between error types if I need to
           | "add context and rethrow"
           | 
           | - Often lack of stack/trace information for custom error
           | types. Something went wrong the the DB query? Great! Where?
           | Which line of code?
           | 
           | There are solutions for these, I try them, and I'm sure
           | someone will pipe up mentioning them (e.g. anyhow, thiserror,
           | miette, etc), but its just so much damn ceremony to do it
           | properly at a particular call site, especially when you are
           | mixing your own code with library code and each library's
           | unique snowflake error types, that I don't do it
           | consistently.
        
           | treis wrote:
           | I'd like stuff like
           | 
           | myFunc() works as today
           | 
           | myFunc()^ returns the err if there is one
           | 
           | myFunc()! panics if there is an err
        
             | majewsky wrote:
             | > myFunc()! panics if there is an err
             | 
             | You can do this with generics today:                 func
             | must[T](val T, err error) T {         if err != nil {
             | panic(err.Error())         }         return val       }
             | //usage example       file := must(os.Create("out.txt"))
             | defer file.Close()       bytesWritten :=
             | must(file.Write([]byte("Hello World\n")))
             | 
             | We have something like this in our internal utility
             | library. I'm getting some serious mileage out of this when
             | using Go as a script language, where error propagation is
             | not as important as for a regular application or a library.
             | 
             | > myFunc()^ returns the err if there is one
             | 
             | You can also do this with generics:                 func
             | geterr[T](val T, err error) {         return err       }
             | 
             | It is true that must() and geterr() are slightly more
             | verbose than single-character operators, but I'd argue
             | having a word instead of a symbol is much more readable.
             | Besides, ^ cannot be used as a postfix unary operator
             | because it's already a binary operator. That would create a
             | grammar ambiguity.
        
             | klodolph wrote:
             | I don't think any option should panic on error. I've had to
             | deal with programs that panic on error and the way I dealt
             | with it was by forking the project and removing every call
             | to panic(). It's even worse with libraries.
             | 
             | The other problem is that it's super common to want to wrap
             | the error somehow when returning it. Often you want to wrap
             | the error differently depending on where the error came
             | from in the function, like this:                 d, err :=
             | os.ReadFile(fname)       if err != nil {         return err
             | // unwrapped       }       x, err := parseX(d)       if err
             | != nil {         return fmt.Errorf("%s: %w", fname)       }
             | 
             | I know that not all Go developers write good error handling
             | code. However, I don't want to make it easier to write bad
             | error handling code if you're not making it correspondingly
             | easier to write good error handling code.
        
               | metaltyphoon wrote:
               | Unless you put the function name somewhere in the error,
               | there is no way to know where something happened. "Some
               | thing didn't write properly? Cool! Where and which line?"
        
         | bheadmaster wrote:
         | > You don't have compile time checks for errors.
         | 
         | Doesn't the fact that errors are values, combined with the fact
         | that you cannot ignore values (except explicitly by assigning
         | them to "_"), provide compile time check for errors?
        
           | teraflop wrote:
           | Not really. It's idiomatic to use a single "err" variable for
           | every error value in the same function body, and the compiler
           | will only check whether that variable is used at least once;
           | it doesn't perform a data flow analysis to ensure that
           | _every_ value that might be assigned is used.
           | 
           | So if you assign 10 different error results to the same
           | variable at various points, but only actually check it 9
           | times and forget the 10th, the compiler will not tell you
           | that anything's wrong.
        
             | bheadmaster wrote:
             | You are right. I forgot about that case.
             | 
             | Perhaps variable re-declarations (via := operator) would be
             | a good addition to Go. Compiler could optimize the code to
             | re-use the variables when possible, but the semantics of
             | the language would force the programmer to handle each and
             | every error.
        
           | stouset wrote:
           | Not really. Go thinks this is fine (on mobile, forgive me if
           | I get this wrong).                   foo, err := foo()
           | if err != nil {              return nil, err         }
           | bar, err := bar(foo)                  return bar, nil
           | 
           | The problem occurs because go only cares if a variable is
           | used once per definition. Not once per assignment.
        
             | bheadmaster wrote:
             | You are right, I have missed that, as I have written under
             | the sibling comment.
             | 
             | Though I'd like to ask - does that scenario really happen
             | in practice? It is idiomatic to handle every error right
             | after the function call that returns the error. To me, the
             | lack of "if err != nil {" under the "bar(foo)" call really
             | stings my eyes.
             | 
             | I know, compile time checking is different from "it doesn't
             | happen in practice". It's a tradeoff. I'm just wondering
             | about the magnitude of the impact.
        
               | stouset wrote:
               | You're looking at a minimal test case, not an example of
               | it happening in real production code. Of course it's
               | obvious in the minimal test case, that's the point.
               | 
               | I've personally written something akin to the following,
               | which triggered no errors (at the time, maybe this is
               | fixed):                   foo, err := foo()         if
               | err != nil {              nil, err         }
               | return foo, nil
               | 
               | The worst part is _because_ all of the error-handling is
               | copypasta boilerplate, your eyes _don 't_ look at it. So
               | subtle bugs get through and make it to production. I've
               | seen this one too:                   foo, err := foo()
               | if err != nil {              return foo, nil         }
               | return foo, nil
               | 
               | Also note that now we've gone from "Doesn't [go] provide
               | compile time check for errors?" to "Well I guess it
               | doesn't check that errors are used, but that would never
               | happen to _me_. "
        
               | bheadmaster wrote:
               | > Also note that now we've gone from "Doesn't [go]
               | provide compile time check for errors?" to "Well I guess
               | it doesn't check that errors are used, but that would
               | never happen to me."
               | 
               | True, but there was also a "you are right" in between :)
        
               | seer-zig wrote:
               | > does that scenario really happen in practice
               | 
               | It does happen, I've seen it several times, and even
               | other insidious examples that linters did not catch. When
               | you're dealing with a code base that is constantly
               | changes, things like that end up happening.
        
         | marwatk wrote:
         | The bigger issue is that returning the error without wrapping
         | provides zero context and after a crash you're stuck trying to
         | figure out which of a hundred calls to Write was responsible
         | for "write error" or some other equally ambiguous message
         | that's nearly impossible to track down.
         | 
         | So you have to resort to a poor man's stack trace: if err !=
         | nil { return fmt.Errorf("my thing: %w", err) }
         | 
         | (We use wrapcheck via golangci-lint to enforce it because not
         | having context for an error has bitten us so many times)
        
           | Gibbon1 wrote:
           | Things I tend to do in my firmware for errors.
           | 
           | Record the error line number where the error happened. Use
           | __builtin_return_address(0) to fink on the caller.
           | 
           | Idle thoughts. Despite it's provenience BASIC's on error goto
           | has merit. The problem with try/catch is creating scoped
           | blocks of code that's annoying.                  try        {
           | // scoped stuff        }        catch        {        }
           | 
           | vs                  on_error_goto label;             // stuff
           | label:
           | 
           | Also a thought is having a separate error_return keyword. And
           | the ability to mark functions with 'no error'
        
             | metaltyphoon wrote:
             | The thing with try/catch is that many times, code that
             | throws doesn't have to be handled on the call site! So you
             | can easily have a happy path and kick the bucket to a
             | location where the error can ACTUALLY be handled property.
        
       | haskellandchill wrote:
       | I'm a Go developer now (oops thought it was a Rust position, will
       | fix this next year). I would put it firmly in the middle of my
       | ranking of industry languages.
       | 
       | Haskell, Rust, Ocaml, F#, Elm > Scala, Kotlin, Swift > Go > Java,
       | C#, C++, C > Clojure, Lisp, Elixir > JavaScript, Python, Ruby, R,
       | Php, Perl
        
       | beltsazar wrote:
       | I wonder if what I heard from some people is true, that at Google
       | Go isn't used as widely as people think.
        
         | clpm4j wrote:
         | Wasn't YouTube rewritten mostly in Go several years ago? Java
         | and C++ won't be displaced as the primary languages at Google,
         | but I think Go is in the top 4 languages they use (along with
         | TypeScript).
        
         | geodel wrote:
         | Well I don't know who are those people. Reasonable people would
         | think Google would not let employees simply re-writing major
         | chunk of existing code for production services in Go. So tons
         | of huge projects in C++/Java/Dart will remain in same languages
         | unless the product itself is sunset. Even then also Go will not
         | be used to write OS kernel, device drivers and such.
         | 
         | So where ever else Go is used it is decent enough.
        
         | pphysch wrote:
         | What do people think? That Google is using it for everything?
        
         | 37ef_ced3 wrote:
         | You can think of Go as the modern representative the Plan 9 and
         | Oberon schools of thought -- their answer to (and replacement
         | for) C and C++.
         | 
         | The fact that it was developed at Google is incidental. That's
         | where Robert Griesemer (Oberon) and Rob Pike (Plan 9) and Ken
         | Thompson (Unix, Plan 9) and Russ Cox (Plan 9) and Ian Lance
         | Taylor, etc., happened to be employed.
        
       | AtNightWeCode wrote:
       | Some thoughts.
       | 
       | There is no best practice on how to structure a Go code base.
       | 
       | go.dev is still ugly. It is ok in comparison to the old
       | Win95-styled design.
       | 
       | That awful closure fib example on go.dev is still a good reason
       | to ignore Go. I would guess most of all devs don't understand it
       | when they read it the first time.
       | 
       | Fuzzing in general is an anti-pattern but can be useful.
        
         | bilinguliar wrote:
         | I struggled with examples of codebase structure when I was
         | learning the language. I looked into code written by Go
         | contributors, and it struck me as "procedural."
         | 
         | This is where a significant shift in my programming started:
         | abandoning OOP, removing unnecessary dependencies, moving from
         | Linux to OpenBSD, from k8s to VM, and from clouds to bare
         | metal. Pros: I understand computers better and have more fun.
         | Cons: companies are still at the stage of moving to a cloud.
         | And now I have to wait for trends to catch up.
        
           | AtNightWeCode wrote:
           | C was the lang I first really learned. You can look at
           | opensource projs and they are all very different. C#
           | solutions for instance are so generic it is almost boring.
        
       | fulafel wrote:
       | Nice to see fuzzing get mainstream visiblity and signs of
       | adoption like this.
        
       ___________________________________________________________________
       (page generated 2022-09-08 23:02 UTC)