Function type specification

Consider two simple functions that take one Float64 and return another Float64:

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

julia> g(x) = x^3
g (generic function with 1 method)

Also, consider a higher-order function that takes a function and returns another function:

julia> h(fun::Function) = x -> 2fun(x)
h (generic function with 1 method)

julia> h(f)(2.)
8.0

julia> h(g)(2.)
16.0

Now, I want to apply h to an array of functions. However, such operation’s type stability depends on whether the array is homogeneous or not:

julia> fun_homog = [g, g]
2-element Array{#g,1}:
 g
 g

julia> fun_inhomog = [g, h]
2-element Array{Function,1}:
 g
 h

julia> @code_warntype broadcast(h, fun_homog)
(No instability)

julia> @code_warntype broadcast(h, fun_inhomog)
(Lots of instability)

The point here is that fun_homog’s element type is #g, whereas fun_inhomog’s element type is abstract Function.

I wonder if this kind of instability can be eliminated by allowing function type specification (like C’s function pointer). Clearly, f and g here are of the same type, in the sense that both take one Float64 and return another Float64. However, currently once an array [f, g] is formed, the array does not recognize such similarity between f and g.

In other words, I wonder if the array [f, g] can be typed as something like Array[::Function(::Float64)::Float64] to indicate that the array’s elements are functions that take one Float64 and return another Float64, and also wonder if such information could be used to eliminate the aforementioned type instability.

1 Like

https://github.com/yuyichao/FunctionWrappers.jl

1 Like

Glad to know that there is already an effort in this direction!

How can I use this in the above case? Could you show an example?

Why wasn’t function typing part of Julia’s design from the start ?

I find it really surprising that something like

::Function(::Float64)::Float64

doesn’t already exist.

Isn’t functionwrappers a hack to get around what is really a design problem ?

Because it has problematic interactions with multiple dispatch: https://github.com/JeffBezanson/phdthesis/blob/876be73a5aab9b034fac3eb9ea9d8f96713f786f/chap4.tex

The biggest challenge right now to doing something like this is that the type of those functions isn’t ::Function(::Float64)::Float64, they are ::Function(f, ::Float64)::Float64 and ::Function(g, ::Float64)::Float64. For another recent post on the topic, see Proposal for a first-class dispatch wrapper - #2 by jameson.

1 Like

That proposal looked really nice, are the plans in this direction?

Seems plausible, but the devil’s in the details and actually implementing it. Fortunately @jameson has a solid track record of delivering on even harder projects than this :nerd:

That said, this is a complex issue and we’ll have to think it through pretty carefully.

1 Like