patrickmn / go-cache

An in-memory key:value store/cache (similar to Memcached) library for Go, suitable for single-machine applications.
https://patrickmn.com/projects/go-cache/
MIT License
8.16k stars 874 forks source link

WIP: Converting to generics proof of concept #128

Closed lukemassa closed 2 years ago

lukemassa commented 4 years ago

NOTE: This is not to be merged until generics make it into mainline go, and even then care will have to be taken with versioning so clients without generics will still be able to compile.

I wanted to test out the generics proposal for go (https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-contracts.md), and I thought a good exercise would be to try to convert some code into generic code.

Below is a "working" example, which can be run like this (following instructions here: https://go.googlesource.com/go/+/refs/heads/dev.go2go/README.go2go.md)

luke@Lukes-MacBook-Air go-cache % ~/goroot/bin/go tool go2go run cache.go2
Hello world

Caveats:

  1. This is embarrassing but I couldn't figure out how to run this code directly without temporarily changing the package name to main. I tried to put it into ~/go2/src and import it into a client project, but it complained about not being able to reference private field .cache, see caveat 2. Maybe there's a different way to do it, or maybe caveat 2 has to be addressed first.
  2. I'm not sure if this is the go2go tool, but for some reason the go2 code needed to address the .cache field of Cache directly. For example, in my small client implementation at the bottom of cache.go2, if you replace c.cache.Set with the appropriate c.Set you get this compilation error:
    cache.go2:1146:2: type *Cache(string) of c does not match *cache(T) (cannot infer T)

    In general, I don't quite understand how all the methods here are able to be about cache and not Cache, I guess there's some sort of magic since cache is the only value in the struct? However it happens, it looks like that's not working in go2.

  3. I needed to define ItemMap in lieu of map[string]Item due to a limitation in complex inline types in generic go. I asked about this in the go slack (https://gophers.slack.com/archives/C88U9BFDZ/p1598134017011500) and was told that this is the only option.
  4. The runtime.SetFinalizer didn't work as is, perhaps the same issue as caveat 2, maybe some other thing, I pulled it out for now.
  5. I commented out all the Increment code; I'm not sure the best approach here. Maybe some sort of IncrementableCache, but that seems to defeat the purpose of generic code :) I wonder if there's a way to define these methods and have client code fail to compile if they try to call Increment() on a cache they set up with e.g. strings or something?
  6. I haven't touched the tests or the sharded file, other than to rename them to .go2 which is required by the go2go tool.
lukemassa commented 2 years ago

Closing in favor of #147