Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@tooolbox
Last active September 3, 2020 13:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tooolbox/fb385bfa05032ddc989afb393948be48 to your computer and use it in GitHub Desktop.
Save tooolbox/fb385bfa05032ddc989afb393948be48 to your computer and use it in GitHub Desktop.
Angle Brace Delimiters for Go Contracts

Angle Brace Delimiters for Go Contracts

This document references the Contracts Draft Design for Go Generics, dated 31 July 2019.

The current design uses parentheses to delimit type parameter clauses, but this makes the code difficult to read. This is covered briefly in Non-Parenthetical Delimiters from the essay Towards Clarity: Syntax Changes for Contracts in Go, as well as in many other points of feedback which can be found at https://github.com/golang/go/wiki/Go2GenericsFeedback as linked documents or inline comments.

The official draft states:

Why not use the syntax F<T> like C++ and Java?
When parsing code within a function, such as v := F<T>, at the point of seeing the < it's ambiguous whether we are seeing a type instantiation or an expression using the < operator. Resolving that requires effectively unbounded lookahead. In general we strive to keep the Go parser simple.

I propose a solution to the < ambiguity by adopting the following rules:

  • The <> characters are used to delimit type parameter clauses.
  • In function, method and type declarations, the form used is identifier<types...>.
  • In bare type instantiations, the form used is identifier<type>.
  • In function calls, the form used is function(<types...> arguments...).
  • In struct literals, the form used is struct{<types...> field: value...).
  • In type conversions, the form used is to(<types...> from)

More generally, where a type is expected, the identifier<type> form should be unambiguous because a comparison operation makes no sense.

It seems as though a lesser-than operator would never appear in the following:

  • A type declaration
  • A type alias
  • A contract
  • A var statement
  • A function/method declaration
  • A type assertion

In other words, and especially given inference of type parameters, it seems that there are few scenarios where F<T> could be confused with i < j—mainly something that will evaluate and then be stored in a variable.

Some examples where a comparison would be unexpected:

var v Vector<int>

type List<type Element> struct {
	next *List<Element>
	val  Element
}

type VectorInt = Vector<int>

contract PrintStringer<X> {
	stringer<X>
	X Print()
}

contract G<Node, Edge> {
	Node Edges() []Edge
	Edge Nodes() (from Node, to Node)
}

type Graph<type Node, Edge G> struct { ... }
func New<type Node, Edge G>(nodes []Node) *Graph(Node, Edge) { ... }
func (g *Graph<Node, Edge>) ShortestPath(from, to Node) []Edge { ... }

On the other hand, here are some examples of how it would work with function calls, struct literals, etc:

func Ranger<type T>() (*Sender<T>, *Receiver<T>) {
	c := make(chan T)
	d := make(chan bool)
	s := &Sender{<T> values: c, done: d}
	r := &Receiver{<T> values: c, done: d}
	runtime.SetFinalizer(r, r.finalize)
	return s, r
}

func New<type K, V>(compare func(K, K) int) *Map<K, V> {
	return &Map{<K, V> compare: compare}
}

func (m *Map<K, V>) InOrder() *Iterator<K, V> {
	sender, receiver := chans.Ranger(<keyValue<K, V>>)
	var f func(*node<K, V>) bool
	f = func(n *node<K, V>) bool {
		if n == nil {
			return true
		}
		// Stop sending values if sender.Send returns false,
		// meaning that nothing is listening at the receiver end.
		return f(n.left) &&
			sender.Send(keyValue{<K, V> n.key, n.val}) &&
			f(n.right)
	}
	go func() {
		f(m.root)
		sender.Close()
	}()
	return &Iterator{receiver}
}

(See below for a full code comparison with the existing Contracts draft.)

It's open to opinion, but perhaps this even makes the code more readable than if all type parameters immediately followed the relevant identifier. Consider which is more readable:

sender, receiver := chans.Ranger<keyValue<K, V>>()
sender.Send(keyValue<K, V>{n.key, n.val})
// or
sender, receiver := chans.Ranger(<keyValue<K, V>>)
sender.Send(keyValue{<K, V> n.key, n.val})

By putting the type parameters inside the () or {} it seems a little easier to visually identify Ranger as a method and keyValue as a struct literal.

In summary, this would resolve the ambiguity of:

a := b<x, y con>(j, k) // parser: "b < x"?

by changing it to this:

a := b(<x, y con> j, k) // parser: type parameters ahoy!

(Note: Towards Clarity: Syntax Changes for Contracts in Go contains several other concepts such as the empty contract, an alternate contract syntax, and an alternate type parameter syntax, all of which I maintain are valid, but they were omitted from this document to preserve the focus.

Code Comparison

Design

Type parameters

// Print prints the elements of a slice.
// It should be possible to call this with any slice value.
func Print(s []T) { // Just an example, not the suggested syntax.
	for _, v := range s {
		fmt.Println(v)
	}
}
func Print<type T>(s []T) {
	// same as above
}
	Print(<int> []int{1, 2, 3})

Type contracts

// This function is INVALID.
func Stringify<type T>(s []T) (ret []string) {
	for _, v := range s {
		ret = append(ret, v.String()) // INVALID
	}
	return ret
}

Contract introduction

contract stringer<T> {
	T String() string
}

Using a contract

func Stringify<type T stringer>(s []T) (ret []string) {
	for _, v := range s {
		ret = append(ret, v.String()) // now valid
	}
	return ret
}

Multiple type parameters

func Print2<type T1, T2>(s1 []T1, s2 []T2) { ... }
func Print2Same<type T1>(s1 []T1, s2 []T1) { ... }
contract viaStrings<To, From> {
	To   Set(string)
	From String() string
}

func SetViaStrings<type To, From viaStrings>(s []From) []To {
	r := make([]To, len(s))
	for i, v := range s {
		r[i].Set(v.String())
	}
	return r
}

Parameterized types

type Vector<type Element> []Element
var v Vector<int>
func (v *Vector<Element>) Push(x Element) { *v = append(*v, x) }
// This is OK.
type List<type Element> struct {
	next *List<Element>
	val  Element
}

// This type is INVALID.
type P<type Element1, Element2> struct {
	F *P<Element2, Element1> // INVALID; must be (Element1, Element2)
}
type StringableVector<type T stringer> []T

func (s StringableVector<T>) String() string {
	var sb strings.Builder
	sb.WriteString("[")
	for i, v := range s {
		if i > 0 {
			sb.WriteString(", ")
		}
		sb.WriteString(v.String())
	}
	sb.WriteString("]")
	return sb.String()
}
type Lockable<type T> struct {
	T
	mu sync.Mutex
}

func (l *Lockable<T>) Get() T {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.T
}

Parameterized type aliases

type VectorInt = Vector<int>

Contract embedding

contract PrintStringer<X> {
	stringer<X>
	X Print()
}
contract PrintStringer<X> {
	X String() string
	X Print()
}

Using types that refer to themselves in contracts

package compare

// The equal contract describes types that have an Equal method with
// an argument of the same type as the receiver type.
contract equal<T> {
	T Equal(T) bool
}

// Index returns the index of e in s, or -1.
func Index<type T equal>(s []T, e T) int {
	for i, v := range s {
		// Both e and v are type T, so it's OK to call e.Equal(v).
		if e.Equal(v) {
			return i
		}
	}
	return -1
}
import "compare"

type EqualInt int

// The Equal method lets EqualInt satisfy the compare.equal contract.
func (a EqualInt) Equal(b EqualInt) bool { return a == b }

func Index(s []EqualInt, e EqualInt) int {
	return compare.Index(<EqualInt> s, e)
}

Mutually referencing type parameters

package graph

contract G<Node, Edge> {
	Node Edges() []Edge
	Edge Nodes() (from Node, to Node)
}

type Graph<type Node, Edge G> struct { ... }
func New<type Node, Edge G>(nodes []Node) *Graph(Node, Edge) { ... }
func (g *Graph<Node, Edge>) ShortestPath(from, to Node) []Edge { ... }
type Vertex struct { ... }
func (v *Vertex) Edges() []*FromTo { ... }
type FromTo struct { ... }
func (ft *FromTo) Nodes() (*Vertex, *Vertex) { ... }
var g = graph.New(<*Vertex, *FromTo> []*Vertex{ ... })
type NodeInterface interface { Edges() []EdgeInterface }
type EdgeInterface interface { Nodes() (NodeInterface, NodeInterface) }

Passing parameters to a contract

func MapAndPrint<type E, M stringer(M)>(s []E, f(E) M) []string {
	r := make([]string, len(s))
	for i, v := range s {
		r[i] = f(v).String()
	}
	return r
}

Values of type parameters are not boxed

package from

contract setter<T> {
	T Set(string) error
}

func Strings<type T setter>(s []string) ([]T, error) {
	ret := make([]T, len(s))
	for i, v := range s {
		if err := ret[i].Set(v); err != nil {
			return nil, err
		}
	}
	return ret, nil
}
type Settable int

func (p *Settable) Set(s string) (err error) {
	*p, err = strconv.Atoi(s)
	return err
}

func F() {
	// The type of nums is []Settable.
	nums, err := from.Strings(<Settable> []string{"1", "2"})
	if err != nil { ... }
	// Settable can be converted directly to int.
	// This will set first to 1.
	first := int(nums[0])
	...
}
package pair

type Pair<type carT, cdrT> struct {
	f1 carT
	f2 cdrT
}

Function argument type inference

	Print(<int> []int{1, 2, 3})
	s1 := []int{1, 2, 3}
	Print(s1)
package transform

func Slice<type From, To>(s []From, f func(From) To) []To {
	r := make([]To, len(s))
	for i, v := range s {
		r[i] = f(v)
	}
	return r
}
	strs := transform.Slice([]int{1, 2, 3}, strconv.Itoa)
package pair

func New<type T>(f1, f2 T) *Pair(T) { ... }
type Pair<type T> struct { f1, f2 T }
var V = Pair{1, 2} // inferred as Pair{<int> 1, 2}

Instantiating a function

// PrintInts will be type func([]int).
var PrintInts = Print<int>

Type assertions and switches

contract reader<T> {
	T Read([]byte) (int, error)
}

func ReadByte<type T reader>(r T) (byte, error) {
	if br, ok := r.(io.ByteReader); ok {
		return br.ReadByte()
	}
	var b [1]byte
	_, err := r.Read(b[:])
	return b[0], err
}

Instantiating types in type literals

x1 := []T(v1)   // type conversion
x2 := []T{<v2>} // composite literal of type []T<v2>

Using parameterized types as unnamed function parameter types

var f func(x(T)) // named parameter of type (T)
var g func(x<T>) // unnamed parameter of type x<T>

Embedding a parameterized type in a struct

type S1<type T> struct {
	f T
}

type S2 struct {
	S1(int) // field named S1 of type (int)
}

type S3 struct {
	S1<int> // embedded instantiated type of S1<int>
}

Embedding a parameterized interface type in an interface

type I1<type T> interface {
	M(T)
}

type I2 interface {
	I1(int) // method named I1 with argument of type int
}

type I3 interface {
	I1<int> // embedded instantiated type of I1<int>
}

Pointer methods

contract setter<T> {
	T Set(string)
}

func Init<type T setter>(s string) T {
	var r T
	r.Set(s)
	return r
}

type MyInt int

func (p *MyInt) Set(s string) {
	v, err := strconv.Atoi(s)
	if err != nil {
		log.Fatal("Init failed", err)
	}
	*p = MyInt(v)
}

// INVALID
// MyInt does not have a Set method, only *MyInt has one.
var Init1 = Init(<MyInt> "1")

// DOES NOT WORK
// r in Init is type *MyInt with value nil,
// so the Set method does a nil pointer deference.
var Init2 = Init(<*MyInt> "2")
contract setter<T> {
	*T Set(string)
}

Pointer or value methods

func LookupAsString<type T stringer>(m map[int]T, k int) string {
	return m[k].String() // Note: calls method on value of type T
}

type MyInt int
func (p *MyInt) String() { return strconv.Itoa(int(*p)) }
func F(m map[int]MyInt) string {
	return LookupAsString(MyInt)(m, 0)
}

Operators

// This function is INVALID.
func Smallest<type T>(s []T) T {
	r := s[0] // panics if slice is empty
	for _, v := range s[1:] {
		if v < r { // INVALID
			r = v
		}
	}
	return r
}

Types in contracts

contract SignedInteger<T> {
	T int, int8, int16, int32, int64
}
contract Ordered<T> {
	T int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr,
		float32, float64,
		string
}
func Smallest<type T Ordered>(s []T) T {
	r := s[0] // panics if slice is empty
	for _, v := range s[1:] {
		if v < r {
			r = v
		}
	}
	return r
}

Conjunction and disjunction in contracts

// PrintStringer1 and PrintStringer2 are equivalent.
contract PrintStringer1<T> {
	T String() string
	T Print()
}

contract PrintStringer2<T> {
	T String() string; T Print()
}
contract Float<T> {
	T float32, float64
}
contract IOCloser<S> {
	S Read([]byte) (int, error), // note trailing comma
		Write([]byte) (int, error)
	S Close() error
}
contract unsatisfiable<T> {
	T int
	T uint
}

Both types and methods in contracts

contract StringableSignedInteger<T> {
	T int, int8, int16, int32, int64
	T String() string
}
type MyInt int
func (mi MyInt) String() string {
	return fmt.Sprintf("MyInt(%d)", mi)
}

Aggregate types in contracts

contract byteseq<T> {
	T string, []byte
}
type MyByte byte
type MyByteAlias = byte
func Join<type T byteseq>(a []T, sep T) (ret T) {
	if len(a) == 0 {
		// Use the result parameter as a zero value;
		// see discussion of zero value below.
		return ret
	}
	if len(a) == 1 {
		return T(append([]byte(nil), a[0]...))
	}
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i]) // len works for both string and []byte
	}

	b := make([]byte, n)
	bp := copy(b, a[0])
	for _, s := range a[1:] {
		bp += copy(b[bp:], sep)
		bp += copy(b[bp:], s)
	}
	return T(b)
}

Aggregates of type parameters in contracts

contract Slice<S, Element> {
	S []Element
}
func Map<type S, Element Slice>(s S, f func(Element) Element) S {
	r := make(S, len(s))
	for i, v := range s {
		r[i] = f(v)
	}
	return r
}

type MySlice []int

func DoubleMySlice(s MySlice) MySlice {
	v := Map(<MySlice, int> s, func(e int) int { return 2 * e })
	// Here v has type MySlice, not type []int.
	return v
}
type M<type T> []T

contract C<T> {
	T M(T)   // T must implement the method M with an argument of type T
	T M<T>   // T must be the type M(T)
}

Comparable types in contracts

func Index<type T comparable>(s []T, x T) int {
	for i, v := range s {
		if v == x {
			return i
		}
	}
	return -1
}

Type conversions

contract integer<T> {
	T int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr
}

contract integer2<T1, T2> {
	integer<T1>
	integer<T2>
}

func Convert<type To, From integer2>(from From) To {
	to := To(from)
	if From(to) != from {
		panic("conversion out of range")
	}
	return to
}

Untyped constants

contract integer<T> {
	T int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr
}

func Add10<type T integer>(s []T) {
	for i, v := range s {
		s[i] = v + 10 // OK: 10 can convert to any integer type
	}
}

// This function is INVALID.
func Add1024<type T integer>(s []T) {
	for i, v := range s {
		s[i] = v + 1024 // INVALID: 1024 not permitted by int8/uint8
	}
}
The zero value
type Optional<type T> struct {
	p *T
}

func (o Optional<T>) Val() T {
	if o.p != nil {
		return *o.p
	}
	var zero T
	return zero
}
Lots of irritating silly parentheses
	F(<int, float64> x, y)(s)
Defined aggregate types
func Map<type Element>(s []Element, f func(Element) Element) []Element {
	r := make([]Element, len(s))
	for i, v := range s {
		r[i] = f(v)
	}
	return r
}
type MySlice []int

func DoubleMySlice(s MySlice) MySlice {
	s2 := Map(s, func(e int) int { return 2 * e })
	// Here s2 is type []int, not type MySlice.
	return MySlice(s2)
}
Identifying the matched predeclared type
contract Float<F> {
	F float32, float64
}

func NewtonSqrt<type F Float>(v F) F {
	var iterations int
	switch v.(type) {
	case float32:
		iterations = 4
	case float64:
		iterations = 5
	default:
		panic(fmt.Sprintf("unexpected type %T", v))
	}
	// Code omitted.
}

type MyFloat float32

var G = NewtonSqrt(MyFloat(64))

Sort

type orderedSlice<type Elem Ordered> []Elem

func (s orderedSlice<Elem>) Len() int           { return len(s) }
func (s orderedSlice<Elem>) Less(i, j int) bool { return s[i] < s[j] }
func (s orderedSlice<Elem>) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

// OrderedSlice sorts the slice s in ascending order.
// The elements of s must be ordered using the < operator.
func OrderedSlice<type Elem Ordered>(s []Elem) {
	sort.Sort(orderedSlice(<Elem> s))
}
	sort.OrderedSlice(<int32> []int32{3, 5, 2})
	sort.OrderedSlice([]string{"a", "c", "b"})
type sliceFn<type Elem> struct {
	s []Elem
	f func(Elem, Elem) bool
}

func (s sliceFn<Elem>) Len() int           { return len(s.s) }
func (s sliceFn<Elem>) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
func (s sliceFn<Elem>) Swap(i, j int)      { s.s[i], s.s[j] = s.s[j], s.s[i] }

// SliceFn sorts the slice s according to the function f.
func SliceFn<type Elem>(s []Elem, f func(Elem, Elem) bool) {
	Sort(sliceFn{<Elem> s, f})
}
	var s []*Person
	// ...
	sort.SliceFn(s, func(p1, p2 *Person) bool { return p1.Name < p2.Name })

Map keys

package maps

// Keys returns the keys of the map m.
// Note that map keys (here called type K) must be comparable.
func Keys<type K, V comparable(K)>(m map[K]V) []K {
	r := make([]K, 0, len(m))
	for k := range m {
		r = append(r, k)
	}
	return r
}
	k := maps.Keys(map[int]int{1:2, 2:4}) // sets k to []int{1, 2} (or {2, 1})

Map/Reduce/Filter

// Package slices implements various slice algorithms.
package slices

// Map turns a []T1 to a []T2 using a mapping function.
func Map<type T1, T2>(s []T1, f func(T1) T2) []T2 {
	r := make([]T2, len(s))
	for i, v := range s {
		r[i] = f(v)
	}
	return r
}

// Reduce reduces a []T1 to a single value using a reduction function.
func Reduce<type T1, T2>(s []T1, initializer T2, f func(T2, T1) T2) T2 {
	r := initializer
	for _, v := range s {
		r = f(r, v)
	}
	return r
}

// Filter filters values from a slice using a filter function.
func Filter<type T>(s []T, f func(T) bool) []T {
	var r []T
	for _, v := range s {
		if f(v) {
			r = append(r, v)
		}
	}
	return r
}
	s := []int{1, 2, 3}
	floats := slices.Map(s, func(i int) float64 { return float64(i) })
	sum := slices.Reduce(s, 0, func(i, j int) int { return i + j })
	evens := slices.Filter(s, func(i int) bool { return i%2 == 0 })

Sets

// Package set implements sets of any type.
package set

type Set<type Elem comparable> map[Elem]struct{}

func Make<type Elem comparable>() Set<Elem> {
	return make(Set<Elem>)
}

func (s Set<Elem>) Add(v Elem) {
	s[v] = struct{}{}
}

func (s Set<Elem>) Delete(v Elem) {
	delete(s, v)
}

func (s Set<Elem>) Contains(v Elem) bool {
	_, ok := s[v]
	return ok
}

func (s Set<Elem>) Len() int {
	return len(s)
}

func (s Set<Elem>) Iterate(f func(Elem)) {
	for v := range s {
		f(v)
	}
}

Example use:

	s := set.Make(<int>)
	s.Add(1)
	if s.Contains(2) { panic("unexpected 2") }

Channels

package chans

import "runtime"

// Ranger returns a Sender and a Receiver. The Receiver provides a
// Next method to retrieve values. The Sender provides a Send method
// to send values and a Close method to stop sending values. The Next
// method indicates when the Sender has been closed, and the Send
// method indicates when the Receiver has been freed.
//
// This is a convenient way to exit a goroutine sending values when
// the receiver stops reading them.
func Ranger<type T>() (*Sender<T>, *Receiver<T>) {
	c := make(chan T)
	d := make(chan bool)
	s := &Sender{<T> values: c, done: d}
	r := &Receiver{<T> values: c, done: d}
	runtime.SetFinalizer(r, r.finalize)
	return s, r
}

// A sender is used to send values to a Receiver.
type Sender<type T> struct {
	values chan<- T
	done <-chan bool
}

// Send sends a value to the receiver. It returns whether any more
// values may be sent; if it returns false the value was not sent.
func (s *Sender<T>) Send(v T) bool {
	select {
	case s.values <- v:
		return true
	case <-s.done:
		return false
	}
}

// Close tells the receiver that no more values will arrive.
// After Close is called, the Sender may no longer be used.
func (s *Sender<T>) Close() {
	close(s.values)
}

// A Receiver receives values from a Sender.
type Receiver<type T> struct {
	values <-chan T
	done chan<- bool
}

// Next returns the next value from the channel. The bool result
// indicates whether the value is valid, or whether the Sender has
// been closed and no more values will be received.
func (r *Receiver<T>) Next() (T, bool) {
	v, ok := <-r.values
	return v, ok
}

// finalize is a finalizer for the receiver.
func (r *Receiver<T>) finalize() {
	close(r.done)
}

Containers

// Package orderedmap provides an ordered map, implemented as a binary tree.
package orderedmap

import "chans"

// Map is an ordered map.
type Map<type K, V> struct {
	root    *node<K, V>
	compare func(K, K) int
}

// node is the type of a node in the binary tree.
type node<type K, V> struct {
	key         K
	val         V
	left, right *node<K, V>
}

// New returns a new map.
func New<type K, V>(compare func(K, K) int) *Map<K, V> {
	return &Map{<K, V> compare: compare}
}

// find looks up key in the map, and returns either a pointer
// to the node holding key, or a pointer to the location where
// such a node would go.
func (m *Map<K, V>) find(key K) **node<K, V> {
	pn := &m.root
	for *pn != nil {
		switch cmp := m.compare(key, (*pn).key); {
		case cmp < 0:
			pn = &(*pn).left
		case cmp > 0:
			pn = &(*pn).right
		default:
			return pn
		}
	}
	return pn
}

// Insert inserts a new key/value into the map.
// If the key is already present, the value is replaced.
// Returns true if this is a new key, false if already present.
func (m *Map<K, V>) Insert(key K, val V) bool {
	pn := m.find(key)
	if *pn != nil {
		(*pn).val = val
		return false
	}
	*pn = &node{<K, V> key: key, val: val}
	return true
}

// Find returns the value associated with a key, or zero if not present.
// The found result reports whether the key was found.
func (m *Map<K, V>) Find(key K) (V, bool) {
	pn := m.find(key)
	if *pn == nil {
		var zero V // see the discussion of zero values, above
		return zero, false
	}
	return (*pn).val, true
}

// keyValue is a pair of key and value used when iterating.
type keyValue<type K, V> struct {
	key K
	val V
}

// InOrder returns an iterator that does an in-order traversal of the map.
func (m *Map<K, V>) InOrder() *Iterator<K, V> {
	sender, receiver := chans.Ranger(<keyValue<K, V>>)
	var f func(*node<K, V>) bool
	f = func(n *node<K, V>) bool {
		if n == nil {
			return true
		}
		// Stop sending values if sender.Send returns false,
		// meaning that nothing is listening at the receiver end.
		return f(n.left) &&
			sender.Send(keyValue{<K, V> n.key, n.val}) &&
			f(n.right)
	}
	go func() {
		f(m.root)
		sender.Close()
	}()
	return &Iterator{receiver}
}

// Iterator is used to iterate over the map.
type Iterator<type K, V> struct {
	r *chans.Receiver(keyValue<K, V>)
}

// Next returns the next key and value pair, and a boolean indicating
// whether they are valid or whether we have reached the end.
func (it *Iterator<K, V>) Next() (K, V, bool) {
	keyval, ok := it.r.Next()
	if !ok {
		var zerok K
		var zerov V
		return zerok, zerov, false
	}
	return keyval.key, keyval.val, true
}
import "container/orderedmap"

var m = orderedmap.New(<string, string> strings.Compare)

func Add(a, b string) {
	m.Insert(a, b)
}

Append

func Add(s, t []byte) []byte
package slices

// Append adds values to the end of a slice, returning a new slice.
func Append<type T>(s []T, t ...T) []T {
	lens := len(s)
	tot := lens + len(t)
	if tot <= cap(s) {
		s = s[:tot]
	} else {
		news := make([]T, tot, tot + tot/2)
		copy(news, s)
		s = news
	}
	copy(s[lens:tot], t)
	return s
}
// Copy copies values from t to s, stopping when either slice is
// full, returning the number of values copied.
func Copy<type T>(s, t []T) int {
	i := 0
	for ; i < len(s) && i < len(t); i++ {
		s[i] = t[i]
	}
	return i
}
	s := slices.Append([]int{1, 2, 3}, 4, 5, 6)
	slices.Copy(s[3:], []int{7, 8, 9})

Metrics

package metrics

import "sync"

type Metric1<type T comparable> struct {
	mu sync.Mutex
	m  map[T]int
}

func (m *Metric1<T>) Add(v T) {
	m.mu.Lock()
	defer m.mu.Unlock()
	if m.m == nil {
		m.m = make(map[T]int)
	}
	m[v]++
}

contract cmp2<T1, T2> {
	comparable<T1>
	comparable<T2>
}

type key2<type T1, T2 cmp2> struct {
	f1 T1
	f2 T2
}

type Metric2<type T1, T2 cmp2> struct {
	mu sync.Mutex
	m  map[key2<T1, T2>]int
}

func (m *Metric2<T1, T2>) Add(v1 T1, v2 T2) {
	m.mu.Lock()
	defer m.mu.Unlock()
	if m.m == nil {
		m.m = make(map[key2<T1, T2>]int)
	}
	m[key{<T1, T2> v1, v2}]++
}

contract cmp3<T1, T2, T3> {
	comparable<T1>
	comparable<T2>
	comparable<T3>
}

type key3<type T1, T2, T3 cmp3> struct {
	f1 T1
	f2 T2
	f3 T3
}

type Metric3<type T1, T2, T3 cmp3> struct {
	mu sync.Mutex
	m  map[key3<T1, T2, T3>]int
}

func (m *Metric3<T1, T2, T3>) Add(v1 T1, v2 T2, v3 T3) {
	m.mu.Lock()
	defer m.mu.Unlock()
	if m.m == nil {
		m.m = make(map[key3]int)
	}
	m[key{<T1, T2, T3> v1, v2, v3}]++
}

// Repeat for the maximum number of permitted arguments.
import "metrics"

var m = metrics.Metric2{<string, int>}

func F(s string, i int) {
	m.Add(s, i) // this call is type checked at compile time
}

List transform

package list

// List is a linked list.
type List<type T> struct {
	head, tail *element<T>
}

// An element is an entry in a linked list.
type element<type T> struct {
	next *element<T>
	val  T
}

// Push pushes an element to the end of the list.
func (lst *List<T>) Push(v T) {
	if lst.tail == nil {
		lst.head = &element{<T> val: v}
		lst.tail = lst.head
	} else {
		lst.tail.next = &element{<T> val: v }
		lst.tail = lst.tail.next
	}
}

// Iterator ranges over a list.
type Iterator<type T> struct {
	next **element<T>
}

// Range returns an Iterator starting at the head of the list.
func (lst *List<T>) Range() *Iterator<T> {
	return Iterator{<T> next: &lst.head}
}

// Next advances the iterator.
// It returns whether there are more elements.
func (it *Iterator<T>) Next() bool {
	if *it.next == nil {
		return false
	}
	it.next = &(*it.next).next
	return true
}

// Val returns the value of the current element.
// The bool result reports whether the value is valid.
func (it *Iterator<T>) Val() (T, bool) {
	if *it.next == nil {
		var zero T
		return zero, false
	}
	return (*it.next).val, true
}

// Transform runs a transform function on a list returning a new list.
func Transform<type T1, T2>(lst *List<T1>, f func(T1) T2) *List<T2> {
	ret := &List{<T2>}
	it := lst.Range()
	for {
		if v, ok := it.Val(); ok {
			ret.Push(f(v))
		}
		it.Next()
	}
	return ret
}

Context

// Key is a key that can be used with Context.Value.
// Rather than calling Context.Value directly, use Key.Load.
//
// The zero value of Key is not ready for use; use NewKey.
type Key<type V> struct {
	name string
}

// NewKey returns a key used to store values of type V in a Context.
// Every Key returned is unique, even if the name is reused.
func NewKey<type V>(name string) *Key {
	return &Key{<V> name: name}
}

// WithValue returns a new context with v associated with k.
func (k *Key<V>) WithValue(parent Context, v V) Context {
	return WithValue(parent, k, v)
}

// Value loads the value associated with k from ctx and reports
//whether it was successful.
func (k *Key<V>) Value(ctx Context) (V, bool) {
	v, present := ctx.Value(k).(V)
	return v.(V), present
}

// String returns the name and expected value type.
func (k *Key<V>) String() string {
	var v V
	return fmt.Sprintf("%s(%T)", k.name, v)
}
var ServerContextKey = context.NewKey(<*Server> "http_server")

	// used as:
	ctx := ServerContextKey.WithValue(ctx, srv)
	s, present := ServerContextKey.Value(ctx)

Dot product

// Numeric is a contract that matches any numeric type.
// It would likely be in a contracts package in the standard library.
contract Numeric<T> {
	T int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr,
		float32, float64,
		complex64, complex128
}

func DotProduct<type T Numeric>(s1, s2 []T) T {
	if len(s1) != len(s2) {
		panic("DotProduct: slices of unequal length")
	}
	var r T
	for i := range s1 {
		r += s1[i] * s2[i]
	}
	return r
}

Absolute difference

// NumericAbs matches numeric types with an Abs method.
contract NumericAbs<T> {
	Numeric<T>
	T Abs() T
}

// AbsDifference computes the absolute value of the difference of
// a and b, where the absolute value is determined by the Abs method.
func AbsDifference<type T NumericAbs>(a, b T) T {
	d := a - b
	return d.Abs()
}
// OrderedNumeric matches numeric types that support the < operator.
contract OrderedNumeric<T> {
	T int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr,
		float32, float64
}

// Complex matches the two complex types, which do not have a < operator.
contract Complex<T> {
	T complex64, complex128
}

// OrderedAbs is a helper type that defines an Abs method for
// ordered numeric types.
type OrderedAbs<type T OrderedNumeric> T

func (a OrderedAbs<T>) Abs() OrderedAbs<T> {
	if a < 0 {
		return -a
	}
	return a
}

// ComplexAbs is a helper type that defines an Abs method for
// complex types.
type ComplexAbs<type T Complex> T

func (a ComplexAbs<T>) Abs() T {
	r := float64(real(a))
	i := float64(imag(a))
	d := math.Sqrt(r * r + i * i)
	return T(complex(d, 0))
}
func OrderedAbsDifference<type T OrderedNumeric>(a, b T) T {
	return T(AbsDifference(OrderedAbs(<T> a), OrderedAbs(<T> b)))
}

func ComplexAbsDifference<type T Complex>(a, b T) T {
	return T(AbsDifference(ComplexAbs(<T> a), ComplexAbs(<T> b)))
}
// This function is INVALID.
func GeneralAbsDifference<type T Numeric>(a, b T) T {
	switch a.(type) {
	case int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr,
		float32, float64:
		return OrderedAbsDifference(a, b) // INVALID
	case complex64, complex128:
		return ComplexAbsDifference(a, b) // INVALID
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment