Experiments with Go generics

generics

Quick experiments with Go generics

  • algebra, a generic square root function for float, complex and and rational.
  • future, a concurrent cache ("future cache").
  • mapreduce, parallel Map, Reduce, and ForEach utilities
  • maps, a map with sorted keys based on a binary tree.
  • metric, a streamz-style multidimensional variable for production monitoring.
  • number, generic functions related to numbers (min, max, abs) and a user-defined complex type.
  • oddities, bugs and quirks.
  • pq, a priority queue
  • slices, generic slice utilities, and a user-defined Slice type.
  • stream, a streams library.
  • striped, a concurrency-safe map using lock striping, and also a custom hash/eq relation.

First impression:

This is really nice. It addresses the main things I miss about generics, namely

  • being able to change the equivalence relation of map;
  • better APIs for data structures like trees, graphs, and priority queues; and
  • the ability to generate efficient specialized code for a range of data types (though I understand that's not guaranteed);

and does so without overwhelming complexity.

By comparison, C++'s templates are extremely powerful, but syntactically and semantically quite complex, and historically the error messages have been both confusing and too late. (Templates also lead to considerable bloat in the text segment, but that may be a risk of the Go approach too.) Java's generics are limited to reference types, and thus are no use for efficient algorithms on (say) arrays of integers. Somehow the Go approach seems to do most of what I need while still feeling simple and easy to use.

Observations:

  • Slices can now be implemented in the language, but not without unsafe pointer arithmetic. The generic slice algorithms work nicely. So does sorting with a custom order.

  • unsafe.Sizeof is disallowed on type parameters, yet it can be simulated using pointer arithmetic (though not as a constant expression). Why?

  • I often need a hash table with an alternative hash function, for

    • comparing non-canonical pointers (e.g. *big.Int, go/types.Type) by their referent;
    • comparing non-comparable values (such as slices) under the obvious relation;
    • using an alternative comparator (e.g. case insensitive, absolute value) for simple types. However, the custom hash function often wants to be at least partly defined in terms of the standard hash function, so the latter needs to be exposed somehow; see hacks.RuntimeHash. I imagine that could be problematic.
  • min, max, abs work nicely.

  • Go's built-in complex numbers could be satisfactorily replaced by a library.

  • The abstract algebraic ring generates pretty good code. One can imagine writing some numerical analysis routines this way when the algorithm is sufficiently complex that it is best not duplicated.

  • I couldn't find a way to achieve ad-hoc polymorphism, that is, defining a generic function by cases specialized to each possible type. For example, I don't know how to write a generic version of all the math/bits.OnesCount functions that uses the most efficient implementation. (Typeswitch doesn't handle named variants of built-in types; and using reflect is cheating.)

  • In practice I suspect concurrent loop abstractions will nearly always want additional parameters such as: a limit on parallelism; a context; cancellation; control over errors (e.g. ignore, choose first, choose arbitrarily, or combine all).

Users will no doubt build generic libraries of collections, of stream processing functions, and of numeric analysis routines. The design space for each is large, and I imagine arriving at simple, efficient, and coherent APIs worthy of the standard library will be an arduous task. But there is no need to hurry.

My experiments have tended to parameterize over built-in types, or "any". I should probably spend more time investigating interface-constrained types.

Owner
Alan Donovan
Software engineer at GitHub; ex-Googler; co-author of https://gopl.io.
Alan Donovan
Similar Resources

Experimenting with golang generics to implement functional favorites like filter, map, && reduce.

funcy Experimenting with golang generics to implement functional favorites like filter, map, && reduce. 2021-12 To run the tests, you need to install

Dec 29, 2021

A collection of functional operators for golang with generics

fn fn is a collection of go functional operators with generics Getting Started P

Jul 8, 2022

Benchmarks to compare Go Generics

This is a collection of various sorts implemnted both as []int only and as const

Dec 8, 2022

Utility library that uses Go generics mechanism

golang-generics-util Utility library that explores Go generics (1.18) xsync Sync

Dec 11, 2022

CDN-like in-memory cache with shielding, and Go 1.18 Generics

cache CDN-like, middleware memory cache for Go applications with integrated shielding and Go 1.18 Generics. Usage package main import ( "context" "

Apr 26, 2022

Go 1.18 generics based slice and sorts.

genfuncs import "github.com/nwillc/genfuncs" Package genfuncs implements various functions utilizing Go's Generics to help avoid writing boilerplate c

Jan 2, 2023

F - Experimenting with Go 1.18 generics to write more functional Go code

f f is a simple library that leverages the new generics in Golang to create a tools for functional style of code. Pipe like '|' in Elixir or Elm. inp

Apr 12, 2022

A hands-on approach for getting started with Go generics.

Go Generics the Hard Way This repository is a hands-on approach for getting started with Go generics: Prerequisites: how to install the prerequisites

Dec 27, 2022

Optional type using Go 1.18 generics.

go.eth-p.dev/goptional Generic Optional (or Go Optional, if you prefer) goptional is a package that provides an implementation of an Optional[T] monad

Apr 2, 2022
Related tags
Code Generation for Functional Programming, Concurrency and Generics in Golang

goderive goderive derives mundane golang functions that you do not want to maintain and keeps them up to date. It does this by parsing your go code fo

Dec 25, 2022
Example code for Go generics

go-generics-example Example code for Go generics. Usage $ go build -gcflags=-G=3 Requirements Go 1.17 or later Advertise Go 言語にやってくる Generics は我々に何をも

Dec 30, 2022
Collection of unusual generics usecases in Go

Unusual Generics Type parameters or Generics in Go designed to reduce boilerplate for container data types like lists, graphs, etc. and functions like

Dec 14, 2022
Package truthy provides truthy condition testing with Go generics
Package truthy provides truthy condition testing with Go generics

Truthy Truthy is a package which uses generics (Go 1.18+) to create useful boolean tests and helper functions. Examples // truthy.Value returns the tr

Nov 11, 2022
Go Library for Competitive Programming with Generics

Go Library for Competitive Programming with Generics Go used to be a difficult language to use for competitive programming. However, with the introduc

Dec 21, 2022
Extended library functions using generics in Go.

Just few extended standard library functions for Golang using generics.

Dec 16, 2021
A library that provides Go Generics friendly "optional" features.

go-optional A library that provides Go Generics friendly "optional" features. Synopsis some := optional.Some[int](123) fmt.Printf("%v\n", some.IsSome(

Dec 20, 2022
experimental promises in go1.18 with generics

async go a prototype of "promises" in go1.18. note: this is just an experiment used to test alternate patterns for dealing with asynchronous code in g

Dec 23, 2022
Go 1.18 generics use cases and examples

Go 1.18 generics use cases What are generics? See Type Parameters Proposal. How to run the examples? As of today, gotip is the simplest way to run the

Jan 10, 2022
Functional tools in Go 1.18 using newly introduced generics

functools functools is a simple Go library that brings you your favourite functi

Dec 5, 2022