Last year Ian Lance Taylor and Robert Griesemer released a new draft of Go generics (The Next Step for Generics), and the response from Gopher at home and abroad was overwhelming, with everyone interpreting the draft and this article, and feeling that this version of Go generic design is basically close to Go’s generic goals, and in short, much better than the previous one.
Ian also provided an online compilation tool, go2go, to get a taste of Go generic programming.
What if you compile locally?
Actually Go source code is synced to github, so you just need to download the appropriate branch, compile it yourself, and get this go2go tool. This article guides you if you download, compile, and use this tool, and you can also learn how Go generic code is converted to Go1 code and then run.
Of course, as always, the current design and tools are designed for the draft version, and will change when the official version is released.
Installation
First download the Go code, the branch is dev.go2go
|
|
By following the steps above, you will be able to compile the latest Go tools that support Go generics.
Writing Go generic code
Next let’s write a Go generic application:
In this example, we define a NumberString
interface, which is an extension of the interface, and you can have only numbers or strings implement this interface with the following declaration:
The main purpose is still to constrain the types in the generic. Because we want to use the +
symbol in the body of functions that use generic arguments, only numbers and strings support this operator, so in order for the function to compile properly, you need to constrain the type arguments. The Go
compiler finds objects that are NumberString
objects when it compiles them, so they can be summed using the +
operator.
In this case, the NumberString
interface cannot be implemented by other types, for example, the following code will compile with an error:
Also note that the go2
code files are currently suffixed with .go2
to distinguish them from the Go1
code.
You can now compile and run the above code:
How is the Go2 code compiled?
go2go
converts Go2
code to go1
code for running, which means that it provides generic support through compile-time conversions. So the generic design of Go
is relatively simple, and Go2
also provides backward compatibility.
You can see what magic go2go
does by converting Go2
code to Go1
code with the following command.
|
|
The converted Go1 code is as follows:
|
|
As you can see, for the generic code in the code, because the type parameter needs to be instantiated when instantiating, go2go
specializes the generic code, generating a special type for each type.
So in our example above, the types of c1
and c2
are different, and their types are instantiate୦୦Concat୦int
and instantiate୦ ୦Concat୦string
. Use instantiate
as prefix and type as suffix int
,with ୦୦
and ୦୦୦
as hyphen.
If the type parameters are the same, the same specialised type is used, e.g. c1
and c3
in the following example, both use the same specialised type instantiate୦୦Concat୦int
.
The real code logic of go2go is in go/go2go, which provides the logic for code parsing and conversion, and you can savor the implementation by Ian Lance Taylor and Robert Griesemer. I believe there will be an in-depth Gopher analysis article coming soon.
Then the go2go tool entry code is at cmd/go2go.
Mess up a bit
Since the go2go tool translates Go2 code into Go1 code and specializes the generic types, what happens if we declare a type with the same name as the specialized type? For example, the following code:
|
|
We declare the instantiate୦୦Concat୦int
type in the code and then compile and run it:
|
|
The result is that the compilation fails because the go2go
conversion program also generates a renamed instantiate୦୦Concat୦int
type.
Of course go2go
is still a conceptual tool and will certainly do optimization and type case handling in the future, the related technology is called Name mangling
, which is something the compiler will do.
Reference https://colobu.com/2020/06/18/run-local-go-generic-files/