Running f(x)=x*x prompts a definition overwritten warning. The warning alerts to the possibility of this kind of behavior. In general, redefining functions when some other functions referencing it have already been compiled is tricky. As http://github.com/julialang/julia/issues/265 from 2011 indicates, this is an old issue.
A program can avoid this issue with care. For example, using anonymous functions with foo() in the question will give:
julia> foo(x->x)
3
julia> foo(x->x*x)
9
In Julia 0.6 this issue is resolved. The Github issue details the resolution, but essentially, Julia keeps track of a version number of the world, and a function 'sees' a certain version of the world. In the REPL, a redefinition causes the call to the older function to trigger a recompile (see http://docs.julialang.org/en/latest/manual/methods.html# for details). The resulting behavior is less weird:
julia> # version 6.0
julia> function foo(f)
f(3)
end
foo (generic function with 1 method)
julia> f(x)=x
f (generic function with 1 method)
julia> foo(f)
3
julia> f(x)=x*x
f (generic function with 1 method)
julia> foo(f)
9
julia> # :-)
Thanks to @StefanKarpinski, @ChrisRackauckas
f(x)=x*xprompts adefinition overwrittenwarning. The warning alerts to the possibility of this kind of behavior. In general, redefining functions when some other functions referencing it have already been compiled is tricky. As github.com/julialang/julia/issues/265 from 2011 indicates, this is an old issue, but I guess programs can be refactored to avoid this issue. - Dan Getz