|
|
Log in / Subscribe / Register

Eleven Years of Go

The Go blog celebrates eleven years of Go language development and looks forward to what comes next. "When the pandemic hit, we decided to pause any public announcements or launches in the spring, recognizing that everyone’s attention rightly belonged elsewhere. But we kept working, and one of our team members joined the Apple/Google collaboration on privacy-preserving exposure notifications to support contact tracing efforts all over the world. In May, that group launched the reference backend server, written in Go."

to post comments

Eleven Years of Go

Posted Nov 10, 2020 23:43 UTC (Tue) by HelloWorld (guest, #56129) [Link] (9 responses)

As Einstein once said, things should be made as simple as possible, but no simpler. Go is an example of what happens when you do try to make them simpler.

Eleven Years of Go

Posted Nov 12, 2020 3:12 UTC (Thu) by Paf (subscriber, #91811) [Link] (8 responses)

Would you be willing to expound on this a bit?

Eleven Years of Go

Posted Nov 12, 2020 4:01 UTC (Thu) by ncm (guest, #165) [Link]

Let's not.

People who like Go like it. The rest of us like other languages. There is little to be learned from a language's omissions.

Eleven Years of Go

Posted Nov 12, 2020 5:38 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

explanations, err := iDlikeToExplain()
if err != nil {
    return nil, err
}
for _, n := range explanations {
    fmt.Printf("But the explanation is too wordy %v", n)
}

Eleven Years of Go

Posted Nov 12, 2020 20:34 UTC (Thu) by ibukanov (subscriber, #3942) [Link]

What is puzzling is that various proposal to make error handling less verbose were rejected as those are against spirit of Go.

I suppose even pure formatting change to allow to put on one line if err != nil { return err; } and reduce at least vertical verbosity to see more code on the screen will be similarly rejected. It will be against simplicity spirit with its overly complicated formatting rule.

Eleven Years of Go

Posted Nov 13, 2020 14:10 UTC (Fri) by HelloWorld (guest, #56129) [Link] (4 responses)

The Go developers chose to forgo “complicated” features such as generics to the point where not having them severely limits code reuse, making the code more verbose and thus harder to read. Cyberax already pointed out error handling, but that is only the tip of the iceberg.

Ultimately a good programming language shouldn't try to solve any particular problem. The job of a programming language is to allow the programmer to write a solution to a problem in way that is composable and re-usable so that he only has to do it once. Go does the exact opposite: the designers picked a few problems that they are interested in and built solutions for these into language. Everybody needs collections, so they added maps and arrays. They decided they need concurrency, so they added channels. They decided they need resource management, so they added the defer statement. None of these need to be built in, they can all be built as libraries instead if you have a decent language. The most critical aspect here is a decent type system, which is something that Go sorely lacks.

Let's take the defer statement. When you place the defer keyword at the beginning of a statement, that statement will be put on a stack to be executed when the function returns. So you can open a resource (a file or a socket, say), then use `defer myResource.Close()`, and the resource will be closed when you're done – easy enough. But there is no mechanism at all that forces or even encourages you to add that statement – it's very easy to forget. And it gets worse: the defer statement is utterly useless when you're trying to implement a composite resource, meaning a resource that is composed from several underlying resources that all have to be disposed. Such a resource would need a corresponding `make` function which needs to allocate all the underlying resources, and if allocating one of them fails, the ones you have allocated so far need to be freed again. It also needs a corresponding `Close` function to clean everything up again. `defer` does absolutely nothing to help you with that.
So what does a proper solution to this problem look like?
https://typelevel.org/cats-effect/datatypes/resource.html

`Resource` is a type that bundles together the actions to allocate and free a resource. It has a `use` method, which takes a function as a parameter. The use method will allocate the resource, call the function and pass the resource as a parameter, and then free the resource – it's not possible to leak the resource unless you specifically request this. `Resource` also has methods to compose different resources together into a composite resource, making that a trivial endeavour. And not only that: `Resource` is in fact a full-blown Monad, which enables the programmer to use a boatload of functionality that was written with entirely different monads in mind. This is what programming should look like.

And the problem is that basically every feature in Go is like that. It often kinda sorta works for the common cases, but as soon as you try to do something interesting and different, you're on your own, and once you have a solution, the language makes it virtually impossible to reuse in a useful way. The irony is that Rob Pike actually seems to recognize that compositionality is useful and important:
https://commandcenter.blogspot.com/2012/06/less-is-expone...
It's so weird to see somebody espouse compositionality like that, and then come up with a language that makes compositionality harder to achieve than basically any other recent language out there. He must have been living under a rock for decades as far as programming language research is concerned.
Like C's language design, Go's is fundamentally rooted in the 1960s, and I believe that this is part of the reason some people like it: they learn a few trivial improvements like the `defer` statement, and can otherwise basically carry on programming like they did in C. That makes them feel good about themselves and they like that. Learning something genuinely new otoh makes you acutely aware that there is a *lot* of stuff in the world that you don't know anything about, and that is so frustrating to many people that they'd rather stick with a 1960s-style language like Go and accept boilerplate and lack of compositionality and reuse as a fact of life. These are the kinds of people that Go caters to, and frankly, if that were the only reason to avoid it (it isn't), that'd be enough by itself.

Eleven Years of Go

Posted Nov 15, 2020 21:06 UTC (Sun) by NYKevin (subscriber, #129325) [Link]

TL;DR: Go is exactly the opposite of Lisp. So it has exactly the same problem as Lisp (i.e. you love it or you hate it).

Eleven Years of Go

Posted Nov 23, 2020 2:24 UTC (Mon) by jccleaver (guest, #127418) [Link] (2 responses)

> Like C's language design, Go's is fundamentally rooted in the 1960s, and I believe that this is part of the reason some people like it: they learn a few trivial improvements like the `defer` statement, and can otherwise basically carry on programming like they did in C. That makes them feel good about themselves and they like that. Learning something genuinely new otoh makes you acutely aware that there is a *lot* of stuff in the world that you don't know anything about, and that is so frustrating to many people that they'd rather stick with a 1960s-style language like Go and accept boilerplate and lack of compositionality and reuse as a fact of life. These are the kinds of people that Go caters to, and frankly, if that were the only reason to avoid it (it isn't), that'd be enough by itself.

The depressing thing is that, if you're going to write C your code is going to end up much more useful within pre-existing ecosystems if you simply... write it in C (or C++). Go and Rust are PITAs to package and maintain in traditional distributions, and invite a painful and unsettling amount of bundling. Most of the useful tools I've seen in either Go or Rust would be completely do-able in open source C, but are instead in things it's so hard to recompile and that toss so much stability out the window that we resort to downloading third-party blobs more or less out of necessity. It's ugly, and seems like the worst of old-school Apple's NIH for the modern Google age.

Eleven Years of Go

Posted Nov 23, 2020 3:18 UTC (Mon) by mathstuf (subscriber, #69389) [Link] (1 responses)

> Go and Rust are PITAs to package and maintain in traditional distributions, and invite a painful and unsettling amount of bundling.

Sure, they could be possible in open-source C. But they haven't been written in C. Why? I surmise because some people like solving problems instead of dealing with all the boilerplate involved with setting up a build system[1], wrangling dependencies like you're from the 90's (because, surprise, some people tend to target things other than Linux distros where useful dependency management is second-rate at best), figuring out a test suite and CI strategy, figuring out distribution mechanisms, documentation hosting, instructions for use, dealing with all the weird linker problems that can arise in C ecosystems (symbol collisions, explaining DT_SONAME, DT_RUNPATH, macOS library IDs and rpath madness, and other fun things).

You know what basically makes all of these problems go away? Cargo.toml, crates.io, and docs.rs. Sure, if you're not FOSS, you've got to figure out registry hoops, but that's fine: you want to keep your stuff secret, you can do some extra work.

> are instead in things it's so hard to recompile

Have you actually done that? What problems have you encountered?

I agree that it's nice when `dnf install ripgrep` works. But it's also nice that if I have a bugfix made upstream, it's literally just a `cargo install --root=$HOME/misc/root/rustup rustup` and I have the latest version available (with a single symlink no less). No need to figure out the build system someone cooked up because "CMake language sucks", "autotools is weird", or whatever excuse people use these days for making Yet Another C Build System.

[1] I say this as a CMake developer, by the way.

Eleven Years of Go

Posted Nov 23, 2020 12:31 UTC (Mon) by nix (subscriber, #2304) [Link]

... though in fact Rust does have its own crazy build system, used only by Rust hackers and those who'd rather build from source than run rustup, with the obvious name "x.py". It's not all *that* unpleasant to tie into autobuilders, though: easier than Mozilla's crazy build system, say.

(x.py is a new special-snowflake one-project build system, but all in all my love for Rust overrides my mild dislike of x.py, which does at least let the Rustaceans write rustc's own build system in Rust itself and exploit cargo's many wonderful features. I can understand why they wanted *that*.)

Everything written in Rust other than Rust itself is much easier to build, because Cargo just works :)

Eleven Years of Go

Posted Nov 10, 2020 23:58 UTC (Tue) by Cyberax (✭ supporter ✭, #52523) [Link] (5 responses)

Go is an example of a language that has amazing tooling (_fast_ and static compilation were a stroke of genius) but the language itself is painfully verbose.

Eleven Years of Go

Posted Nov 11, 2020 0:42 UTC (Wed) by lamikr (subscriber, #2289) [Link] (4 responses)

Go language does not only encourage for keeping things simple by splitting the functionalitity to simple "one directory" packages but really forces it by not allowing anykind of singular calls between classes on two different directories.
I think this is understandable requirement for any published "API"s but I think that inside the one "application package" there should be a some kind of concept that would allow the circular references between the classes on package itself even if they are in different directories.

This would be usefull for example in cases where you define an API in certain classes and then couple of different implementations of those API's in separate classes. Currently the GO forces both the interface classes and the real implementation to be in the same directory, but sometimes the code would be much more easier to read if one could split the different implementations of classes to own sub-directories. As an example of that is one project where I have tens of "helper" classes which are auto-generated from XML. At the moment I need to keep them on same directory with the real implementation code but for me the code would be much easier to handle and check diffs if I could hide these generated classes to some "autogenerated" subdir of the project.

Similar thing with simple example of "Vehicle" interface and multiple different implementations of vehicle (car, bike, motorcycle, boat).
If the code is simple and consist only the Vehicle.go and then each of it's implementation in single file (car.go, bike.go, etc...) then the code stays clean. But in cases where each vehicle implementation is more complicated and requires more than single file, it would be nice if the implementation of each of these vehicles could be hidden behind it's own "subdir'

Eleven Years of Go

Posted Nov 11, 2020 3:03 UTC (Wed) by Cyberax (✭ supporter ✭, #52523) [Link]

> Go language does not only encourage for keeping things simple by splitting the functionalitity to simple "one directory" packages but really forces it by not allowing anykind of singular calls between classes on two different directories.
Uhh... WHUT?

> Currently the GO forces both the interface classes and the real implementation to be in the same directory
It most certainly doesn't.

> If the code is simple and consist only the Vehicle.go and then each of it's implementation in single file (car.go, bike.go, etc...) then the code stays clean. But in cases where each vehicle implementation is more complicated and requires more than single file, it would be nice if the implementation of each of these vehicles could be hidden behind it's own "subdir'
Nobody stops you from doing that. Moreover, Go uses structural typing, so implementations don't actually have to know that they're implementing an interface.

Eleven Years of Go

Posted Nov 11, 2020 3:41 UTC (Wed) by Cyberax (✭ supporter ✭, #52523) [Link] (2 responses)

I think you simply have circular references between packages (Go does forbid this). Just break it and you'll be fine:
- package1
  - api
     api_desc.go
  - car
     car.go
  - train
     train.go

Eleven Years of Go

Posted Nov 26, 2020 13:02 UTC (Thu) by lamikr (subscriber, #2289) [Link] (1 responses)

The problem with circular references are now always easy to break.
Think an example where the vehicle/vehicle.go calls the in vehicle/car/car.go to register to listen events.
Then the vehicle/car/car.go try to call the vehicle/vehicle.go to notify from some of the occured events.

That will cause an circular reference error.
In the simple cases of only a couple of classes it would be fine to fix that by putting all the files to vehicles-dir.

But in real world the car may itself be a little bit more complicated and consist of from multiple files and then it's starts looking messy if all of the files are in same directory. That's why I would like to allow the circular references between directories for the classes that are in same component.

Eleven Years of Go

Posted Nov 26, 2020 22:18 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link]

Extract an interface for registering to events and you'll be fine. I've yet to find an example of a truly unbreakable loop.

Eleven Years of Go

Posted Nov 11, 2020 20:58 UTC (Wed) by anatolik (guest, #73797) [Link]

I discovered Golang several years ago and truly fell in love with it. It is a fantastic language + great tooling for it. I would add Goland IDE to the list of must-use tools for the language.


Copyright © 2020, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds