Constructors for `<:Function` types when possible, like in C++

I only realized that functions are singleton types after writing the post above :sweat_smile:.

Still, even after realizing that functions are singleton types I thought that there might be a certain reason to prefer passing functions as types: the Performance of captured variables issue. I thought that passing functions as types could enable writing more concise code with closures, because let isn’t necessary for type parameters. Long story short, turns out that let is also unnecessary for variables that happen to be of singleton type.

This is how I found this out:

fun_slow(f::F, g::G) where {F <: Function, G <: Function} =
  x ->
    let x::Float64 = x
      function()
        x = f(x)
        g(x)
      end
    end

fun_ugly(f::F, g::G) where {F <: Function, G <: Function} =
  let f = f, g = g
    x ->
      let f = f, g = g, x::Float64 = x
        function()
          x = f(x)
          g(x)
        end
      end
  end

(::Type{F})() where {F <: Function} = F.instance

fun_nice(::F, ::G) where {F <: Function, G <: Function} =
  x ->
    let x::Float64 = x
      function()
        x = F()(x)
        G()(x)
      end
    end

My initial idea was that fun_slow would be very slow and the other two would be tied in speed, but fun_nice is obviously a lot nicer than fun_ugly. After benchmarking with BenchmarkTools.@benchmark it turned out that all three returned functions ran at the same speed.

Good to know that there’s one less case where let is necessary for closures :smile:. Perhaps the Performance tips should be updated, if this behavior is something that can be counted on.