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

**URL:** https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611
**Category:** Internals & Design
**Tags:** inference, function, constructors
**Created:** [August 31, 2022, 6:19pm UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611 "2022-08-31T18:19:58Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [August 31, 2022, 6:19pm UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/1 "2022-08-31T18:19:58Z")

</div>

I was thinking about how C++20 [added](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0624r2.pdf) support for default constructors for stateless (with no captures) lambdas, meaning that nowadays all function object families may be default-constructible in C++.  
Then I realized that in Julia I can’t even do `typeof(sqrt)()`, or something like this:

```julia
func(::F) where {F <: Function} = F()(5.0)
func(sqrt)

# Or this
func(::Type{F}) where {F <: Function} = F()(5.0)
func(typeof(sqrt))

```

Seems like passing “pure” functions as types, instead of as objects would make sense in some cases (possibly enabling new Julia design patterns), and maybe might even enable additional optimizations when used?

The above would basically enable expressing things like this, but in a prettier and safer way:

```julia
func(::Val{f}) where {f} = f(5.0)
func(Val{sqrt}())

```

Informally, each “stateless” Function type should have a no-argument constructor, on a best-effort basis from the compiler. In `@assume_effects` terminology, I guess that “stateless” might mean the combination of `:notaskstate`, `:inaccessiblememonly` and perhaps `:consistent`.

Though the distinction between methods and functions in Julia complicates things perhaps, because only methods may be “pure” or “stateless”, it doesn’t make sense to say that a _function_ is “stateless”?

Thoughts?

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [August 31, 2022, 7:26pm UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/2 "2022-08-31T19:26:57Z")

</div>

Every ‘singleton’ struct can be constructed from it’s type using `T.instance`

```julia-auto
julia> struct Foo end

julia> Foo.instance
Foo()

julia> typeof(sqrt).instance
sqrt (generic function with 19 methods)

julia> typeof(+).instance
+ (generic function with 206 methods)

```

I doubt this provides any great opportunities for optimizations though, and it’s generally not a good idea.

This sort

> [@nsajko](#):
>
> 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](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured) 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.

I think you should read that section again. The boxing problem only comes into play if you rebind the captured variable.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [August 31, 2022, 8:58pm UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/3 "2022-08-31T20:58:34Z")

</div>

> [@nsajko](#):
>
> Seems like passing “pure” functions as types, instead of as objects would make sense in some cases (possibly enabling new Julia design patterns), and maybe might even enable additional optimizations when used?

I don’t see why, since you can already specialize on the function type, and for singleton types there is not much practical distinction between passing a type and passing the instance.

What, concretely, do you hope to achieve that isn’t possible now?

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 1, 2022, 1:04am UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/4 "2022-09-01T01:04:58Z")

</div>

> [@stevengj](#):
>
> for singleton types there is not much practical distinction

I only realized that functions are singleton types _after_ writing the post above 😅.

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](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured) 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:

```julia
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 😄. Perhaps the Performance tips should be updated, if this behavior is something that can be counted on.

---

<div class="post-metadata">

### Author: ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)
#### Post date: [September 1, 2022, 1:15am UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/5 "2022-09-01T01:15:26Z")

</div>

> [@nsajko](#):
>
> ```julia-auto
> fun_nice(::F, ::G) where {F <: Function, G <: Function} =
> x ->
> let x::Float64 = x
> function()
> x = F()(x)
> G()(x)
> end
> end
> 
> ```

What is the advantage of what you wrote compared to:

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

```

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 1, 2022, 1:48am UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/6 "2022-09-01T01:48:48Z")

</div>

Your `fun_nice` seems to be exactly my `fun_slow`. And there’s no advantage, as I said in the previous message. I expected (because of Performance tips) that `fun_slow` would be slower, but it is not, at least with nightly Julia.

---

<div class="post-metadata">

### Author: ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)
#### Post date: [September 1, 2022, 2:05am UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/7 "2022-09-01T02:05:37Z")

</div>

> [@PetrKryslUCSD](#):
>
> `x`

Still, you seem to see some upside since you call it “nice”?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [September 1, 2022, 2:13am UTC](https://discourse.julialang.org/t/constructors-for-function-types-when-possible-like-in-c/86611/8 "2022-09-01T02:13:32Z")

</div>

> [@nsajko](#):
>
> `fun_nice` is obviously a lot nicer than `fun_ugly`.

`g ∘ f` seems even nicer…
