Live data from Hacker News

Twelve Years of Go

go.dev

181–190 of 244 posts

Re: Twelve Years of Go

#181
post #120
post #68

Earlier quoted context omitted.

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 }

> 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?

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

#182

I cant believe they are moving forward with "generics". Programmers on average already tend to make things more complicated than they should be. Now every single module in the ecosystem is gonna use more abstractions, generics to fit their social environment. Its well known that abstractions are the devil. How many modules are gonna use generics when they should not? Most? Programmers are bad at programming and they…

If you want to write unmaintainable code in Go, it's already very easy; just use interfaces incorrectly. Go lets bad programmers write bad programs. If you have a solution to that problem, your programming language will be the one that kills all current programming languages. Generics will be similar; people will misuse them, and you'll curse their names when you have to dive in and debug it. But it will also let goo…

> But it will also let good programmers write very good programs and libraries, and that's going to be a huge benefit for everyone.

I hope we can see some good examples of generics being used in the standard library once 1.18 is released.

Re: Twelve Years of Go

#183

Earlier quoted context omitted.

Everything you say compfort me in the fact this is going to be bad. Everything I read in the article about generics compfort me in the fact this is going to be bad. Example: first you agree with me "its already easy to write bad code", well you agree then its gonna be easier. Your example about io.Copy. Yeah bingo, absolutely io is the exception, the only case I know in 25 years of programming that is made tasteful w…

So in your opinion, should Go also not have generics for maps and channels (as they effectively do today), or are those also one of a kind data structures that are worthy of generics? The designers of Go recognized that generic type parameters are necessary.. it’s just that they decided to only bestow them on a few types in the standard library instead of designing a general solution.

So in your opinion, should Go also not have generics for maps and channels (as they effectively do today), or are those also one of a kind data structures that are worthy of generics?

Thats exactly the proper dichotomy. Those choices were made by great language designers, not by programmers. Generics are some type of macros, of course they are useful. In some rare, very sensible cases, where the added complexity is really worth it. In the hands of programmers eager to show how smart they are, they are deadly. Code reviewers all around the world are gonna be like "why dont you use generics here?" just because they can. Bloated code, everywhere.

Go was a niche language suitable for 10x programming. It was modern C. Not C++, not java, not C#, not F#. It was C. The extraordinary, unexpected, return of C. You could write a modern server in C. You could write a modern application in C. It was amazing. It's now victim of its success and might become an industry language. As I mentionned, the grammar being changed, it's literally a new language that's being born. Go++ is being born. Why would you terminate a language which in 12 years has become one of the top 5 choices on the server?

This is not a sensible choice. This is not the choice of the hackers. This is the industry putting its dirty paws on a great piece of technology.

Re: Twelve Years of Go

#184
post #99
post #74

Earlier quoted context omitted.

> No 'oops I forgot to put in a try/catch and now my code died with no explanation'. This is so backwards. First, I want my program to immediately crash if I have a bug. Go is like shell in that it keeps going even if there's an error. Second, I'm used to getting stack traces, Go is the language that will give "no explanation" by comparison if there's a failure.

> First, I want my program to immediately crash if I have a bug. An error being returned doesn't always mean there's a bug. > Go is like shell in that it keeps going even if there's an error. With both Go and shell scripts it's up to you if you want the program to keep going when there's an error.

> An error being returned doesn't always mean there's a bug.

The bug is not the error, the bug is the unhandled error.

Re: Twelve Years of Go

#185

Earlier quoted context omitted.

Most of the time, you'll return early after an error. To get into a situation where you'd need to handle n! cases, you'd need to keep running the statements after a failure, and then collate and return all the errors at the end. Not sure why you'd want to do that. You'd definitely need to go out of your way to do something like this, and probably start asking yourself why you're doing this pretty early on. Plus it wo…

It’s + not * in that example.

Ah, okay. In that case it becomes

  {n + 1 \choose n - 1}
What code are you writing that results in this set of possibilities?

Re: Twelve Years of Go

#186
post #98

Earlier quoted context omitted.

> I'd spend hours condensing 10 lines of perfectly working code into 1 line of the most concise text possible Which is also the hardest part of convincing people to use Go for me: "Why can't I just .map()/.filter()/.find()?" followed closely by "Why do I always have to check for errors?" What is odd to me is that while yes, my Go code is more verbose than my node services - I always end up writing less Go for the sam…

My non-Go code is starting to look more like my Go code. One of the things Go taught me is that I was not being as careful about my errors as I should be. It can be argued that exception-based handling provides you a nice baseline default, but it makes it way to easy when doing network or system-type programming to thoughtlessly default to that, when you need to be thoughtfully defaulting to that. With sufficient car…

Go’s error handling is a strange this to praise considering it is entirely possible to ignore it without warning and the way to check error kinds was bolted on through type assertions when errors are supposed to be values in Go. Error kinds are important especially in network programming when the error can be dozens of different things. Compare this to something like Rust or Haskell which force you to handle errors and their variants.

Re: Twelve Years of Go

#187

A good twelve years. Go really changed the way I think about programming. I used to be excited by programming language features instead of what problem I was actually trying to solve with programming. I'd spend hours condensing 10 lines of perfectly working code into 1 line of the most concise text possible; huffman encoded better than even gzip could imagine. And I'd feel great about it. I'd imagine people reading i…

Go’s package and dependency system is actually the only reason I have never started using it more. The lack of true versioning, unspoken assumption of GitHub, package system, and all of the confusion between god mod, go get, go install, etc. just hurts my brain. I think Rust actually has this perfect. It’s clear. You just specify the name and version and features in the Cargo.toml file and it is pulled from crates.io. No installation-time execution either.

As far as binaries, I think Rust beats it out here too. Take path separators for example. It’s completely possible to have a binary in Go that uses the entirely wrong path separators for the OS. Rust forces you to handle this.

Re: Twelve Years of Go

#188
post #101

Earlier quoted context omitted.

I have often thought that if you could travel back in time and make Java's interfaces work like Go, there would be no Go today. The first-order effects of that change may not seem like much, but the second-order effects of that change is profound. In Java, interfaces must temporally precede their implementations; in Go they don't have to. This turns out to be huge in practice. It turns out that huge swathes of all th…

> This turns out to be huge in practice. It turns out that huge swathes of all that boilerplate and frameworkitis that Java is so well known for are just trying to get around the consequences of that mistake, because all the interface-based structure has to be laid down in advance. I'm a little lost by what you mean here? In my mind the only difference between a Go interface and a Java interface is Java lets you decl…

Java does not let you declare them in the type signature... Java requires you to declare them in the type signature. That means, the interface must precede the implementation, temporally, as in, it must exist first. In purely local development, you may do the implementation before the implementation, but until you at least have them together, the compiler won't let you claim you've implemented that interface.

That means you can't just take an image class from some JPEG library and declare an interface around its already-existing methods. That means the JPEG library has to know all the interfaces that may be useful, and declare them all first. If some of those interfaces are from other libraries, it must depend on those libraries to do it. This pressures image libraries to get together and have to declare "image processing" frameworks, which creates pressures to create all-singing, all-dancing image frameworks because these new interfaces being declared have to work for everything up front. If you get the interfaces wrong, the end-user of these libraries can't just fix them up on the fly. The framework then is pressured to undergo significant churn as it keys in on the correct all-singing, all-dancing set of interfaces to provide, either breaking backwards compatibility or having to drag along every bad decision it made for extended periods of time.

Granted, if a set of libraries does successfully run this gauntlet, the end result can be quite impressive, but it's a hell of a gauntlet to run!

This is also why it's at least a modestly acceptable Java practice to pre-emptively declare an interface for anything you think you might need an interface for later, because if you don't do it now, you'll have a harder time coming back and doing it later. I have a Java code base where darned near every class is basically duplicated, as both an interface and an implementation. I understand not everyone thinks this is good practice, but the language still pushes you in that direction even so. In Go, it simply neither good practice, nor something the language pushes you towards.

In Go, if I need to parse PNGs, I get a PNG parsing library. It just parses PNGs. The author of the library can make the best PNG library they care to, and the author of the library has no obligations to pre-declare any interfaces. If someone wants to weave this into a metalibrary, they can, and they don't have to fork the PNG library to do it, they can easily declare interfaces as they like, wrap things if they like, whatever. It's all more flexible. You're less likely to end up with that best-of-breed, all-singing, all-dancing awesome framework that is integrated and does everything in the end... but in the meantime you also get to use all the code that would have failed to finish the Java gauntlet.

In Java, because interface declarations must temporally precede all implementations, there's this huge pressure constantly pulling things into huge, all-encompassing frameworks, because all requirements are constantly being pushed up into the interfaces... the same interfaces that also have to exist first, before they can use them.

On paper, this is such a small little difference. It even sounds good... "why, of course we should have to declare conformance to interfaces? What if we accidentally implemented an interface and all hell broke loose? [1]" In reality... it's been a huge mistake.

[1]: My answer to that, BTW: http://www.jerf.org/iri/post/2954

Re: Twelve Years of Go

#189
post #138
post #101

Earlier quoted context omitted.

I have often thought that if you could travel back in time and make Java's interfaces work like Go, there would be no Go today. The first-order effects of that change may not seem like much, but the second-order effects of that change is profound. In Java, interfaces must temporally precede their implementations; in Go they don't have to. This turns out to be huge in practice. It turns out that huge swathes of all th…

Java’s nominal typing is both better and worse at the same time - but go is not novel in that area, plenty of similar languages existed before as well, so I don’t think having it contributed to go’s success. As for your last paragraph, I feel like we often mean something different between a production-level go and java project. Non-IDE java development is entirely possible, but I think a prod project usually means so…

"plenty of similar languages existed before as well, so I don’t think having it contributed to go’s success."

I struggle to think of one that has risen to the heights Go has risen.

I'm a computer language polyglot and a bit of a language tourist, though not as much as some people. There's a huge churn of features out there in some language somewhere, that has never manifested in any top-level language like C++ or Java. (For instance, array-based programming has been experimented with quite a bit, but has never been in a top-grade language. The closest that I know of is NumPy.) Whether Go is a top-level language or not at this point is a matter of legitimate debate (depends a lot on your exact definition), but it's certainly knocking on it.

The closest I can name are things like Python, but there is a fundamental difference between run-time duck typing and compile-time interface conformance, although they're certainly related.

Re: Twelve Years of Go

#190
post #98

Earlier quoted context omitted.

My non-Go code is starting to look more like my Go code. One of the things Go taught me is that I was not being as careful about my errors as I should be. It can be argued that exception-based handling provides you a nice baseline default, but it makes it way to easy when doing network or system-type programming to thoughtlessly default to that, when you need to be thoughtfully defaulting to that. With sufficient car…

I think this is for sure the first time I have ever heard someone say that Haskell makes it too easy to handle error cases.

To be more precise, it is the language that makes error-as-values so easy that it actually strays over into "as easy to forget about errors as exception-based handling".

You can successfully build huge chains of code that are just blindly passing errors up without adding any context about where they happened or anything in a way that even Rust can't compete with.

Haskell mitigates this issue by also having one of the more clever ways of dealing with errors, if you start getting into monad transformers or some of the advanced stuff, so it's not all bad. But it definitely can make it so easy to "handle" errors that you just forget about them.

Post reply on HN