Caching function values

Hello,

This may be silly. I would like to understand whether this is a viable design pattern in Julia. I want to define a new type GraphPoint <: AbstractArray that joins together a point and a function value at that point (like a cache, to avoid re-evaluating a function if you will). I would do it pretty much like this:

immutable GraphPoint <: AbstractArray
  x::AbstractArray
  fx::Real
end

The idea is to have a function that uses this information to avoid computations, as in

function myFun(point::GraphPoint)
  return x.fx
end

function myFun(x::AbstractArray)
  # compute something with x
  return something
end

GraphPoint objects are created somewhere. It’s not relevant by whom or when. The point is, I would like to naturally extend all other functions defined on AbstractArray to my new type GraphPoint, by simply redirecting them to the x field of the structure. Say, I would like to do matrix-vector products with A::AbstractMatrix and an object point::GraphPoint by doing A*point.x.

Is there a way to naturally extend all functions defined on AbstractArrat to my new type GraphPoint in this sense?

Thank you.

1 Like

This is called “memoization.” If it helps, there’s already a package: https://github.com/simonster/Memoize.jl.

5 Likes

Wow, that’s really interesting, thank you. I will definitely look into it. The reason why I was thinking of a structure like the one I described, is that in my case the value of the function may be obtained somewhere else than by calling the function itself: in that instant, I would like to store such value along with the point.

It is possible though that I could combine memoization into my scenario, to obtain what I need.

Thank you again!

Sure, if you’ll need that value in many places, it’s entirely reasonable to carry it around. Good luck!

Not that I know of, but there are various delegation macros floating around that have a similar effect. I use

""" `delegate(f, typfield)` delegates `f(::T, args...)` to `f(t.field, args...)`

    type AA
        a
    end

    @delegate(Base.length, AA.a)
    length(AA([1,2,3]))    # -> 3
"""
macro delegate(f, typfield)
    @assert typfield.head == :.
    typ = typfield.args[1]
    field = typfield.args[2].args[1]
    :(function $(esc(f))(obj::$(esc(typ)), args...; kwargs...)
      # Not sure why, but using @inline caused an error on Julia 0.4
      $(esc(Expr(:meta, :inline)))
      $(esc(f))(getfield(obj, $(esc(Expr(:quote, field)))), args...; kwargs...)
    end)
end

Memoize.jl might work, but AFAIK it doesn’t use weak-key dictionaries, so it’ll keep your objects arrays until you explicitly clear the memo. That’s not a problem with the GraphPoint.fx solution (I would use a Nullable there)