This article is about what it means to add generics to Go, and why I think we should do this. I will also touch on a possible change in the architecture of the language in order to add generics.
Go was released on November 10, 2009. Less than a day later, the
first comment about generics appeared . It also mentions exceptions that we added to the language in the form of panic and recover at the beginning of 2010.
For three years of observation, the absence of generics has always been a list of three main problems that need to be fixed in the language.
Why are generics needed?
What does adding generics mean and why do we want it?
To paraphrase
Jazayeri and others : programming with generics allows you to represent functions and data structures as generics, excluding types.
What does this mean?
Suppose we need to represent the elements of the slice in the reverse order. This is not a very common task, but also not so rare.
Suppose we have a slice of integers.
func ReverseInts(s []int) {
first := 0
last := len(s)
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
. . , . , .
func ReverseInts(s []int) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
1,
last
. .
func ReverseStrings(s []string) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
ReverseInts
ReverseStrings
, , , . .
Go,
Reverse
, .
.
Python JavaScript . Go , , .
, ++, Java, Rust Swift, .
Go
Go?
, (interface type) , .
sort.Sort
.
, Go — . . , , , .
. . . , , , , , - , . — , , .
, , , - . Go , , , ,
Index
, . , , . -, , map' . Go , . .
-
Reverse
, reflect, . , .
,
Reverse
. . ,
Reverse
, - , , .
, , , Go, . , , , , . .
, , , , . , . , Go . .
Go . , . .
Go
, Go,
Reverse
. . , Go .
open source, , -
Reverse
, .
, «» . «» , . , , ++, , .
Reverse
, , , :
. , , ++.
, Go .
, . Go. , .
, . , . , , , .
Go - : map. , , . , . ,
[]int
, , , .
map' — - , . :
-, , , , map: , , , .
, , - .
,
Reverse
: - , , , . map, , , , .
Go . , .
, , .
Big Rock Candy Mountain, ,
. . , Go . , .
Go , , . , , , . .
, , .
. , .
-,
, -. , . , -, - , . -.
- , . , , , . , .
Go. C . .
Go
, Go . Go . . , , - .
Go. : , , Go .
, . , , Go.
Gophercon (Robert Griesemer)
Go. , .
Reverse
.
func Reverse (type Element) (s []Element) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
, .
.
Element
(type parameter). , , , .
, , , .
func ReverseAndPrint(s []int) {
Reverse(int)(s)
fmt.Println(s)
}
(int)
,
Reverse
.
, , , , .
- .
func ReverseAndPrint(s []int) {
Reverse(s)
fmt.Println(s)
}
-
Reverse
ReverseInts
ReverseStrings
, , .
Go , .
, -, - .
Reverse
.
Element
, Go. -, , .
.
func IndexByte (type T Sequence) (s T, b byte) int {
for i := 0; i < len(s); i++ {
if s[i] == b {
return i
}
}
return -1
}
bytes strings
IndexByte
.
b
s
,
s
[]byte
. - bytes strings. , .
,
T
—
[]byte
.
len
, byte.
T
. , , - ,
T
.
Sequence
. .
Sequence
.
contract Sequence(T) {
T string, []byte
}
, :
T
[]byte
. , . .
,
, Gophercon 2018, , . , , . , .
/ . .
,
String
[]string
s
.
func ToStrings (type E Stringer) (s []E) []string {
r := make([]string, len(s))
for i, v := range s {
r[i] = v.String()
}
return r
}
: ,
String
.
,
String
.
Stringer
.
contract Stringer(T) {
T String() string
}
,
T
String
.
,
fmt.Stringer
, ,
ToStrings
fmt.Stringer
. - ,
fmt.Stringer
.
fmt.Stringer
, Go . ,
fmt.Stringer
.
.
type Graph (type Node, Edge G) struct { ... }
contract G(Node, Edge) {
Node Edges() []Edge
Edge Nodes() (from Node, to Node)
}
func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) {
...
}
func (g *Graph(Node, Edge)) ShortestPath(from, to Node) []Edge {
...
}
, . . ,
Node
Edges
, ,
Node
.
Edge
Nodes
,
Nodes
,
Edge
.
,
New
,
Graph
,
ShortestPath
Graph
.
, - . .
(Ordered types)
Go
Min
. ,
Max
. ,
Min
, .
Min
, . :
func Min (type T Ordered) (a, b T) T {
if a < b {
return a
}
return b
}
Ordered
,
T
, « », « », .
contract Ordered(T) {
T int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
string
}
Ordered
— , . , , - . , « ».
, « », , . , Go .
, , , -, . , -, , . - , , .
, , .
Min
(, , ) .
Ordered
, .
func Min (type T contracts.Ordered) (a, b T) T {
if a < b {
return a
}
return b
}
-
, - , . , .
type Tree (type E) struct {
root *node(E)
compare func(E, E) int
}
type node (type E) struct {
val E
left, right *node(E)
}
.
New
.
func New (type E) (cmp func(E, E) int) *Tree(E) {
return &Tree(E){compare: cmp}
}
,
v
, , .
func (t *Tree(E)) find(v E) **node(E) {
pn := &t.root
for *pn != nil {
switch cmp := t.compare(v, (*pn).val); {
case cmp < 0:
pn = &(*pn).left
case cmp > 0:
pn = &(*pn).right
default:
return pn
}
}
return pn
}
, , . , - .
, .
func (t *Tree(E)) Contains(v E) bool {
return *t.find(e) != nil
}
This is the code for inserting a new value.
func (t *Tree(E)) Insert(v E) bool {
pn := t.find(v)
if *pn != nil {
return false
}
*pn = &node(E){val: v}
return true
}
E
. - . , Go, , .
.
var intTree = tree.New(func(a, b int) int { return a - b })
func InsertAndCheck(v int) {
intTree.Insert(v)
if !intTree.Contains(v) {
log.Fatalf("%d not found after insertion", v)
}
}
. - , . -- .
, . , , , . , , .
CL, go/types. , , , . , , .
, -, , . , , . , , - . , .
, , , Go. . , .
— , -, , Go. , — , , , , . , - Go.