Go Commentary #3: Generic Collections, Generics Constraints, AI Bot

Writing generic collection types in Go: the missing documentation

  • Context:

    • Generics were released in Go 1.18 (~2y), is not used very much - only in some good cases for methods in slices and maps packages.
  • Problem:

    • Wanted to write a sortable Set (slice or map) of any type but the documents for a generic collection are poor and immature.
    type Sortable[T comparable] interface {
        Less(member T) bool
    }
    
    type Name struct {
        First string
        Last string
    }
    
    func (n Name) Less(member Name) bool {
        return n.First < member.First || n.First == member.First && n.Last < member.Last
    }
    
    var _ Sortable[Name] = Name{}
    
    type SortableSet[T Sortable] interface { // cannot use generic type Sortable[T comparable] without instantiation
        Add(member T)
        Size() int
        Contains(member T) bool
        Sorted() []T
    }
    
    • Can try what built-in slices does in slices.go
    func Index[S ~[]E, E comparable](s S, v E) int {
        for i := range s {
            if v == s[i] {
                return i
            }
        }
        return -1
    }
    
    type SortableSet[T Sortable[E], E comparable] interface {
        Add(member T)
        Size() int
        Contains(member T) bool
        Sorted() []T
    }
    
    • But not work for map:
    type MapSet[T Sortable[E], E comparable] struct {
        members map[T]struct{} // invalid map key type T (missing comparable constraint)
    }
    
  • Solution:

    // Type set used only for constraints, not vars
    type SortableConstraint[T comparable] interface {
        comparable
        Sortable[T]
    }
    
    type SortableSet[T SortableConstraint[T]] interface {
        Add(member T)
        Size() int
        Contains(member T) bool
        Sorted() []T
    }
    
    type SliceSet[T SortableConstraint[T]] struct {
        members []T
    }
    
    type MapSet[T SortableConstraint[T]] struct {
        members map[T]struct{}
    }
    
  • Conclusion:

    • Current Google rearch results are not really helpful since the immaturity

    • The official Go documentations (proposal/ language spec) are too long

    • This article is very handy as considerably pioneering in real life implementation at @Dolt

    • Cheat sheet found in spec by the author:

    type argument      type constraint                // constraint satisfaction
    
    int                interface{ ~int }              // satisfied: int implements interface{ ~int }
    string             comparable                     // satisfied: string implements comparable (string is strictly comparable)
    []byte             comparable                     // not satisfied: slices are not comparable
    any                interface{ comparable; int }   // not satisfied: any does not implement interface{ int }
    any                comparable                     // satisfied: any is comparable and implements the basic interface any
    struct{f any}      comparable                     // satisfied: struct{f any} is comparable and implements the basic interface any
    any                interface{ comparable; m() }   // not satisfied: any does not implement the basic interface interface{ m() }
    interface{ m() }   interface{ comparable; m() }   // satisfied: interface{ m() } is comparable and implements the basic interface interface{ m() }
    
    

Russ Cox is working on a bot

  • Context:

    • As there is @gopherbot to try to help automate: labeling, commenting, changing issues' status...

    • Gaby (Go AI Bot) is being built (experiment) for what LLMs can be used effectively (including identifying what they should not be used for).

    • Source is not official nor open, can help snoop around in this search and help send feedback.


sticker #2
Subscribe to Dwarves Memo

Receive the latest updates directly to your inbox.