{"id":13836830,"url":"https://github.com/taylorchu/generic","last_synced_at":"2026-01-18T06:17:43.209Z","repository":{"id":143271960,"uuid":"59611078","full_name":"taylorchu/generic","owner":"taylorchu","description":"A code generation tool to enable generics in go","archived":false,"fork":false,"pushed_at":"2017-12-04T05:12:51.000Z","size":65,"stargazers_count":163,"open_issues_count":4,"forks_count":7,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-07-10T21:27:05.865Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/taylorchu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-05-24T21:49:56.000Z","updated_at":"2025-05-05T01:47:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"8b958f18-13d0-4476-9306-ee587aa310bb","html_url":"https://github.com/taylorchu/generic","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/taylorchu/generic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorchu%2Fgeneric","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorchu%2Fgeneric/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorchu%2Fgeneric/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorchu%2Fgeneric/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taylorchu","download_url":"https://codeload.github.com/taylorchu/generic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorchu%2Fgeneric/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28531993,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T15:00:55.312Z","updated_at":"2026-01-18T06:17:43.183Z","avatar_url":"https://github.com/taylorchu.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Generic, a code generation tool to enable generics in go\n\n[![CircleCI](https://circleci.com/gh/taylorchu/generic.svg?style=svg)](https://circleci.com/gh/taylorchu/generic)\n\n__v2__ `go get -u github.com/taylorchu/generic/cmd/gorewrite`\n\n__v1__ _(deprecated)_ `go get -u github.com/taylorchu/generic/cmd/generic`\n\nThis is an experiment to enable generics with code generation in the most elegant way.\n\n\u003cimg src=\"http://i.imgur.com/X07XInF.png\" width=\"300\"\u003e\n\n## Example\n\nYou can create a package like this. Note that `Type` and `TypeQueue` are type placeholders.\n\n```go\npackage queue\n\ntype Type string\n\n// TypeQueue represents a queue of Type types.\ntype TypeQueue struct {\n\titems []Type\n}\n\n// New makes a new empty Type queue.\nfunc New() *TypeQueue {\n\treturn \u0026TypeQueue{items: make([]Type, 0)}\n}\n\n// Enq adds an item to the queue.\nfunc (q *TypeQueue) Enq(obj Type) *TypeQueue {\n\tq.items = append(q.items, obj)\n\treturn q\n}\n\n// Deq removes and returns the next item in the queue.\nfunc (q *TypeQueue) Deq() Type {\n\tobj := q.items[0]\n\tq.items = q.items[1:]\n\treturn obj\n}\n\n// Len gets the current number of Type items in the queue.\nfunc (q *TypeQueue) Len() int {\n\treturn len(q.items)\n}\n```\n\nAdd rewrite config in `GoRewrite.yaml`, and run `gorewrite`:\n\n```yaml\nspec:\n  - name: result\n    import: github.com/YourName/queue\n    typeMap:\n      Type:\n        expr: int64\n      TypeQueue:\n        expr: FIFO\n```\n\nThe output is saved to `$PWD/result/`.\n\n```go\npackage result\n\ntype FIFO struct {\n\titems []int64\n}\n\nfunc New() *FIFO {\n\treturn \u0026FIFO{items: make([]int64, 0)}\n}\n\nfunc (q *FIFO) Enq(obj int64) *FIFO {\n\tq.items = append(q.items, obj)\n\treturn q\n}\n\nfunc (q *FIFO) Deq() int64 {\n\tobj := q.items[0]\n\tq.items = q.items[1:]\n\treturn obj\n}\n\nfunc (q *FIFO) Len() int {\n\treturn len(q.items)\n}\n```\n\n## `GoRewrite.yaml` reference\n\nThe yaml config contains multiple rewrite specs.\n\n- `spec[*].name` (string): unique identifier the spec. It is a path to the output, and used as package name if the spec is not local.\n- `spec[*].local` (bool): true if the spec is local. If the spec is local, the output will be saved in `$PWD` instead of a new package relative to `$PWD`.\n  All the top level identifiers and the filename will also be prefixed with `spec[*].name` to avoid conflicts.\n- `spec[*].typeMap` (map): type mappings used to replace placeholders. The key is type placeholder. The value `expr` can be any go expression.\n  If `expr` references any other packages, all those packages need to be listed in `import`.\n\n```yaml\nspec:\n  - name: result\n    local: true\n    import: github.com/YourName/queue\n    typeMap:\n      Type:\n        expr: test.Box\n        import:\n          - github/YourName/test\n```\n\n## FAQ\n\n### What are the existing approaches to generics in go?\n\nThis [post](https://appliedgo.net/generics/) summarizes the current state in go to _\"simulate\"_ generics. \n\n### Why are type-checking and ast-based replacement important?\n\nType-checking and ast-based replacement ensure that the tool doesn't generate invalid code even you or the tool make mistakes, and rewrites identifiers in cases that it shouldn't.\n\n### Why is type placeholder designed this way?\n\n`type TypeXXX int32`\n\n - It provides a namespace for replaceable types.\n - Knowing that this type might be replaced, package creator can still write go-testable code with a concrete type.\n - It can express meaning. For example, `TypeQueue` shows that it is a queue.\n\n### Why does this tool rewrite at package-level instead of file-level?\n\n - This tool tries NOT to apply any restriction for package creator except that any TypeXXX might be rewritten. Package creator has full flexibility to write normal go code.\n - It is common to distribute go code at package-level.\n\n### Why does it remove all the comments?\n\nComments in go ast are [free-floating](https://github.com/golang/go/issues/20744), so they are hard to work with. Hopefully it is fixed in the near future.\n\n### How do I make sure the rewritten package is not import-able?\n\nThe spec name should start with `internal/`. For example, `internal/queue`.\n\n\u003e When the go command sees an import of a package with internal in its path, it verifies that the package doing the import is within the tree rooted at the parent of the internal directory. For example, a package .../a/b/c/internal/d/e/f can be imported only by code in the directory tree rooted at .../a/b/c. It cannot be imported by code in .../a/b/g or in any other repository.\n\nSee [Internal packages](https://golang.org/doc/go1.4#internalpackages).\n\n### How do I determine spec name?\n\nSpec name is essentially go package path, and the base name of this package path is a package name.\n\n\u003e Good package names are short and clear. They are lower case, with no under_scores or mixedCaps.\n\nSee [Package names](https://blog.golang.org/package-names).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaylorchu%2Fgeneric","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaylorchu%2Fgeneric","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaylorchu%2Fgeneric/lists"}