go language generics system

Related tags

Miscellaneous gotgo
Overview

Gotgo

This document describes the third iteration of my attempt at a reasonable implementation of generics for go based on the idea of template packages.

Quick start

You can compile gotgo by typing

./build

and you can run it on an example template file by typing

./gotgo/gotgo pkg/gotgo/slice.got int string

A complete example is in the example/ subdirectory.

cd example
./build
./example

If you want to see what a template package will look like, check out slice.got, which is a simple package exporting handy functions for slices, such as Map, Fold, Filter, Append, Cat (concat).

The got file

A template package is contained in a got file, ending with the .got extension. As you might be able to guess, "got" stands for "go template". If you call gotgo with a --package-name flag, you can generate a go file which is a member of any package you like.

The got file differs from an ordinary go file only in its package line, which will be something like

package slice(type a, type b a)

This defines a package template named "slice", with two type parameters. The first could be any type, which will be called "a", and the second type, called "b" will default to be the same as "a", if no second type parameter is provided. The default type argument is optional, and will itself default to interface{}. The default type should be either an interface type, or a type defined in terms of other template parameters, although I'm not sure whether/how to enforce this. Your got file should be able to compile with the default type!

Within this package, the types "a" and "b" will be in scope, so the slice got file might contain:

func Append(slice []a, datum a) []a {
    // first expand if needed...
    slice = slice[0:len(slice)+1]
    slice[len(slice)-1] = datum
    return slice
}

We could also have a function that uses both "a" and "b":

func Map(f func(a) b, slice []a) []b {
    out := make([]b, len(slice))
    for i,v := range slice {
        out[i] = f(v)
    }
    return out
}

Importing a got package

If you want to use the above package, you typically do so by creating an ordinary go file that has a special import statement that specifies the types desired. Currently, this is not automated, as gotgo is in rapid flux.

import intslice "./slice(int)"

func foo(x int, xs []int, ...) {
    ...
    intslice.Append(xs,x)

This import is valid go (since the language spec states that the interpretation of the import string is implementation-dependent), and is accepted by the go compiler, so long as the slice(int) package has been generated and compiled.

The package name of this templated import may be dependent on the gotgo implementation unless you use the --package-name flag when running gotgo.

Getting fancier with interface types

We can get a bit fancier in the package specification by using interfaces.

package list(type a fmt.Stringer)

import fmt "fmt"

type T struct {
    Datum a
    Next *T
}
func (l T) String() String {
    if l.Next != nil {
        return l.Datum.String() + ", " + l.Next.String()
    } else {
        return l.Datum.String()
    }
}

This isn't much different from what I've already described, but there is (will be) an additional twist that isn't shown, which is that if you make the default type an interface, then any type parameter passed to the template must satisfy that interface! This is valuable because it means that you can guarantee that you can't break the compile of any client code unless you change the template signature.

If you write a template that requires a numeric type, such as

package maxmin(type a int)

func max(x,y a) a {
    if x > y { return x }
    return y
}

then you'll need to use a numeric type as your default. The gotgo system will then enforce that this package may only be parametrized with types that are assignment-compatible3 with int (or whatever default type you choose).

How does it work?

There is a simple program called gotgo, which you pass the filepath to a .got file and a list of types. By default, gotgo outputs the go code to stdout, but if you specify -o foo.go, it will create a file named foo.go.

A zeroconf go build system will need to track down and build imported packages, and in order to work with gotgo, will need to know how to build templated packages. An sketch of a helper for such a build system is provided in the gotimports program, which (non-recursively and incorrectly) dumps some make rules that might be helpful in creating your own Makefile.

Problems solved by gotgo

  • In go, there is no way to write a generic data structure, such as a linked list. As the FAQ points out, this isn't such a problem, since go has a pretty nice stable of built-in data structures, but it is a problem, since sooner or later you'll run into a need for more complicated structures (e.g. perhaps a red-black tree), and you don't want to reimplement them for every data type you use.

  • In go, there is no way to write a generic function whose return type depends on its input, or with two arguments of the same (but variable type). This is a much more serious shortcoming than the previous one, as it means you can't even write generic functions for the existing built-in generic data structures. For example, consider the generic version of

    func Append(x int, xs []int) []int
    

    which will append the given value to the slice, expanding it if needed. This is precisely the sort of function you'd like to write only once (or twice perhaps, to treat "large" data types differently), but currently copy-and-paste is the only way to reuse this code. (And similarly for methods...)

  • Compile time penalty of templates. In C++, using templates means recompiling the template every time you use it. Using gotgo, however, templates are separately compiled, just like any other go package. So a template need be compiled once by gotgo, and then once for each type it is parametrized by, which is the minimal number of recompiles consistent with allowing the compiler to generate optimal code for each type.

  • In the latest gotgo, you can use the --package-name flag to generate a go file in a given package. This makes it possible to use generics with private data types, or in the same package that defines a data type.

You might also like...
Real-time Charging System for Telecom & ISP environments

Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Features Real-time Online/Offline Charging System (OCS). Account Balance

Cross-platform file system notifications for Go.

File system notifications for Go fsnotify utilizes golang.org/x/sys rather than syscall from the standard library. Ensure you have the latest version

FreeSWITCH Event Socket library for the Go programming language.

eventsocket FreeSWITCH Event Socket library for the Go programming language. It supports both inbound and outbound event socket connections, acting ei

Simple interface to libmagic for Go Programming Language

File Magic in Go Introduction Provides simple interface to libmagic for Go Programming Language. Table of Contents Contributing Versioning Author Copy

Go language interface to the PAPI performance API

go-papi Description go-papi provides a Go interface to PAPI, the Performance Application Programming Interface. PAPI provides convenient access to har

File system event notification library on steroids.

notify Filesystem event notification library on steroids. (under active development) Documentation godoc.org/github.com/rjeczalik/notify Installation

The Gorilla Programming Language
The Gorilla Programming Language

Gorilla Programming Language Gorilla is a tiny, dynamically typed, multi-engine programming language It has flexible syntax, a compiler, as well as an

Mobile Blogging System

Mobile Blogging System

An unified key management system to make life easier.
An unified key management system to make life easier.

Safebox An unified key management system to make life easier. The main goal of safebox is to make key backup easier with single main key to derive the

Owner
David Roundy
David Roundy
Aboriginal Generics: the future is here!

Aboriginal Generics: the future is here! Inspired by this gem of an idea (click the image to go to the original comment): Installation go get github.c

Pavel Vasilev 150 Aug 17, 2022
An implementation of standard generics APIs in Go.

generics This package shows an implementation outlook of proposed generics APIs import "changkun.de/x/generics" Related issues: golang/go#45458 golang

Changkun Ou 26 Mar 3, 2022
Go 1.18 Generics based slice package

The missing slice package A Go-generics (Go 1.18) based functional library with no side-effects that adds the following functions to a slice package:

Steven Soroka 31 Aug 24, 2022
Advent of Code 2021 solutions using Go 1.18 Generics

advent-of-code-2021 Here are my solutions for Advent of Code 2021. This year, I chose to write my solutions using Go 1.18 with generics (by building t

Glenn Lewis 4 Aug 15, 2022
Go-generic - A collection of experiments using Go Generics coming out in Go 1.18

Go Generic - experiments with Go 1.18 beta Data structures: iter.Iter[T any] - l

Matthew Hall 2 Aug 15, 2022
Generic-list-go - Go container/list but with generics

generic-list-go Go container/list but with generics. The code is based on contai

Arne Bahlo 5 May 16, 2022
Lithia is an experimental functional programming language with an implicit but strong and dynamic type system.

Lithia is an experimental functional programming language with an implicit but strong and dynamic type system. Lithia is designed around a few core concepts in mind all language features contribute to.

Valentin Knabel 6 Jun 14, 2022
Some utilities for Persian language in Go (Golang)

persian Some utilities for Persian language in Go (Golang). Installation go get github.com/mavihq/persian API .ToPersianDigits Converts all English d

هلو | آموزش زبان با بازی 65 Sep 2, 2022
:chart_with_upwards_trend: Monitors Go MemStats + System stats such as Memory, Swap and CPU and sends via UDP anywhere you want for logging etc...

Package stats Package stats allows for gathering of statistics regarding your Go application and system it is running on and sent them via UDP to a se

Go Playgound 164 Sep 27, 2022
Unit tests generator for Go programming language

GoUnit GoUnit is a commandline tool that generates tests stubs based on source function or method signature. There are plugins for Vim Emacs Atom Subl

Max Chechel 64 Sep 27, 2022