# Another implementation of \`@memoize\` which is type inference friendly & generic functions

**URL:** <https://discourse.julialang.org/t/another-implementation-of-memoize-which-is-type-inference-friendly-generic-functions/3133>\
**Category:** Package Announcements\
**Tags:** announcement, memoize\
**Created:** [April 9, 2017, 11:37pm UTC](https://discourse.julialang.org/t/another-implementation-of-memoize-which-is-type-inference-friendly-generic-functions/3133 "2017-04-09T23:37:38Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![FANG\_Colin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fang_colin/32/170_2.png) [@FANG\_Colin](https://discourse.julialang.org/u/FANG_Colin)\
**Post date:** [April 9, 2017, 11:37pm UTC](https://discourse.julialang.org/t/another-implementation-of-memoize-which-is-type-inference-friendly-generic-functions/3133/1 "2017-04-09T23:37:38Z")

</div>

I made another [Memoize.jl](https://github.com/colinfang/Memoize.jl) package for daily use of Julia.

Suggestions & criticisms are welcom.

## Overview

This package provides basic support for type inference friendly generic function memoization. It allows to customize cache key from function arguments.

- Type inference friendly
- Cache invalidation
- Each method of a generic function has its own cache
- Custom cache key
- Recursive functions

## Limitation

- Keyword arguments or default arguments are not supported.
- Require standard function definition with return type annotated.
- Parametric functions are not supported.
- Use `Dict` for cache, not `ObjectIdDict`.
- Work best with Julia v0.6 since [automatic recompilation of dependent functions](https://github.com/julialang/julia/issues/265) is fixed.

## Exposed Verbs

```julia
export @memoize, clear_cache, get_cache

```

## Usage

```julia
Pkg.clone("https://github.com/colinfang/Memoize.jl.git")

using Memoize

@memoize function fib(x::Int)::Int
   x <= 2 ? x : fib(x - 1) + fib(x - 2)
end

@memoize function fib(x::Float64, y)::Float64
   x + y
end

julia> fib(3), fib(1.0, 5)
(3, 6.0)

julia> @time fib(100)
0.000073 seconds (199 allocations: 14.166 KiB)
juila> @time fib(100)
0.000005 seconds (5 allocations: 176 bytes)

julia> get_cache(fib)
Dict{Tuple,Dict} with 2 entries:
  (Float64, Any) => Dict{Any,Float64}(Pair{Any,Float64}((1.0, 5), 6.0))
  (Int64,) => Dict{Any,Int64}(Pair{Any,Int64}(68, 117669030460994),Pair{A…

julia> clear_cache(fib)
julia> get_cache(fib)
Dict{Tuple,Dict} with 2 entries:
  (Float64, Any) => Dict{Any,Float64}()
  (Int64,) => Dict{Any,Int64}()

julia> @time fib(100)
0.000027 seconds (5 allocations: 176 bytes)

julia> Base.return_types(fib, (Int,))
1-element Array{Any,1}:
 Int64

# Assume `y` doesn't affect the result.
function Memoize.make_key(::typeof(fib), x, y)
   x
end

julia> fib(1.0, 5)
6.0
julia> fib(1.0, 6)
6.0

```

## Macro Expand

```julia
@macroexpand Memoize.@memoize function fib(x::Int)::Int
   x <= 2 ? x : fib(x - 1) + fib(x - 2)
end

quote
    let
        local #55#pt = (Int,)
        local cache = (Memoize.get!)((Memoize.Dict){Memoize.Any, Int}, Dict{Tuple,Dict}(), #55#pt)
        global fib
        function fib(x::Int)::Int
            function unmemoized()::Int
                if x <= 2
                    x
                else
                    fib(x - 1) + fib(x - 2)
                end
            end
            key = (Memoize.make_key)(fib, x)
            (Memoize.get!)(unmemoized, cache, key)
        end
    end
end

```

> **[GitHub - colinfang/Memoize.jl: Type inference friendly generic function...](https://github.com/colinfang/Memoize.jl)**
>
> Type inference friendly generic function memoization
