ProductPromotion
Logo

Go.Lang

made by https://0x3d.site

GitHub - cheekybits/genny: Elegant generics for Go
Elegant generics for Go. Contribute to cheekybits/genny development by creating an account on GitHub.
Visit Site

GitHub - cheekybits/genny: Elegant generics for Go

GitHub - cheekybits/genny: Elegant generics for Go

genny - Generics for Go

Build Status GoDoc

Install:

go get github.com/cheekybits/genny

=====

(pron. Jenny) by Mat Ryer (@matryer) and Tyler Bunnell (@TylerJBunnell).

Until the Go core team include support for generics in Go, genny is a code-generation generics solution. It allows you write normal buildable and testable Go code which, when processed by the genny gen tool, will replace the generics with specific types.

  • Generic code is valid Go code
  • Generic code compiles and can be tested
  • Use stdin and stdout or specify in and out files
  • Supports Go 1.4's go generate
  • Multiple specific types will generate every permutation
  • Use BUILTINS and NUMBERS wildtype to generate specific code for all built-in (and number) Go types
  • Function names and comments also get updated

Library

We have started building a library of common things, and you can use genny get to generate the specific versions you need.

For example: genny get maps/concurrentmap.go "KeyType=BUILTINS ValueType=BUILTINS" will print out generated code for all types for a concurrent map. Any file in the library may be generated locally in this way using all the same options given to genny gen.

Usage

genny [{flags}] gen "{types}"

gen - generates type specific code from generic code.
get <package/file> - fetch a generic template from the online library and gen it.

{flags}  - (optional) Command line flags (see below)
{types}  - (required) Specific types for each generic type in the source
{types} format:  {generic}={specific}[,another][ {generic2}={specific2}]

Examples:
  Generic=Specific
  Generic1=Specific1 Generic2=Specific2
  Generic1=Specific1,Specific2 Generic2=Specific3,Specific4

Flags:
  -in="": file to parse instead of stdin
  -out="": file to save output to instead of stdout
  -pkg="": package name for generated files
  -tag="": build tag that is stripped from output
  • Comma separated type lists will generate code for each type

Flags

  • -in - specify the input file (rather than using stdin)
  • -out - specify the output file (rather than using stdout)

go generate

To use Go 1.4's go generate capability, insert the following comment in your source code file:

//go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "KeyType=string,int ValueType=string,int"
  • Start the line with //go:generate
  • Use the -in and -out flags to specify the files to work on
  • Use the genny command as usual after the flags

Now, running go generate (in a shell) for the package will cause the generic versions of the files to be generated.

  • The output file will be overwritten, so it's safe to call go generate many times
  • Use $GOFILE to refer to the current file
  • The //go:generate line will be removed from the output

To see a real example of how to use genny with go generate, look in the example/go-generate directory.

How it works

Define your generic types using the special generic.Type placeholder type:

type KeyType generic.Type
type ValueType generic.Type
  • You can use as many as you like
  • Give them meaningful names

Then write the generic code referencing the types as your normally would:

func SetValueTypeForKeyType(key KeyType, value ValueType) { /* ... */ }
  • Generic type names will also be replaced in comments and function names (see Real example below)

Since generic.Type is a real Go type, your code will compile, and you can even write unit tests against your generic code.

Generating specific versions

Pass the file through the genny gen tool with the specific types as the argument:

cat generic.go | genny gen "KeyType=string ValueType=interface{}"

The output will be the complete Go source file with the generic types replaced with the types specified in the arguments.

Real example

Given this generic Go code which compiles and is tested:

package queue

import "github.com/cheekybits/genny/generic"

// NOTE: this is how easy it is to define a generic type
type Something generic.Type

// SomethingQueue is a queue of Somethings.
type SomethingQueue struct {
  items []Something
}

func NewSomethingQueue() *SomethingQueue {
  return &SomethingQueue{items: make([]Something, 0)}
}
func (q *SomethingQueue) Push(item Something) {
  q.items = append(q.items, item)
}
func (q *SomethingQueue) Pop() Something {
  item := q.items[0]
  q.items = q.items[1:]
  return item
}

When genny gen is invoked like this:

cat source.go | genny gen "Something=string"

It outputs:

// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny

package queue

// StringQueue is a queue of Strings.
type StringQueue struct {
  items []string
}

func NewStringQueue() *StringQueue {
  return &StringQueue{items: make([]string, 0)}
}
func (q *StringQueue) Push(item string) {
  q.items = append(q.items, item)
}
func (q *StringQueue) Pop() string {
  item := q.items[0]
  q.items = q.items[1:]
  return item
}

To get a something for every built-in Go type plus one of your own types, you could run:

cat source.go | genny gen "Something=BUILTINS,*MyType"

More examples

Check out the test code files for more real examples.

Writing test code

Once you have defined a generic type with some code worth testing:

package slice

import (
  "log"
  "reflect"

  "github.com/stretchr/gogen/generic"
)

type MyType generic.Type

func EnsureMyTypeSlice(objectOrSlice interface{}) []MyType {
  log.Printf("%v", reflect.TypeOf(objectOrSlice))
  switch obj := objectOrSlice.(type) {
  case []MyType:
    log.Println("  returning it untouched")
    return obj
  case MyType:
    log.Println("  wrapping in slice")
    return []MyType{obj}
  default:
    panic("ensure slice needs MyType or []MyType")
  }
}

You can treat it like any normal Go type in your test code:

func TestEnsureMyTypeSlice(t *testing.T) {

  myType := new(MyType)
  slice := EnsureMyTypeSlice(myType)
  if assert.NotNil(t, slice) {
    assert.Equal(t, slice[0], myType)
  }

  slice = EnsureMyTypeSlice(slice)
  log.Printf("%#v", slice[0])
  if assert.NotNil(t, slice) {
    assert.Equal(t, slice[0], myType)
  }

}

Understanding what generic.Type is

Because generic.Type is an empty interface type (literally interface{}) every other type will be considered to be a generic.Type if you are switching on the type of an object. Of course, once the specific versions are generated, this issue goes away but it's worth knowing when you are writing your tests against generic code.

Contributions

Articles
to learn more about the golang concepts.

Resources
which are currently available to browse on.

mail [email protected] to add your project or resources here ๐Ÿ”ฅ.

FAQ's
to know more about the topic.

mail [email protected] to add your project or resources here ๐Ÿ”ฅ.

Queries
or most google FAQ's about GoLang.

mail [email protected] to add more queries here ๐Ÿ”.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory