Any form of generics needs some way to constrain what types can be used with your generic functions (or generic types with methods), so that you can do useful things with them. The Go team’s initial version of their generics proposal famously had a complicated method for this called “contracts”, which looked like function bodies with some expressions in them. I (and other people) thought that this was rather too clever. After a lot of feedback, the Go team’s revised second and third proposal took a more boring approach; the final design that was proposed and accepted used a version of Go interfaces for this purpose.

Read More

Go is a programming language which passes by value, which effectively means that if you give a value as a parameter to a function, the received value within the function is actually a copy of the original. You can modify it however you wish and your changes will not affect the original value or escape the function scope. This is in contrast to some languages which pass values by reference instead of copying them.

Newcomers to Go, however, will quickly discover that it doesn’t feel as though this is what is really happening in practice. You pass a map into a function only to find that if that function modifies the map, it gets modified everywhere. Worse, the program might just break in mysterious ways or panic altogether! What gives?

Read More

When I wrote about why it matters that map values are unaddressable in Go, there were a set of Twitter replies from Sean Barrett:

Knowing none of the details & not being a go programmer, I would have guessed that map values aren’t addressable because they’re in a dynamically-sized hash table so they need to get relocated behind the user’s back; getting the address of a value slot would break that.

But I’d also have assumed Go has dynamically-extensible arrays, and the same argument would apply in that case, so maybe not?

This sparked an article about how Go maps store their values and keys, so today I’m writing about the second part of Barrett’s reply, about “dynamically-extensible arrays”, because the situation here in Go is peculiar (especially from the perspective of a C or C++ programmer trying to extend their intuitions to Go). Put simply, Go has pointers and it has something like dynamically extensible arrays, but in practice you can’t use pointers to slices or slice elements. Trying to combine the two is a recipe for pain, confusion, and weird problems.

Read More

Go’s last standing major weakness is error handling. A few years ago the list was much longer, with the language missing an adequate package manager, system for pulling static assets into a binary, and generics. But now, the first two have already been addressed been address with Go Modules in 1.11 and go:embed in 1.16, and generics are expected to be in beta form by Go 1.18’s release in December. Errors are the last major omission.

The current Go language memory model was written in 2009, with minor updates since. It is clear that there are at least a few details that we should add to the current memory model, among them an explicit endorsement of race detectors and a clear statement of how the APIs in sync/atomic synchronize programs.

This post restates Go’s overall philosophy and the current memory model and then outlines the relatively small adjustments I believe that we should make to the Go memory model. It assumes the background presented in the earlier posts “Hardware Memory Models” and “Programming Language Memory Models.”

I have opened a GitHub discussion to collect feedback on the ideas presented here. Based on that feedback, I intend to prepare a formal Go proposal later this month. The use of GitHub discussions is itself a bit of an experiment, continuing to try to find a reasonable way to scale discussions of important changes.

Read More

To kick things off, why are constants good? Three things spring to mind:

  • Immutability. Constants are one of the few ways we have in Go to express immutability to the compiler.

  • Clarity. Constants give us a way to extract magic numbers from our code, giving them names and semantic meaning.

  • Performance. The ability to express to the compiler that something will not change is key as it unlocks optimisations such as constant folding, constant propagation, branch and dead code elimination.

But these are generic use cases for constants, they apply to any language. Let’s talk about some of the properties of Go’s constants.

Read More

Go’s place between C and Python in terms of abstraction and garbage collection memory management model has made it attractive to programmers looking for a fast but reasonably high level language. However, there is no free lunch. Go’s abstractions, especially with regards to allocation, come with a cost. This article will show ways to measure and reduce this cost.

A change recently landed in the development version of Go, and will be in Go 1.17, with the title of doc/go1.17: note deprecation of ‘go get’ for installing commands. The actual updated documentation (from the current draft release notes) says:

go get prints a deprecation warning when installing commands outside the main module (without the -d flag). go install cmd@version should be used instead to install a command at a specific version, using a suffix like @latest or @v1.2.3. In Go 1.18, the -d flag will always be enabled, and go get will only be used to change dependencies in go.mod.

I have some views on this. The first one is that this is a pretty abrupt deprecation schedule. Go will be printing a warning for only one release, which means six months or so. People who don’t update to every Go version (or their operating system’s packaged version doesn’t) will go from ‘go get’ working normally to install programs to having it fail completely.

Read More

I’ve spent a lot of time thinking about the best way to handle errors in Go programs. I really wanted there to be a single way to do error handling, something that we could teach all Go programmers by rote, just as we might teach mathematics, or the alphabet.

However, I have concluded that there is no single way to handle errors. Instead, I believe Go’s error handling can be classified into the three core strategies.

If you’ve worked with Go before, you’ve probably seen this runtime error.

panic: runtime error: invalid memory address or nil pointer dereference

The current solution is checking thevar != nil before using the var, but forgetting to do that means your program will crash. That means this simple programmer error could take down your whole server. Hopefully you catch these errors with tests before they reach production. However, we’re not machines so inevitably we won’t catch some of these until our end users encounter an error in production.

Read More

I’m learning Go as a first language, is there any use cases where I should avoid Go?

The release of Go 1.16 introduced a new embed package in the Go standard library. It provides access to files embedded in a Go program at compile time using the new //go:embed directive. It’s a powerful new feature because it allows building a binary with static dependencies like templates, HTML/CSS/JS, or images self-contained. This portability is great for easy distribution and usage. Previously, developers had to rely on third-party libraries for embed behaviour.

In this article we’ll walk through a small demo app, golang-nextjs-portable, that exposes an HTTP server that hosts both an API endpoint, as well as an embedded (Next.js) web app that calls the API.

Read More

I like Go. I use it for a number of things (including this blog, at the time of writing). Go is useful. With that said, Go is not a good language. It’s not bad; it’s just not good.

We have to be careful using languages that aren’t good, because if we’re not careful, we might end up stuck using them for the next 20 years.

This is a list of my chief complaints about Go. Some of these are mentioned frequently, and some are rarely discussed.

I’ve also included some comparisons to both Rust and Haskell (which I consider to be good languages). This is to show that all the problems listed here have already been solved.

Read More

We are excited to announce that native fuzzing is ready for beta testing in its development branch, dev.fuzz!

Fuzzing is a type of automated testing which continuously manipulates inputs to a program to find issues such as panics or bugs. These semi-random data mutations can discover new code coverage that existing unit tests may miss, and uncover edge case bugs which would otherwise go unnoticed. Since fuzzing can reach these edge cases, fuzz testing is particularly valuable for finding security exploits and vulnerabilities.

Read More

Today’s post comes from a recent Go pop quiz. Consider this benchmark fragment.1

func BenchmarkSortStrings(b *testing.B) {
        s := []string{“heart”, “lungs”, “brain”, “kidneys”, “pancreas”}
        b.ReportAllocs()
        for i := 0; i < b.N; i++ {
                sort.Strings(s)
        }
}

A convenience wrapper around sort.Sort(sort.StringSlice(s)), sort.Strings sorts the input in place, so it isn’t expected to allocate (or at least that’s what 43% of the tweeps who responded thought). However it turns out that, at least in recent versions of Go, each iteration of the benchmark causes one heap allocation. Why does this happen?

Read More

Over the past couple months, I’ve been working on a library for constant-time Big Numbers in Go. I think it’s about time that I presented a bit of this work.

In this post, I’ll try to explain what exactly this work is about, and why you might care about it. This post is intended to be an introduction, and shouldn’t require any background in Cryptography.

Golang

Discuss the Go programming language.

Created on Oct 1, 2020
By @root