Functions in an input file-- how?

The problem FunctionWrappers.jl tries to solve is explained in the issue linked in the package readme. It doesn’t make calling anonymous function faster, in fact it makes it a little slower since there’ll be no inlining. It does eliminate the dispatch if you have a set of user defined functions that will be called with identical signatures.

Types for functions? Well, Julia has come a long way since I last got to play with it.
But I can’t see in the documentation how you write the type for a function to pass
as a parameter. What is F?

immutable Neumann{F}
    f::F
end

For instance, when I write

g(i::Int)=i

I get back

typeof(g)
#g

???

immutable Neumann{F}
    f::F
end

F is a type parameter and the type will be “specialized” on that type parameter. You can read more at https://docs.julialang.org/en/release-0.4/manual/types/#man-parametric-types.

Just write typeof(g) if you have to.

But what if I want to define a type, say:

type A
f::Function
end

where I would now like to replace ::Function with the type of this function

function f(a::Array{Float64,2})::Float64

How do I do this please?

Thanks.

P

type A
    f::typeof(f)
end

A non-parametric type like this is pretty useless though. Especially since it’s not even a closure…

There is not really any advantage over what you are trying to do compared to my version with just F.

Where do you get F I wonder? Do you have to use typeof()?

You don’t need to specify F, it is done automatically when the type is created:

julia> immutable Neumann{F}
           f::F
       end

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

julia> n = Neumann(f)
Neumann{#f}(f)

julia> n.f(3)
9

julia> assemble(n::Neumann, x) = n.f(x) # Usage is optimized
assemble (generic function with 1 method)

julia> @code_llvm assemble(n, 2.0)

define double @julia_assemble_60683(double) #0 !dbg !5 {
top:
  %1 = fmul double %0, %0
  ret double %1
}

I don’t think it is useless: say it is in a library, and the lib will set up the arguments and expects a certain type on return. What is useless about matching what is expected anyway?

But: Does one have to use typeof() or can the type be constructed in any other way?

Thanks.

It is more useful to parametrize the object shown in @kristoffer.carlsson’s reply. It’s useless when it’s not parametrized since you’ve limited the type to a single function. Basically, if you know that the user have to pass in a sin function, why don’t you just not letting the user passing it in at all.

The “other way” is exactly using a parametrized type/function and the dispatch will figure out the type parameter for you automatically.

For the few cases I’ve seen function type or type of callable are useful are,

  • Specialization on a certain function:

    This is the only case I’ve seen where you need typeof(f). You’d write

    f(callback) = do_something_fancy
    f(::typeof(identity)) = nothhing # i.e. do something boring
    
  • Use as a field type, see @kristoffer.carlsson’s code above.

  • Use in a container, this is where FunctionWrappers.jl is useful. It allows you to store multiple different functions in a leaftype container and load/call them without any dispatch overhead as long as you specify the type behavior of the function.

    Basically if you have [sin, cos, tan, cosh] and care about randomly load and call function from this array, FunctionWrapper{Float64,Tuple{Float64}}[sin, cos, tan, cosh] could be better at doing this.

1 Like

@yuyichao:

Perhaps I’m misunderstanding how this thing works. If I write
double (*)(double, double)
in the C language, any number of functions are going to match the signature. Are you saying that if I have

type A
f::F
end

in Julia, the type F is literally going to match only a single function when F= typeof(somefun)?

Correct. And double (*)(double, double) (or more generally std::function<double(double,double)>) is exactly what FunctionWrappers.jl does. It was actually the first sentence in the issue I linked above https://github.com/JuliaLang/julia/issues/13984#issue-116879024 . Function in julia are all functors, making anonymous functions, callable objects, and functions the same thing afa calling them is concerned. You get the same behavior in C++ if you do decltype on a lambda. This behavior is very useful to allow the maximum amount of optimizations, e.g. the callback can be inlined in to the function you are passing it to. It is bad if you want to have a list of them with different types or want to reduce specialization on them. That’s exactly why c++ have std::function AFAIK and is also what https://github.com/JuliaLang/julia/issues/13984#issue-116879024 mentions in the second sentence…

1 Like

@yuyichao:

Thank you very much for the thorough explanation. By the way, something like this should be somewhere in the documentation. It is either well hidden or absent at this point. I couldn’t find any mention of declaring the type of a function in the way described in this thread anywhere.

Petr

I’m 80% sure the use of typeof(f) and function parameter are both described in the doc. Improvements to the doc are always welcome…

@yuyichao:

I think the documentation needs some work. The only mention of the type of a function is in the section “Julia Functions”:

For example the name of Base.sin is sin. By convention, the name of the created type is the same as the function name, with a # prepended. So typeof(sin) is Base.#sin.

There is no mention of it in the section on “Functions” which would be the first place I would go looking for it.