Question regarding multiple dispatch [was Strange and dangerous behavior redefining a function]

question

#1

Hi,

I am running Julia v. 0.5.1-pre+27 and I stumbled in this unexpected behavior:
I defined a function in Julia REPL, e.g.:

f(a,b::Int64)=a*b

and I ran it once, e.g.:

f(3,4)

Then I modified the function:

f(a,b)=a*b*2

and I ran it again:

f(3,4)

to my surpise, the result was still the old one, calculated as a*b but running:

f(3,4.0)

yielded the correct result: a*b*2

I tried with different functions and types and the behavior is always the same.
It seems that the method for the type declared in the previous version of the function (here b::Int64) is not updating. Exiting Julia and directly defining the second form of the function results in the correct outcome.

I realized the problem because I was comparing the output of the functions, and it was simple enough, but this behavior is dangerous and may lead to serious problems when trusting the output without crosschecking.


FAQ subcategory
#2

What you are seeing is a consequence of multiple dispatch. If you call methods(f) you will see that there are two methods available one were b::Int64 and one with b::Any. The first one is more specific and is thus selected, when the second argument is an Int64.
When you call f(1, 4.0), b is of type Float64 and thus the more specific one is not selected and the more generic one is used.

If you want to overwrite the function you have to use f(a,b::Int64) = a*b*2.

See http://docs.julialang.org/en/release-0.5/manual/methods/#defining-methods.

julia> f(a,b::Int64)=a*b
f (generic function with 1 method)

julia> f(3,4)
12

julia> f(3,4.0)
ERROR: MethodError: no method matching f(::Int64, ::Float64)
Closest candidates are:
  f(::Any, ::Int64) at REPL[1]:1
 in eval_user_input(::Any, ::Base.REPL.REPLBackend) at ./REPL.jl:64
 in macro expansion at ./REPL.jl:95 [inlined]
 in (::Base.REPL.##3#4{Base.REPL.REPLBackend})() at ./event.jl:68

julia> f(a,b)=a*b*2
f (generic function with 2 methods)

julia> f(3,4)
12

julia> f(3,4.0)
24.0

julia> methods(f)
# 2 methods for generic function "f":
f(a, b::Int64) at REPL[1]:1
f(a, b) at REPL[3]:1

julia> f(a,b::Int64)=a*b*2
WARNING: Method definition f(Any, Int64) in module Main at REPL[1]:1 overwritten at REPL[6]:1.
f (generic function with 2 methods)

#3

The described behavior is expected and desirable. To avoid similar surprises, people should call the special workspace() function each time they want a clean start without exiting Julia REPL.


#4

Thanks for your replies.
Coming from R I never worked with multiple dispatch and I expected that changing the body of the function had a sort of priority over maintaining the method for a function defined with a specific type. My fault. I am now aware of how it is working, and I’ll use the workspace() function when needed.

Thanks.


#5

R actually has multiple dispatch, it’s just slow and not widely used outside of people doing advanced library programming.


#6

Worth mentioning that there is a long-standing issue that overwriting functions does not always work as expected when they have already been used inside other functions.


#7

Just to be precise, overwriting takes place per method, not per function, so the OP doesn’t really overwrite the former definition. Of course the definition of a more specialized method can still lead to surprises, like in the mentioned issue #265. But solving the issue should not and will not change the behavior in the OP, as the latter definition is more general than the former one. In other words, people should not consider that behavior as a bug, but as a feature, demonstrating that overwriting takes place per method, and the order of defining and using the various methods of a function is important.


#8

All right, it is not a bug but a feature (which indeed open great possibilities). I see that the multiple methods behavior is described in the Methods section of the Julia manual, while I did not find (yet) in the manual the issue of the redefinition of a function which has already been used inside another function.

But people should be aware of these issues (which are possible pitfalls) and probably it would be worth mentioning them early (as a warning? as a note?), maybe in the Introduction section of the manual (where types and multiple dispatches are also briefly introduced).


#9

Relevant FAQ entry here.