{"id":13713415,"url":"https://github.com/lelysses/lesser","last_synced_at":"2025-05-06T23:31:58.988Z","repository":{"id":57647551,"uuid":"409640118","full_name":"lelysses/lesser","owner":"lelysses","description":"a tiny (8 sloc without comments) library to present a uniform interface for generic natural ordering of types ","archived":false,"fork":false,"pushed_at":"2022-03-08T18:34:47.000Z","size":11,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-14T00:33:52.446Z","etag":null,"topics":["comparable","constraints","generics","go","golang","lesser","ordered"],"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/lelysses.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}},"created_at":"2021-09-23T15:09:34.000Z","updated_at":"2022-12-29T23:56:55.000Z","dependencies_parsed_at":"2022-08-25T08:21:41.632Z","dependency_job_id":null,"html_url":"https://github.com/lelysses/lesser","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelysses%2Flesser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelysses%2Flesser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelysses%2Flesser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelysses%2Flesser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lelysses","download_url":"https://codeload.github.com/lelysses/lesser/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252787531,"owners_count":21804277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["comparable","constraints","generics","go","golang","lesser","ordered"],"created_at":"2024-08-02T23:01:35.638Z","updated_at":"2025-05-06T23:31:58.311Z","avatar_url":"https://github.com/lelysses.png","language":"Go","readme":"# lesser\n\n\n## What is this?\n\n`lesser` defines a type-parameterized interface with one method, `Less`, which returns a boolean for whether the caller, of type `T`, is less than some other instance of `T`. This is blatantly stolen from [Robert Griesemer's talk at Gophercon 2020](https://www.youtube.com/watch?v=TborQFPY2IM) about the type parameters proposal. Probably more controversially, this library also defines a wrapper called `Basic` over the built-in numerical types, exposing the underlying `\u003c` operator through this `Less` method. The reasoning for this follows.\n\n## Why is this?\n\nIn the near future, [the `constraints` package](https://pkg.go.dev/golang.org/x/exp/constraints) will be in the standard library. Constraints defines an constraint called `Ordered`, which matches all types that respond to the `\u003c` operator. This is explicitly only suitable for built-in types since user-defined types (structs, etc) may not respond to operators. Conversely, however, built-ins may not respond to methods. As a consequence, any sorting function or ordered collection must specify different versions (`BasicSort` vs `Sort`, `BasicHeap` vs `Heap`, etc) for built-in types and user-defined types. This is an untenable position, and makes the type parameters proposal insufficient and unworkable for a large swathe of the problems it exists to solve (anything involving ordering).\n\nThere appear to be three different possible directions to go here:\n\n1. Every time you want to write an ordered collection or a sorting function or anything depending on natural ordering functionality, you have to copy paste it and have one copy use `Lesser` as the constraint and the other use `Ordered` as the constraint. That's not a reasonable request to make. Without this library or something like it ***you are here***. As of the end of last year this was Robert Griesemer's suggested solution, and to the best of my knowledge it still is. It's unclear what the purpose of generics is if we're still going to be forced to use code generation or copy-pasting.\n\n2. Write a library very much like this one, but which defines a series of wrappers for each of the built-in types, each of which has a `Less` method, so then when you want to use `int`s in an ordered collection you'd convert them all to `lesser.Int` first. This is scary and gives me serious Java heebie-jeebies. I do not want Go to turn into a world where we are all using special magic wrappers for every basic data type at all times or something.\n\n3. Exactly what this library is, which is the same as (2) but instead of defining the types manually, you create them at compile-time using type parameters with something like `lesser.Basic[int]` instead of `lesser.Int`. It feels far less likely this way that it'll develop into the scary situation I just described.\n\n4. [SEE ADDENDUM](#addendum) FOR IAN LANCE TAYLOR'S EPIC AND COOL ALTERNATIVE\n\nI don't know if something like this is coming to the standard library, but I'm unwilling to wait until it is. For a while it felt like the `Lesser` interface itself was likely to make it into the `constraints` library, but I'm not sure about that now. All discussion of how the hell to actually use generics has been explicitly pushed until some time after generics are released into the wild. I hate the antichrist.\n\nThis doesn't provide a Java-style `compareTo` or the like, but merely exposes a `Less` method that is fit for sorting algorithms and ordered collections. Look elsewhere for something more robust. This is a plug for a hole in the current generics implementation. This is not a \"framework\"; this is not a \"platform\".\n\n## How do I use it?\n\nWell first you'll need to get Go 1.18, which has not yet been released. Release candidate 1 was released in February, and you can install it as follows:\n\n```bash\ngo install golang.org/dl/go1.18rc1@latest\ngo1.18rc1 download\n```\n\nNow you can use the `go1.18rc1` command as an alternative to the `go` command, but with generics enabled.\n\n## Okay, but how do I *use* it?\n\nIf you want to build an ordered collection, say a binary heap, do something like this:\n\n```go\npackage foo\n\nimport \"github.com/lelysses/lesser\"\n\n// a cool heap\ntype Heap[T lesser.Interface[T]] []T\n\n// push an item onto it\nfunc (h *Heap[T]) Push(val T) {\n\t// let's pretend ...\n}\n```\n\nNow your heap works for user-defined types which expose a `Less[T] bool` method, but it also works for built-in types, although the mechanism for using built-in types is somewhat more complicated.\n\nIf you want to initialize the `Heap` we defined above for the built-in concrete type `int`, and then push the numbers 1, 2, and 3 onto it, you'd do the following:\n\n```go\nvar h Heap[lesser.Basic[int]]\nh.Push(lesser.Basic[int]{1})\nh.Push(lesser.Basic[int]{2})\nh.Push(lesser.Basic[int]{3})\n```\n\nTo get the value back out of a `Basic`, you just poll the `Val` attribute. It used to be as simple as a cast back to the correct type, but then [this issue](https://github.com/golang/go/issues/45639) happened because we can't have nice things, so `Basic` had to be changed from an alias type to a struct. The ergonomics have suffered as a consequence.\n\nIf you want to use it with your own wacky type, `Basic` doesn't apply, since your own type won't implement `Ordered`. Instead, you can just give it a `Less` method.\n\n```go\ntype Name struct {\n\tLast  string\n\tFirst string\n}\n\nfunc (this Name) Less(other Name) bool {\n\tif this.Last == other.Last {\n\t\treturn this.First \u003c other.First\n\t}\n\treturn this.Last \u003c other.Last\n}\n```\n\nAnd now you should be able to directly push some `Name`s onto a heap of `Name`s.\n\n```go\nvar h Heap[Name]\nh.Push(Name{\"Marx\", \"Karl\"})\nh.Push(Name{\"Marx\", \"Groucho\"})\n```\n\n## Okay, but really, why?\n\nI don't know if I really think this library is a good idea. I don't know how Go-y it is. The definition of \"\"\"idiomatic\"\"\" Go will probably change in the coming year, and maybe this is the way things are going. I don't know how I feel about that. More than anything I want this library to get other people thinking about how this is actually going to work, because without something like this library it's not possible to make simple ordered collections that operate on both user-defined and built-in data types.\n\n## Addendum\n\nIan Lance Taylor made (what I think is) a great suggestion [here](https://github.com/golang/go/issues/47632#issuecomment-897168431), arguing for constraining containers to `any` and passing a comparison function to the constructor. This is a good idea and subjectively feels more idiomatic than what I have done here. I think?\n","funding_links":[],"categories":["Repositories"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flelysses%2Flesser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flelysses%2Flesser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flelysses%2Flesser/lists"}