marius311 / Memoization.jl

Easily and efficiently memoize any function, closure, or callable object in Julia.
MIT License
99 stars 2 forks source link

Public/documented API to get cache contents #26

Open Socob opened 1 year ago

Socob commented 1 year ago

It would be nice to have a clear way to get a function’s cache. I see there are functions get_cache(), get_caches(), and find_caches(),

https://github.com/marius311/Memoization.jl/blob/7d183e2594b65effe98f75d564dbbd59cd881cf9/src/Memoization.jl#L30

https://github.com/marius311/Memoization.jl/blob/7d183e2594b65effe98f75d564dbbd59cd881cf9/src/Memoization.jl#L50

https://github.com/marius311/Memoization.jl/blob/7d183e2594b65effe98f75d564dbbd59cd881cf9/src/Memoization.jl#L81

but it’s not clear if they’re part of a public API, how to use them, or how they differ. The thing I’d use it for would be a to write the cache to disk (in some sense a workaround for #4), but I’m sure there are other uses.

marius311 commented 1 year ago

Thanks, yea I should document this. find_caches should be what you want. If you can double check it gives expected results I'd be curious to know.

Socob commented 1 year ago

@marius311 find_caches does seem to have the relevant data. The interface is a bit wonky though, because it returns an IdDict with the passed argument as key:

julia> @memoize f(x) = x^3
f (generic function with 1 method)

julia> f(111)
1367631

julia> f(222)
10941048

julia> Memoization.find_caches(f)
IdDict{Any, Any} with 1 entry:
  f => IdDict{Any, Any}(((222,), ())=>10941048, ((111,), ())=>1367631)

julia> Memoization.find_caches(f)[f]
IdDict{Any, Any} with 2 entries:
  ((222,), ()) => 10941048
  ((111,), ()) => 1367631

I’m not sure if this IdDict can ever have more than one entry (I guess this has to do with whether something is statically memoizable, and I don’t really know under what conditions that goes one way or the other). If not, it’d make sense to get rid of this extra indirection in a user-facing function, so you don’t have to write find_caches(f)[f].

marius311 commented 1 year ago

Thanks for checking, yea the reason it returns that is because for memoizing callables/closures each instance gets its own entry, like:

julia> struct Foo x end

julia> @memoize (f::Foo)() = f.x

julia> Foo(1)()
1

julia> Foo(2)()
2

julia> Memoization.find_caches(Foo)
IdDict{Any, Any} with 2 entries:
  Foo(2) => IdDict{Any, Any}(((), ())=>2)
  Foo(1) => IdDict{Any, Any}(((), ())=>1)

User-facing should definitely have a version that returns the single cache (if there is only one). Will try to get to this soon.