Skip to content

Instantly share code, notes, and snippets.

@256dpi
Last active February 23, 2019 22:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 256dpi/9354565ed3c1c14862660f5c53fce90d to your computer and use it in GitHub Desktop.
Save 256dpi/9354565ed3c1c14862660f5c53fce90d to your computer and use it in GitHub Desktop.

Composable Types

This proposal describes a new composable type system for Go. It follows the design ideas of the already built-in composable types map and chan and should be understood as an alternative way to implement basic generic data structures.

The following is an example of a queue implemented as a composable type (boring code has been removed):

func main() {
	// compose a queue of integers
	q := comp[int]Queue{}
	
	// reset queue
	q.Reset(size)

	// push items
	q.Push(1)
	q.Push(2)

	// pop first item
	q.Pop()
	// => int(1)
	
	// pop second item
	q.Pop()
	// => int(2)
}

// ---

// Queue is a composable FIFO queue.
type Queue comp Item struct {
	items []Item
	// ...
}

// Reset will reset the queue
func (q *Queue) Reset(capacity int) {
	q.items = make([]Item, 0, capacity)
	// ...
}

// Push will add an item to the queue.
func (q *Queue) Push(item Item) {
	// ...
}

// Pop will get an item of the queue.
func (q *Queue) Pop() Item {
	// ...
}

Details

A composable types is declared by adding the comp keyword and at least one generic type in a struct type declaration:

// A composable type with a single generic type.
type Queue comp Item struct {}

// A composable type with three generic types.
type Foo comp Bar Baz Qux struct {}

The generic types can be used in the struct definition to define properties:

type Foo comp Bar struct {
	bar []Bar
}

And in method declarations as parameters, arguments and variables:

func (s *Foo) Add(bar Bar) Bar {
	var b Bar
}

The composable type can then be constructed when needed using the comp keyword:

// compose a queue of ints
queue := comp[int]Queue

// compose a set of strings
set := comp[string]Set

// compose a type with multiple generic types
foo := comp[int,string]Foo

Composable types are designed to be used for allowing code reuse when implementing generic data structures as for example queues, stacks etc. A good example is the sync.Map that currently uses interface{} for keys and values. With composable types the key and value types could be checked on compile time and allow catching errors early.

Notes

  • Similar to maps comp[int]Queue is in itself already a pointer and thus can be safely shared.
  • Once the compiler sees a composition it compiles it and reports errors if the supplied types are not compatible with the implementation (functions as map keys and similar).
@earthboundkid
Copy link

A) I have always liked the syntax

type Item generic
type Queue struct { items []Item }

B) AFAICT, this doesn’t allow writing eg max(a, b), which seems to be a desired outcome for the Go team.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment