Go 1.16 Release Notes
golang.org
golang.org
It's the calm before the storm.
But I love that. :) 10 years in, Go is still my favorite language when it's the right tool for the job.
So actually, this is an exciting release IMO. Highlights:
- darwin/arm64 support (M1 chips)
- Go module quality-of-life improvements
- Built-in support for embedding files
- File system interface! (io/fs)
- Linker optimizations!
- io/ioutil -> io
- Lots of juicy crypto/* package improvements. Filippo and team are crushing it!
No, I don't think so.
I personally think Go's proposed implementation of parametric polymorphism a great feat of modern software engineering, and a testament to the open source process.
Anyway, they'll probably land in Go 1.18.
Luckily I do have some ability to use C++ at my current job, so I can get my fix again there :)
I don't actually think that's a bad thing: I love it that Google pays people to work on Go full time, and don't mind the language being spear-headed by a tight team with a vision (who happen to work at a commercial entity). I'm impressed with their direction, and ability to say no.
Personally, I'm opposed to adding generics, but if we have to...I trust the Go devs to do it better than just about anyone else.
Forgive my ignorance, when would you recommend go? As in what problem domains have you seen it excel at?
I have thought about trying it in the past and even tinkered with a project for a bit but didn't quite find it useful enough to be worth the tooling cost (at the time). Would like an excuse to check it out again.
Btw thanks for that.. I recently moved to a new VPS and migrated from nginx to Caddy.. I love it.
Go is pretty good for almost anything server-side. I wrote a web server in Go that a lot of businesses use in production. It's a very practical "get things done" language and is generally associated with developer satisfaction/happiness. Almost anywhere you use C/C++, I would try to use Go.
It's progbably easier to enumerate what Go is not good at: native GUIs, C interop, some kinds of data science (though I used it as much as Python in college), and some kinds of very low-level programming (though it can be good for embedded systems, if you can stomach large binaries).
Which aspects do you like? Personally I have grown to dislike the pointless abstraction and obfuscation introduced by huge inheritance hierarchies, so Go is a breath if fresh air in that regard in just doing away with it all. I haven't missed classes at all.
If you try to recreate inheritance in Go it will be frustrating and not very useful.
The shape of the code ends up very different and embedding is not used even half as much as inheritance (which is the default position in most other oop languages). That has profound impacts.
inheritance is just like in COM via delegation and struct embedding.
IMO, If you compare Go to an OOP language that runs in a VM there are some things that will fall short but the industry has worked around it. It's not cool to have a beefy Smalltalk or Java VM, with the dynamic runtimes that let you auto-export objects as remote endpoints... you have small binaries exporting HTTP or RPC services running in containers and interfacing with service discovery and fabric systems. The "object orientation" is now at an abstraction sitting above the running binary.
I'm not sure why an application running in the JVM in a container is any different. Can you elaborate?
If someone asks me to build something and they tell me it will run in docker/kubernetes, have the standard containerized CI pipelines, and communicate with other services over some standard protocol like HTTP; doing it on the JVM is doable and probably easier than ever but I would just think about all the cool JVM features I wouldn't get to use (hot code deploy, runtime modularity tools, all the neat bytecode hacks, even spring which everyone but me seems to hate).
If I don't get to use those features then I would rather grab a language like Go, since it doesn't front load so many runtime complexities. (and if this was 10-15 years ago maybe I'd say "Go doesn't front load so many complexities AND performance penalties")
That is how component based programming works.
COM/UWP have proven you don't need to have it available.
They get lots of hate due to their underlying complexity, however they are the main Windows APIs since Vista, as COM took over the Longhorn vision.
GUI libraries often rely on specific language features so they are hard to wrap in other languages. That's why good GUI libraries don't exist in ANY language other than the ones they were written in.
If you install the Gtk libraries on the Mac, Go programs written with gotk3 just compile and run there too.
I'd argue node.js is even easier to learn and even better for getting something useful deployed faster.
I do a lot of golang but whenever I want to do something web browser facing, I cave in for nodejs. Especially in the exploratory phase when building front / back end together.
- Did your TypeScript properly import all of the @types packages required for it to compile properly? They need to be installed alongside the source packages and match the version numbers. They are often maintained separately and may not match the underlying implementation of the code.
- How do you run this in production? Do you check the compiled TypeScript into the git repo? Do you run with ts-node? Do you do different things in production, development, and test?
- Do all of your native dependencies support the node versions you're using? How do you install the correct version of node? If you ignore these issues by using Docker, how are you managing your images and containers?
The list of problems requiring solutions goes on and on. And of course those solutions exist, but this is a summary of why node projects are not "easy to learn". Don't get me wrong, Node can still be the right tool for the job, in particular if you're sharing a lot of code between an app and something that will run in the browser.
Everything I've needed has always been a `require()` or `npm add` away.
Absolutely! REST API servers, data processing jobs, messaging servers, etc etc. I use Go now for virtually everything server side. It is fast, reliable, great tooling, promotes unit testing, and now that I have hit that "comfortable with the language" spot, I have never been more productive.
Arguably, that's more because of the way you can pretty much completely rely on io.Reader and io.Writer being used pervasively throughout the ecosystem (3rd party libraries and all) rather than any specific "Go" special sauce, but, it is what it is.
I would like to compute a load factor and refuse new requests. Or do some basic rate limiting. But the coroutine is spawned before I have a say...
Even if you consult something per request, goroutines are fast enough to look at something and then decide not to do the work that, again, by the time that's a problem, the solution is to throttle upstream anyhow.
As the load increase you enter the territory of queueing (add latenxy) up to a point. Then reject/drop requests. If the rejection is slower than the OS/hardware can provide the software crashes.
For Go it appears that the curve is an almost straight vertical line to oblivion.
But of course if you plan to scale and use a dedicated software to pace requests, there is no point into adding this complexity to the Go libraries.
Maybe what I lament here. Is that this tradeof made by Go is not more advertised. Such that when the day comes that the dreaded out of memory killer shows up, you are ready to fight back.
I think when considered in isolation, Go would be perfect for this. However, I haven’t used it because my existing code in this area is in C++ and I’m not sure how well the two languages interoperate.
I have wrapped a large C++ library for Go it was a pretty straight forward process. I created a file with C callable functions that get passed pointers to the C++ objects and invoke the corresponding methods on that object. On the Go side pointer gets wrapped in a struct type for each C++ class and in the methods on that type I call the C functions. Works great.
How well does it work the other way round - calling Go from C/C++? IIRC when I first looked into doing that, it wasn’t really possible - only threads that were started by Go could run Go code. In particular, `main` had to be in Go and couldn’t be in C++. Does that restriction still apply?
I actually think this is a bit too much magic:
> import _ "embed"
> //go:embed hello.txt
> var s string
> print(s)
But the embed.FS example looks much nicer, I'm glad we can have both.
As a bonus, if you typo the "include_bytes!" macro, as say "includ_bytes", you get a compiler error.
With the go one, if you typo it as "//gp:emebd hello.txt", then you get no compilation error, just an empty string.
If someone compiles your program with an old version of the go compiler, they get no error, just a totally broken program.
Meaningful comments are some of the worst magic you can add to a language IMO.
It's far simpler to reason about compiler-checked preprocessor instructions or macros, both of which are valid alternatives the go team could have added just as easily.
Also, go users have _already_ started parsing comments for magic strings, so it's not like setting an example of using comments is stopping users from doing this crap too.
A macro language which is defined in a clear and consistent way definitely seems less magic than a macro language which has no real definition, other than examples of comments.
Actually now - the import protects from that.
If you want a new compiler feature, add a new statement.
Otherwise these magic comments will grow into their own unaudited meta language with no formal spec, just a few usage examples.
This and struct tags (another stringy metalanguage) are the bits I’m not keen on in Go.
The go 1 guarantee only says that existing go programs will continue to compile correctly on new releases. It doesn't say that new programs will compile correctly on old releases.
> As announced in the Go 1.15 release notes, Go 1.16 drops support for x87 mode compilation (GO386=387). Support for non-SSE2 processors is now available using soft float mode (GO386=softfloat). Users running on non-SSE2 processors should replace GO386=387 with GO386=softfloat.
This change makes perfect sense to me (you'd have to be running a 20+ year old CPU to still need x87 float support, and plenty of distros have already dropped it), but I'm curious as to whether it was partially motivated by Go's decision to implement their own optimizing compiler and surrounding ecosystem. Modeling x87 is a real pain, one without obvious benefits when outside of a mature surrounding framework (like LLVM or GCC).
Can someone with knowledge of Go's compiler internals opine on this? It'd be interesting to hear which bits are sources of historical pain/relative ease.
Copy of part of it:
1) While 387 support isn’t a huge maintenance burden, it does take time away from performance and feature work and represents a fair amount of latent complexity.
2) 387 support has been a regular source of bugs (#36400, #27516, #22429, #17357, #13923, #12970, #4798, just to name a few).
3) 387 bugs often go undetected for a long time because we don’t have builders that support only 387 (so unsupported instructions can slip in unnoticed).
4) Raising the minimum requirement to SSE2 would allow us to also assume many other useful architectural features, such as proper memory fences and 128 bit registers, which would simplify the compiler and runtime and allow for much more efficient implementations of core functions like memmove on 386.
5) We’re exploring switching to a register-based calling convention in Go 1.16, which promises significant performance improvements, but retaining 387 support will definitely complicate this and slow our progress.
The 5) didnt make it into go1.16 but will be focused on again for go1.17.
As an aside, I would love to see Go have first class support for watch/hot reload while developing...! (e.g. go run --watch main.go)
Modd watches file changes and rebuilds, while Devd enables livereload, letting me make changes in my text editor and then see the rendered changes in the browser, side-by-side, in near real-time.
This is for go web development but I'm pretty sure these two tools are language-agnostic.
Its not first class, but I have been happy using reflex [1] for non-http and gin [2] for http. Combined with Go's fast compile they work as well as a hot reload.
I built https://github.com/superhuman/lrt which tries to solve this problem in a go-like way (no configuration required, minimal log noise, and reliability/simplicity as the primary design goals) for Superhuman.
watchexec -cr "make && my-server"
[0] https://github.com/watchexec/watchexec//go:embed main.go go.mod go.sum LICENSE README makefile static/*
var sourceCode embed.FS
// ...
func main() {
// ...
http.Handle("/source/", http.StripPrefix("/source/", http.FileServer(http.FS(sourceCode))))
// ...
} package main
import (
_ "embed"
"fmt"
)
//go:embed quine.go
var src string
func main() {
fmt.Print(src)
}I didn't take the time to really read the spec for go generics, but i really hope the gray beards didn't compromise on letting developers shoot themselves in the foot with overly complex design.
Nowaday i would recommend every developer to go through a 3-month coding session with go, solving real problem, to really appreciate how much one can do with just basic tools and an elegant design (with a few diving session in the stdlib codebase, which is just a pure gem).
This is by far the most important aspect of the language.
That's fine, you won't have to use them, or even use code that depends on generics.
And I won't have to remember a dozens of silly slice tricks each time I have to implement complex data pipelines with different struct types.
https://github.com/golang/go/wiki/SliceTricks
Everybody is happy.
No because C++ still requires some amount of manual memory management, unlike the rest of languages you listed.
I'm not sure how the generics implementation in Swift has any bearing on how generics will work in Go.
No, it's just people complaining about generics for the sake of it at that point.
* Camp 1: generics will always be horrible, Go is right not to include it, it's too complex, Go is meant to be simple, etc.
* Camp 2: I will never use Go because it doesn't have generics, serious languages have generics, etc.
When in reality, both camps are pretty much wrong. Yes, generics are useful in a lot of places. But they also add no value in a lot of places. It's really on you to pick the tool you want to use. If you really want generics, pick C++ or Java instead. If you couldn't care less, Go is an option. It's much more fluid than this binarization of the topic has made it out to be.
I’ve been using Go in the frontend in many (most?) of my personal projects since the early days of GopherJS, and by now I’ve compiling most of that frontend code to Wasm. I’m very happy with the experience and results, and my top wishlist item would be improvements to the binary size for faster first-time loads.
If you haven’t already seen it, https://golang.org/wiki/WebAssembly has lots of good info.
TinyGo is far better, but only supports a subset of Go's stdlib.
I'm playing with TinyGo, and using GPRC communication with the outer engine as a poor substitute for WASM interface types.
https://github.com/fizx/goingo if you want to read the ugly prototype!
goingo is a great idea... excited for it!
> go install now accepts arguments with version suffixes
> The go mod vendor and go mod tidy subcommands now accept the -e flag, which instructs them to proceed despite errors in resolving missing packages.
Do these mean I can finally reliably build the dependencies beforehand, to better utilize Docker layer cache, using this hack?[1][2]
I'm not a fan of using pervasive environment variables. It feels like cluttering my own, well, environment. I very much prefer using explicit command-line options, or even configuration files. Does anybody share the same opinion?
GOINSECURE=foo.com,*.bar.com go get ./...It's nice to see the float parsing speedups too.
I do wish the Unicode package wasn't tied to the Go release cycle. Unicode 13 was released in March of last year.
If unicode was an external library, it would be my responsibility to update this identifier parsing library.
...except that only Go 1.16 can parse those statements, so I need to wait for everyone else to upgrade first. :(
Can this be used to imbed a dynamically growing SQLiteDB? If so that would be a killer feature.
Unfortunately SQLite with Go still requires the remote host to have a c compiler (must use CGO), which makes even a static binary much less portable.
It's read-only.
I read this feature as beneficial for folks who do not need to scale frontends and want to embed resources in the binary to that end. This was already possible before but it looks like they just gave us an official channel for doing so.
No, you just need the shared object.
If you need to export the SQLite, it is better to write a separate goroutine that exports the SQLite file into a remote storage like S3.