daycaster
daycaster

Reputation: 2697

Pass an updated function to an existing function

In this short sequence, the user creates a function userfunc(), but then wants to update the first definition to do something different. However the programfunc() has already compiled the first version, and continues to use it.

userfunc(str, n) = str ^ n
userfunc("hello", 3)

"hellohellohello"

# program makes use of the user's function
programfunc(func, a, b) = func(a, b)
programfunc(userfunc, "hello", 3)

"hellohellohello"

# now the user redefines the function
userfunc(str, n) = str ^ (n * n)
# userfunc("hello", 3) give "hellohellohellohellohellohellohellohellohello"

# but program still makes use of the first userfunc()
programfunc(userfunc, "hello", 3)

"hellohellohello"

So how could programfunc() be defined so that it always uses the latest definition of the function passed to it?

Upvotes: 3

Views: 119

Answers (2)

Frames Catherine White
Frames Catherine White

Reputation: 28202

invoke will do it. (Note though this will probably not compile to nice specialized code)

The issue here is that julia specialized on Type. That is to say it compiles a custom version of the function for every combination of types passed to it. Since Functions have a type in julia 0.5 (Each function is a singleton type.) that causes it to specialize on the function

tested on 0.5-rc0

julia> userfunc(str, n) = str ^ (n*n)
WARNING: Method definition userfunc(Any, Any) in module Main at REPL[16]:1 overwritten at REPL[20]:1.
userfunc (generic function with 1 method)

julia> function programfunc(func, a, b)
       invoke(func, (typeof(a), typeof(b)), a, b)
       end
programfunc (generic function with 1 method)

julia> programfunc(userfunc, "hello", 3)
"hellohellohellohellohellohellohellohellohello"

julia> userfunc(str, n) = str ^ (n)
WARNING: Method definition userfunc(Any, Any) in module Main at REPL[16]:1 overwritten at REPL[20]:1.
userfunc (generic function with 1 method)

julia> programfunc(userfunc, "hello", 3)
"hellohellohello"

Note this also works around #265

julia> foo(x)=2*x
foo (generic function with 1 method)


julia> function g(x)
       invoke(foo, (typeof(x),), x)
       end
g (generic function with 1 method)

julia> g(2)
4

julia> foo(x)=3*x
WARNING: Method definition foo(Any) in module Main at REPL[1]:1 overwritten at REPL[10]:1.
foo (generic function with 1 method)

julia> g(2)
6

Upvotes: 3

David P. Sanders
David P. Sanders

Reputation: 5325

A simple workaround is to use an anonymous function:

programfunc((x,y) -> userfunc(x,y), "hello", 3)

This works because a new anonymous function is created each time:

julia> f(x) = x
x -> f (generic function with 1 method)

julia> x -> f(x)
(::#15) (generic function with 1 method)

julia> x -> f(x)
(::#17) (generic function with 1 method)

Upvotes: 3

Related Questions