Code Generation for Functional Programming, Concurrency and Generics in Golang

goderive

Build Status Go Report Card GoDoc

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 for functions, which are not implemented, and then generates these functions for you by deriving their implementations from the input parameter types.

Examples

In the following code the deriveEqual function will be spotted as a function that was not implemented (or was previously derived) and has a prefix deriveEqual.

package main

type MyStruct struct {
	Int64     int64
	StringPtr *string
}

func (this *MyStruct) Equal(that *MyStruct) bool {
	return deriveEqual(this, that)
}

goderive will then generate the following code in a derived.gen.go file in the same package:

func deriveEqual(this, that *MyStruct) bool {
	return (this == nil && that == nil) ||
		this != nil && that != nil &&
			this.Int64 == that.Int64 &&
			((this.StringPtr == nil && that.StringPtr == nil) || 
        (this.StringPtr != nil && that.StringPtr != nil && *(this.StringPtr) == *(that.StringPtr)))
}

Recursive Examples:

Set Examples:

Functional Examples:

Concurrency Examples:

Functions

Recursive Functions:

  • Equal
    • deriveEqual(T, T) bool
    • deriveEqual(T) func(T) bool
  • Compare
    • deriveCompare(T, T) int
    • deriveCompare(T) func(T) int
  • DeepCopy
    • deriveDeepCopy(dst *T, src *T)
    • deriveDeepCopy(dst []T, src []T)
    • deriveDeepCopy(dst map[A]B, src map[A]B)
  • Clone deriveClone(T) T
  • GoString deriveGoString(T) string
  • Hash deriveHash(T) uint64

Set Functions:

  • Keys deriveKeys(map[K]V) []K
  • Sort deriveSort([]T) []T
  • Unique deriveUnique([]T) []T
  • Set deriveSet([]T) map[T]struct{}
  • Min
    • deriveMin(list []T, default T) (min T)
    • deriveMin(T, T) T
  • Max
    • deriveMax(list []T, default T) (max T)
    • deriveMax(T, T) T
  • Contains deriveContains([]T, T) bool
  • Intersect
    • deriveIntersect(a, b []T) []T
    • deriveIntersect(a, b map[T]struct{}) map[T]struct{}
  • Union
    • deriveUnion(a, b []T) []T
    • deriveUnion(a, b map[T]struct{}) map[T]struct{}

Functional Functions:

  • Fmap
    • deriveFmap(func(A) B, []A) []B
    • deriveFmap(func(rune) B, string) []B
    • deriveFmap(func(A) B, func() (A, error)) (B, error)
    • deriveFmap(func(A) (B, error), func() (A, error)) (func() (B, error), error)
    • deriveFmap(func(A), func() (A, error)) error
    • deriveFmap(func(A) (B, c, d, ...), func() (A, error)) (func() (B, c, d, ...), error)
  • Join
    • deriveJoin([][]T) []T
    • deriveJoin([]string) string
    • deriveJoin(func() (T, error), error) func() (T, error)
    • deriveJoin(func() (T, ..., error), error) func() (T, ..., error)
  • Filter deriveFilter(pred func(T) bool, []T) []T
  • All deriveAll(pred func(T) bool, []T) bool
  • Any deriveAny(pred func(T) bool, []T) bool
  • TakeWhile deriveTakeWhile(pred func(T) bool, []T) []T
  • Flip deriveFlip(f func(A, B, ...) T) func(B, A, ...) T
  • Curry deriveCurry(f func(A, B, ...) T) func(A) func(B, ...) T
  • Uncurry deriveUncurry(f func(A) func(B, ...) T) func(A, B, ...) T
  • Tuple deriveTuple(A, B, ...) func() (A, B, ...)
  • Compose
    • deriveCompose(func() (A, error), func(A) (B, error)) func() (B, error)
    • deriveCompose(func(A) (B, error), func(B) (C, error)) func(A) (C, error)
    • deriveCompose(func(A...) (B..., error), func(B...) (C..., error)) func(A...) (C..., error)
    • deriveCompose(func(A...) (B..., error), ..., func(C...) (D..., error)) func(A...) (D..., error)
  • Mem
    • deriveMem(func(A...) (B...)) func(A...) (B...)
  • Traverse
    • deriveTraverse(func(A) (B, error), []A) ([]B, error)
  • ToError
    • deriveToError(error, func(A...) (B..., bool)) func(A...) (B..., error)
    • deriveToError(error, func() bool) func() error

Concurrency Functions:

  • Fmap
    • deriveFmap(func(A) B, <-chan A) <-chan B
  • Join
    • deriveJoin(<-chan <-chan T) <-chan T
    • deriveJoin(chan <-chan T) <-chan T
    • deriveJoin([]<-chan T) <-chan T
    • deriveJoin([]chan T) <-chan T
    • deriveJoin(chan T, chan T, ...) <-chan T
  • Pipeline
    • derivePipeline(func(A) <-chan B, func(B) <-chan C) func(A) <-chan C
  • Do
    • deriveDo(func() (A, error), func (B, error)) (A, B, error)
  • Dup
    • deriveDup(c <-chan T) (c1, c2 <-chan T)

When goderive walks over your code it is looking for a function that:

  • was not implemented (or was previously derived) and
  • has a predefined prefix.

Functions which have been previously derived will be regenerated to keep them up to date with the latest modifications to your types. This keeps these functions, which are truly mundane to write, maintainable.

For example when someone in your team adds a new field to a struct and forgets to update the CopyTo method. This problem is solved by goderive, by generating generated functions given the new types.

Function prefixes are by default deriveCamelCaseFunctionName, for example deriveEqual. These are customizable using command line flags.

You can derive functions for different types by using different suffixes with the same prefix. For example, if you wish to derive Equal for types MyStruct and MySecondStruct, name the functions deriveEqualMyStruct and deriveEqualMySecondStruct and goderive will derive both.

Let goderive edit your function names in your source code, by enabling autoname and dedup using the command line flags. These flags respectively make sure that your functions have unique names and that you don't generate multiple functions that do the same thing.

How to run

goderive can be run from the command line:

goderive ./...

, using the same path semantics as the go tool.

You can also run goderive using go generate

And you can customize specific function prefixes

Or you can customize all function prefixes

You can let goderive rename your functions using the -autoname and -dedup flags. If these flags are not used, goderive will not touch your code and rather return an error.

Customization

The derive package allows you to create your own code generator plugins, see all the current plugins for examples.

You can also create your own vanity binary. Including your own generators and/or customization of function prefixes, etc. This should be easy to figure out by looking at main.go

Inspired By

Users

These projects use goderive:

Please let us know if you are using goderive by opening an issue or a pull request that adds your project to the list.

Mentioned

Please let us know if you mention goderive in a blog post, talk or go experience report, so that we can add a link to our list.

Owner
Walter Schulze
Pair programmer with an interest in language design.
Walter Schulze
Comments
  • +toerror

    +toerror

    Hi! it's been a while since we talked about "BoolToError" from the Issue. It's my first pull request to any repository ever, so hope u understand if there's any clumsy mistake πŸ˜… Also I don't know how to handle correctly that the import path in main.go being generated pointing to my forked go package "github.com/ingun37/goderive/plugin/toerror" not "github.com/awalterschulze/goderive/plugin/toerror", so I hope you can help me on that. I'll be waiting for your feedback thank you

  • generate doc comments

    generate doc comments

    It would be nice to generate doc comments for the generated functions, so that even someone with no knowledge of goderive can immediately see what the contract of the functions is.

  • applicative do

    applicative do

    http://simonmar.github.io/bib/papers/applicativedo.pdf

    func deriveDo(f func() (A, error), g func() (B, error)) (func() (A, B), error) {
        var a A
        errChan := make(chan error)
        go func() {
             var err error
             a, err = f()
             errChan <- err
        }()
        var b B
        go func() {
             var err error
             b, err = g()
             errChan <- err
        }()
        var reterr error
        for i := 0; i < 2; i++ {
            err := <- errChan
            if err != nil {
                if  reterr == nil {
                   reterr = err
                }
            }
        }
        return func() (A, B) { return a, b }, reterr
    }
    
  • add support for go modules

    add support for go modules

    Hi. Thank you for making this program. I love goderive. I always use this for all project. I want to contribute and I found that it use deprecated govendor. so I change some files to support go modules and it success tests (make travis on go version 1.16). Please review this pull request.

  • Zero value for bool is false

    Zero value for bool is false

    Zero value for bool should be false

    https://tour.golang.org/basics/12

    I had an error from a generated deriveComposeFooBar because the final function returned (bool, error) and the derived fn was returning 0, err.

    Here is example code that will fail without the fix.

    func foo() (string, error) {
    	return "", fmt.Errorf("somethings wrong")
    }
    
    func bar(string) (bool, error) {
    	return true, nil
    }
    
    cat, err := deriveComposeFooBar(
    	foo,
    	bar,
    )()
    

    it generates:

    func deriveComposeFooBar(f0 func() (string, error), f1 func(string) (bool, error)) func() (bool, error) {
    	return func() (bool, error) {
    		v_1_0, err0 := f0()
    		if err0 != nil {
    			return 0, err0
    		}
    		v_2_0, err1 := f1(v_1_0)
    		if err1 != nil {
    			return 0, err1
    		}
    		return v_2_0, nil
    	}
    }
    

    when what we really should have is:

    func deriveComposeFooBar(f0 func() (string, error), f1 func(string) (bool, error)) func() (bool, error) {
    	return func() (bool, error) {
    		v_1_0, err0 := f0()
    		if err0 != nil {
    			return false, err0
    		}
    		v_2_0, err1 := f1(v_1_0)
    		if err1 != nil {
    			return false, err1
    		}
    		return v_2_0, nil
    	}
    }
    

    I couldn't get the project to build so I wasn't sure how to add a test, so hopefully you can go from what I have here to complete the fix.

    PS. I really like the project!

  • deriveEqual: Use Equal() if it is defined on T

    deriveEqual: Use Equal() if it is defined on T

    I would like to generate deriveEqual for the following type hierarchy:

    type Foo struct {
        Field Bar
    }
    
    func (this *Foo) Equal(that *Foo) bool {
        return deriveEqual(this, that)
    }
    
    type Bar map[string]interface{}
    

    Now, as it is not possible to derive an Equal for an interface{} this fails. However, I would like to implement func (Bar) Equal(other Bar) bool {} myself and have deriveEqual notice that and call it instead.

    That way I can take responsibility for the fact that I end up calling reflect.DeepEqual() or implementing custom Equal logic lower down my type hierarchy while still benefiting from all the lovely code generation for the rest of it.

  • suggestion: Make functions that returns secondary bool composable

    suggestion: Make functions that returns secondary bool composable

    Hello I think it would be useful if I can compose functions that returns secondary bool. Because sometimes I expect a map has a specific key, or an interface to be convertible into a type, or many other cases that we can consider it as error when false is returned from such functions. Heres some code I actually use to make it composable with deriveCompose. First one expects the given key to be present in the given map otherwise returns error. Second one expects the given interface to be convertible into string otherwise returns error. Third one is for more general purposes. It only lifts bool to error.

    func expectKey(m map[string]interface{}, k string) (interface{}, error) {
    	if v, ex := m[k]; ex {
    		return v, nil
    	} else {
    		return nil, fmt.Errorf("key %s not exists in map %v", k, m)
    	}
    }
    func expectToBeString(i interface{}) (string, error) {
    	if s, success := i.(string); success {
    		return s, nil
    	} else {
    		return "", fmt.Errorf("conversion to string fail %v", i)
    	}
    }
    func expectTrue(i interface{}, b bool) (interface{}, error) {
    	if b {
    		return i, nil
    	} else {
    		return nil, fmt.Errorf("...")
    	}
    }
    

    I guess the syntax could be like deriveExpectKey(map[A]B, A) (B,error) deriveExpectConversion(interface{}) (A, error) deriveExpectTrue(A, bool) (A, error) thank you.

  • function with blank identifier

    function with blank identifier

    Given the following test code

    func TestCurryWithBlankIdentifier(t *testing.T) {
    	f := func(a string, _ bool, c int) string {
    		return fmt.Sprintf("%s%v%d", a, true, c)
    	}
    	curried := deriveCurryWithBlackIdentifier(f)
    	want := `1atrue`
    	got := curried("a")(false, 1)
    	if got != want {
    		t.Fatalf("got %s != want %s", got, want)
    	}
    }
    

    goderive generates the following code

    // deriveCurryWithBlackIdentifier returns a function that has one parameter, which corresponds to the input functions first parameter, and a result that is a function, which takes the rest of the parameters as input and finally returns the original input function's results.
    func deriveCurryWithBlackIdentifier(f func(a string, _ bool, c int) string) func(a string) func(_ bool, c int) string {
    	return func(a string) func(_ bool, c int) string {
    		return func(_ bool, c int) string {
    			return f(a, _, c)
    		}
    	}
    }
    

    It has compilation error.

    ./derived.gen.go:4430:12: cannot use _ as value
    

    I think these plugins have this issue.

    • curry
    • uncurry
    • apply
  • fix for issue #60

    fix for issue #60

    Fixes #60

    deriveSorted uses Strings, Float64s and Ints functions of sort package only if type of the slice element is not aliased.

    There is another issue in #60. the author provided some test code.

    type stringalias string
    
    func TestSortedMapKeysTypeAliasKey(t *testing.T) {
        var m map[stringalias]string
        m = random(m).(map[stringalias]string)
        keys := deriveSortedAlias(deriveKeysForMapAliasToString(m))
    

    deriveSortedAlias is not generated.

    I have found that deriveSortedAlias never generated if the function's arg is the return value of any generated goderive function.

    the following test code passes without any issue.

    type stringalias string
    
    func TestSortedMapKeysTypeAliasKey(t *testing.T) {
        keys := deriveSortedAlias([]stringalias{"a", "b"})
    

    After some testing, I have finally found that if type alias is defined in a normal go file, there is no issue at all.

    so, I move the type definitions in test/normal/*_test.go files to new types.go file.

  • Using package name instead of folder name

    Using package name instead of folder name

    First of all: goderive is a really cool tool, thanks for your work ;)

    I have the problem that I use deriveKeysString where the argument is of type map[string][]*event.Sensor and is imported via import "github.com/XXX/libs.event/proto/src/go".

    The name of the package "github.com/XXX/libs.event/proto/src/go" is event (which works fine in the rest of my code) but goderive uses a named import with the folder as name, resulting in the following code:

    import (
    	go "github.com/XXX/libs.event/proto/src/go"
    )
    
    func deriveKeysString(m map[string][]*go.Sensor) []string {
    	keys := make([]string, 0, len(m))
    	for key := range m {
    		keys = append(keys, key)
    	}
    	return keys
    }
    

    This obviously won't compile since go is reserved keyword.

    Is it possible to force goderive to use the package name instead of the folder name? (I know I can rename the folder, but this breaks the naming scheme as there also are folders named java or cpp

    (as a workaround I use sed to change go to event)

  • Function names when deriving for multiple types are not descriptive

    Function names when deriving for multiple types are not descriptive

    I am interested in using goderive for https://github.com/twpayne/go-geom which exports multiple distinct types.

    Some packages may wish to derive functions for multiple types, for example:

    package main
    
    type MyFirstStruct struct {
    	Int64 int64
    }
    
    func (this *MyFirstStruct) Equal(that *MyFirstStruct) bool {
    	return deriveEqual(this, that)
    }
    
    type MySecondStruct struct {
    	StringPtr *string
    }
    
    func (this *MySecondStruct) Equal(that *MySecondStruct) bool {
    	return deriveEqual(this, that)
    }
    

    In this case, there is an obvious conflict: deriveEqual cannot be overloaded to support both types.

    Running goderive -autoname resolves this conflict:

    $ goderive -autoname .
    changing function call name from deriveEqual to deriveEqual_
    

    The function names derivedEqual and derivedEqual_ are not particularly descriptive and easily misread or mis-typed. Instead they should include the name of the type, e.g. deriveEqual_MyFirstStruct and deriveEqual_MySecondStruct.

  • Create plugin for DeepCoyp for nested ptr recursion, that can copy cycles

    Create plugin for DeepCoyp for nested ptr recursion, that can copy cycles

    type A struct {
    	B *B
    }
    
    type B struct {
    	A *A
    }
    
    func (a *A) Clone() *A {
    	a1 := &A{B: &B{}}
    	a1.B.A = a1
    
    	tp := &A{}
    	deriveDeepCopyA(tp, a1)
    	return tp
    }
    
  • Add support for time.Time and any type with private fields for DeepCopy?

    Add support for time.Time and any type with private fields for DeepCopy?

    Like the title reads. When generating a struct containing a time.Time field I get this use of un-exported, e.g. time.zone:

    func deriveDeepCopy_15(dst, src *time.Location) {
    	src_v := reflect.Indirect(reflect.ValueOf(src))
    	dst_v := reflect.Indirect(reflect.ValueOf(dst))
    	*(*string)(unsafe.Pointer(dst_v.FieldByName("name").UnsafeAddr())) = *(*string)(unsafe.Pointer(src_v.FieldByName("name").UnsafeAddr()))
    	if *(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr())) == nil {
    		*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())) = nil
    	} else {
    		if *(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())) != nil {
    			if len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr()))) > len(*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr()))) {
    				if cap(*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr()))) >= len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr()))) {
    					*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())) = (*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())))[:len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr())))]
    				} else {
    					*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())) = make([]time.zone, len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr()))))
    				}
    			} else if len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr()))) < len(*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr()))) {
    				*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())) = (*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())))[:len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr())))]
    			}
    		} else {
    			*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())) = make([]time.zone, len(*(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr()))))
    		}
    		copy(*(*[]time.zone)(unsafe.Pointer(dst_v.FieldByName("zone").UnsafeAddr())), *(*[]time.zone)(unsafe.Pointer(src_v.FieldByName("zone").UnsafeAddr())))
    	}
    	if *(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr())) == nil {
    		*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())) = nil
    	} else {
    		if *(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())) != nil {
    			if len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr()))) > len(*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr()))) {
    				if cap(*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr()))) >= len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr()))) {
    					*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())) = (*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())))[:len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr())))]
    				} else {
    					*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())) = make([]time.zoneTrans, len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr()))))
    				}
    			} else if len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr()))) < len(*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr()))) {
    				*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())) = (*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())))[:len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr())))]
    			}
    		} else {
    			*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())) = make([]time.zoneTrans, len(*(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr()))))
    		}
    		copy(*(*[]time.zoneTrans)(unsafe.Pointer(dst_v.FieldByName("tx").UnsafeAddr())), *(*[]time.zoneTrans)(unsafe.Pointer(src_v.FieldByName("tx").UnsafeAddr())))
    	}
    	*(*int64)(unsafe.Pointer(dst_v.FieldByName("cacheStart").UnsafeAddr())) = *(*int64)(unsafe.Pointer(src_v.FieldByName("cacheStart").UnsafeAddr()))
    	*(*int64)(unsafe.Pointer(dst_v.FieldByName("cacheEnd").UnsafeAddr())) = *(*int64)(unsafe.Pointer(src_v.FieldByName("cacheEnd").UnsafeAddr()))
    	if *(**time.zone)(unsafe.Pointer(src_v.FieldByName("cacheZone").UnsafeAddr())) == nil {
    		*(**time.zone)(unsafe.Pointer(dst_v.FieldByName("cacheZone").UnsafeAddr())) = nil
    	} else {
    		*(**time.zone)(unsafe.Pointer(dst_v.FieldByName("cacheZone").UnsafeAddr())) = new(time.zone)
    		**(**time.zone)(unsafe.Pointer(dst_v.FieldByName("cacheZone").UnsafeAddr())) = **(**time.zone)(unsafe.Pointer(src_v.FieldByName("cacheZone").UnsafeAddr()))
    	}
    }
    
  • Feature request: deriveFmap for functor compositions

    Feature request: deriveFmap for functor compositions

    Just a thought: seems it would be feasible to derive fmap for functors that are the composition of two or more functors, such as deriveFmap(func(A) B, func() ([A], error)) ([B], error)

  • Provide a way to add build comment lines in generated files

    Provide a way to add build comment lines in generated files

    Hi,

    thank you for this great project!

    I need some generated files to be compiled only on Linux. Usually I'd drop a "// +build linux" line on top of such file. Obviously I don't want to manually add that on generated files. I could automate that with a Makefile, but Makefiles come with their own problem when you want to support both Linux and Macos (different make command, different sed command).

    So maybe goderive could copy build comment lines from the source file to the generated file, when such comment line is present ? Or another more clever mechanism you could imagine...

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
A faster RWLock primitive in Go, 2-3 times faster than RWMutex. A Go implementation of concurrency control algorithm in paper

Go Left Right Concurrency A Go implementation of the left-right concurrency control algorithm in paper <Left-Right - A Concurrency Control Technique w

Jan 6, 2023
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
Go-generics-simple-doubly-linked-list - A simple doubly linked list implemented using generics (Golang)

Welcome to Go-Generics-Simple-Doubly-Linked-List! Hi, This repository contains a

Jun 30, 2022
Utilities and immutable collections for functional programming in Golang

Utilities and immutable collections for functional programming in Golang. This is an experimental library to play with the new Generics Feature in Go 1.18.

Sep 1, 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
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
efaceconv - Code generation tool for high performance conversion from interface{} to immutable type without allocations.

efaceconv High performance conversion from interface{} to immutable types without additional allocations This is tool for go generate and common lib (

May 14, 2022
Type-driven code generation for Go

What’s this? gen is a code-generation tool for Go. It’s intended to offer generics-like functionality on your types. Out of the box, it offers offers

Jan 4, 2023
Code generation tools for Go.

interfaces Code generation tools for Go's interfaces. Tools available in this repository: cmd/interfacer cmd/structer cmd/interfacer Generates an inte

Dec 23, 2022
Helpfully Functional Go like underscore.js

/\ \ __ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ __ __

Dec 22, 2022
Make Go functional with dogs
Make Go functional with dogs

dogs Make Go functional with dogs Caution This is a highly-experimental package. Any changes will be made in a backward-incompatible manner. This pack

Jan 4, 2023
Helper library for full uint64 randomness, pool backed for efficient concurrency

fastrand64-go Helper library for full uint64 randomness, pool backed for efficient concurrency Inspired by https://github.com/valyala/fastrand which i

Dec 5, 2021
Concurrency in Go video course with in depth explanations & examples
Concurrency  in Go video course with in depth explanations & examples

Concurrency in Go Summary Coding Examples Introduction to Concurrency Go Routines Channels Select Concurrency Patterns Atomics Wait Groups - sync.Wait

Dec 26, 2022
Golang 1.18+ Generics implementation of Set methods

Golang Generics: Set A golang 1.18+ implementation of Set using Go generics Installation $ go get -u github.com/chrispappas/golang-generics-set Quick

Oct 26, 2022
Higher Order Functions using Golang Generics (Hack Days 2022)

hoff: Higher Order Functions (and Friends) Golang 1.18+ implementations of common methods/data structures using Go Generics Requirements Go 1.18 or ne

Jan 4, 2023
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
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