# Function subtypes

**URL:** <https://discourse.julialang.org/t/function-subtypes/92292>\
**Category:** General Usage\
**Created:** [December 29, 2022, 9:11pm UTC](https://discourse.julialang.org/t/function-subtypes/92292 "2022-12-29T21:11:30Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![nchisholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nchisholm/32/37414_2.png) [@nchisholm](https://discourse.julialang.org/u/nchisholm)\
**Post date:** [December 29, 2022, 9:11pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/1 "2022-12-29T21:11:30Z")

</div>

According to the somewhat dated discussion in this [bug report](https://github.com/JuliaLang/julia/issues/17162), the only way to create a function whose supertype is a custom subtype of `Function` is to create a new singleton type, and then define methods on its sole instance.

```julia
# Boiler plate to make a "function" that is <: MyFunction
abstract type MyFunction <: Function end
struct _typeof_f <: MyFunction end
const f = _typeof_f()

# Now define some methods for f
function f(args...)
   ...
end
...

```

The boilerplate is annoying and the Julia LSP (using Emacs + LSP mode) complains at every method definition, “Cannot define function; it already has a value”. (Though the code _does_ work as expected, so maybe this is a bug/limitation of the language server.)

In any case, I am wondering if there is a better way to do things. For normal functions, I assume that something like the above boilerplate somehow happens automatically given the description in [Julia’s documentation](https://docs.julialang.org/en/v1/manual/types/#Types-of-functions). However, I’m not sure if the machinery that does this is available to the user or if it could be emulated with a macro.

My use case here is that I want to “tag” functions (by making them a special subtype of `Function`) as being members of a (linear) function space and define methods for addition and scalar multiplication directly on the functions themselves as a matter of convenience. Thus, one would have `(2f + g)(x) == 2f(x) + g(x)` where `f` and `g` are both instances of the custom subtype.

---

<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:** [December 29, 2022, 10:11pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/2 "2022-12-29T22:11:00Z")

</div>

In your example it seems that it’s necessary to define `f` as an alias name for the `_typeof_f()` function to be able to define a method for the function.

I wonder whether there’s a way to define a method without giving the function a name, that would reduce the boilerplate.

---

<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:** [December 29, 2022, 10:13pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/3 "2022-12-29T22:13:15Z")

</div>

> [@nchisholm](#):
>
> My use case here is that I want to “tag” functions (by making them a special subtype of `Function`) as being members of a (linear) function space and define methods for addition and scalar multiplication directly on the functions themselves as a matter of convenience.

Have you considered using something like `Union{typeof(f), typeof(g)}` instead of `MyFunction`?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [December 30, 2022, 12:02am UTC](https://discourse.julialang.org/t/function-subtypes/92292/4 "2022-12-30T00:02:19Z")

</div>

You do not have to subtype `Function`. You do not even have to instantiate the type. You can turn the type directly into a functor, a [function-like object](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects).

```julia
julia> struct MyFunction end

julia> (::Type{MyFunction})(x) = x + 3

julia> (::Type{MyFunction})(x, y) = x + y

julia> MyFunction(2)
5

julia> MyFunction(2, 8)
10

julia> struct MyParameterizedFunction{A} end

julia> (::Type{MyParameterizedFunction{N}})(x, y) where N = x + y * N

julia> MyParameterizedFunction{3}(2,3)
11

```

Taking this further, you can do the following.

```julia
julia> abstract type MyAbstractFunction end

julia> struct MyConcreteFunction <: MyAbstractFunction end

julia> MyConcreteFunction(x) = x*2
MyConcreteFunction

julia> MyConcreteFunction <: MyAbstractFunction
true

julia> MyConcreteFunction(4)
8

```

---

<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:** [December 30, 2022, 1:21am UTC](https://discourse.julialang.org/t/function-subtypes/92292/5 "2022-12-30T01:21:34Z")

</div>

The “taking this further” part is probably bad advice, because, stylistically, a constructor for some type should return an instance of that type.

Also relevant:

> <https://github.com/JuliaLang/julia/issues/42372>
>
> (This is a Julia 2.0 proposal, as it is breaking. It is surely not novel, but I …don't see another such issue open.) We currently treat outer constructors and \`convert\` method definitions as any other generic function, but there's an argument to be made that they should be special-cased by requiring that they always return an object of the stated type. Motivations:
> 
> 1. At present, it's essentially a bug to write fallback methods like this:
> \`\`\`julia
> foo(x::Int) = 1
> foo(x) = foo(Int(x))
> \`\`\`
> Why? Because someone might define
> \`\`\`julia
> struct Foo end
> Int(f::Foo) = f
> \`\`\`
> in which case you get
> \`\`\`julia
> julia\> foo(Foo())
> ERROR: StackOverflowError:
> Stacktrace:
> \[1\] foo(x::Foo) (repeats 79984 times)
> @ Main ./REPL\[3\]:1
> \`\`\`
> and StackOverflowErrors are to be avoided: they can take forever to resolve in some cases, they can at least in principle trash your session, etc.
> 
> The only good way to write such a fallback method is
> \`\`\`julia
> foo(x) = foo(Int(x)::Int)
> \`\`\`
> but I will bet that the \*vast\* majority of developers do not know this or bother with it, and probably everyone finds it ugly and annoying.
> 
> Some might complain about \[idempotent operators\](https://en.wikipedia.org/wiki/Idempotence) and \[involutions\](https://en.wikipedia.org/wiki/Involution\_(mathematics)), for example one might be tempted to define
> \`\`\`julia
> struct Not
> x
> end
> Not(x::Not) = x.x # just strip the \`Not\` wrapper rather than returning \`Not(Not(5))\`
> \`\`\`
> But a solution is to separately introduce \`not\` from \`Not\`, and allow this behavior for \`not\` but not \`Not\` (\`Not\` must \*always\* wrap in another \`Not\` layer).
> 
> 2. In addition to surprising the developer, failing to enforce this is much harder on inference and the compiler, sometimes with dramatically increased risk of invalidation. Consider the case of https://github.com/julia-vscode/CSTParser.jl/issues/308. For the implementation in https://github.com/julia-vscode/CSTParser.jl/blob/778212a77d2977b94a531240877eacff00700111/src/conversion.jl#L133-L203 it is impossible to predict the outcome. For certain package combinations with the SciML ecosystem, this constructor alone is responsible for thousands of invalidations. Such problems can only be detected by devoted and sophisticated sleuths, but designing the language to be bullet-proof against this solves it neatly with very little cost (when you want to return something different, just check \*before\* you call the constructor, not after).

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [December 30, 2022, 1:58am UTC](https://discourse.julialang.org/t/function-subtypes/92292/6 "2022-12-30T01:58:49Z")

</div>

This is unfortunate:

```julia
julia> abstract type MyAbstractFunction <: Function end

julia> struct MyConcreteFunction <: MyAbstractFunction end

julia> MyConcreteFunction(x) = x*2
MyConcreteFunction

julia> MyConcreteFunction(2)
4

julia> MyConcreteFunction isa Function
false

julia> MyConcreteFunction isa MyAbstractFunction
false

```

---

<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:** [December 30, 2022, 4:06am UTC](https://discourse.julialang.org/t/function-subtypes/92292/7 "2022-12-30T04:06:21Z")

</div>

> [@uniment](#):
>
> `MyConcreteFunction(x) = x*2`

This not how you make a callable object / functor — you’ve just defined a constructor, not a call method. A functor is a callable _object_ which means you need to define how to call an _instance_, not the type itself.

For example:

```julia
julia> abstract type MyAbstractFunction <: Function end

julia> struct MyConcreteFunction <: MyAbstractFunction end

julia> (::MyConcreteFunction)(x) = x*2

julia> f = MyConcreteFunction() # create an instance
(::MyConcreteFunction) (generic function with 1 method)

julia> f(3)
6

julia> f isa Function
true

julia> f isa MyAbstractFunction
true

```

As a more practical example, consider a polynomial functor type, where instances represent particular coefficients:

```julia
julia> struct Poly{T} <: Function
           coeffs::Vector{T}
       end

julia> (p::Poly)(x) = evalpoly(x, p.coeffs)

julia> p = Poly([3,4,5]) # call the constructor
Poly{Int64}([3, 4, 5])

julia> p(7) # call the instance
276

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [December 30, 2022, 11:52am UTC](https://discourse.julialang.org/t/function-subtypes/92292/8 "2022-12-30T11:52:40Z")

</div>

> [@nsajko](#):
>
> The “taking this further” part is probably bad advice, because, stylistically, a constructor for some type should return an instance of that type.

The first and second part are actually the same in this regard. In both cases, I’m overriding the constructor and _not_ returning an instance of the type. If the second part is bad advice, then both parts are bad advice. My motive here is to eliminate “annoying” boiler plate, and technically the syntax actually allows for this. The primary issue is likely a language server bug.

```julia
julia> struct MyFunction end

julia> (::Type{MyFunction})(x) = x + 3

julia> MyFunction(2)
5

julia> MyFunction(x) = 2x
MyFunction

julia> MyFunction(2)
4

julia> MyFunction isa DataType
true

```

Regarding [Issue 42372](https://github.com/JuliaLang/julia/issues/42372), the other take away from this is that the behavior I’m exploiting is actually supported in Julia 1.x. The developers have also emphasized strongly that there are no plans for Julia 2.x at the moment.

> [@stevengj](#):
>
> This not how you make a callable object / functor — you’ve just defined a constructor, not a call method. A functor is a callable _object_ which means you need to define how to call an _instance_, not the type itself.

Technically, I am calling an _instance_. It’s just an _instance_ of `DataType`. The OP does not actually need any fields or captured variables.

However, I do think exploiting the constructor is distracting from a few points. Let me emphasize that subtyping `Function` is not necessary. You can make the instance callable without subtyping `Function`.

```julia
abstract type MyAbstractFunction end
struct MyFunction <: MyAbstractFunction end
(::MyFunction)(x) = x - 1

julia> MyFunction()(2)
1

```

The main advantage that subtyping `Function` provides is that you can pass your type to functions that accept a subtype of `Function`.

> [@nchisholm](#):
>
> My use case here is that I want to “tag” functions (by making them a special subtype of `Function`) as being members of a (linear) function space and define methods for addition and scalar multiplication directly on the functions themselves as a matter of convenience. Thus, one would have `(2f + g)(x) == 2f(x) + g(x)` where `f` and `g` are both instances of the custom subtype.

Here’s one approach:

```julia
abstract type LinearFunction <: Function end
struct ConcreteLinearFunction{F <: Function} <: LinearFunction
    func::F
end
const CLF = ConcreteLinearFunction
(clf::CLF)(x...) = clf.func(x...)

import Base: *, +
n::Number * clf::CLF = CLF(x->n*clf(x))
a::CLF + b::CLF = CLF(x->a(x)+b(x))

```

You can then do the following:

```julia
julia> const f = CLF(x->2x)
(::ConcreteLinearFunction{var"#5#6"}) (generic function with 1 method)

julia> const g = CLF(x->3x)
(::ConcreteLinearFunction{var"#7#8"}) (generic function with 1 method)

julia> (2f + g)(3) == 2f(3) + g(3)
true

julia> f(3)
6

julia> g(3)
9

julia> (2f)(3)
12

julia> f(6)
12

julia> (f + g)(3)
15

julia> (2f + g)(3)
21

```

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [December 30, 2022, 12:36pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/9 "2022-12-30T12:36:20Z")

</div>

You’re just confusing `isa` for `<:`. `isa` on objects, `<:` on types.

---

<div class="post-metadata">

**Author:** ![nchisholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nchisholm/32/37414_2.png) [@nchisholm](https://discourse.julialang.org/u/nchisholm)\
**Post date:** [December 30, 2022, 4:46pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/10 "2022-12-30T16:46:08Z")

</div>

> [@nsajko](#):
>
> Have you considered using something like `Union{typeof(f), typeof(g)}` instead of `MyFunction`?

Thanks for the additional suggestion - I hadn’t thought of that. For what I am envisioning, though, I think that this approach may be hard to extend because you (or users of a package) wouldn’t be able to add new types to the original Union{…}.

---

<div class="post-metadata">

**Author:** ![nchisholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nchisholm/32/37414_2.png) [@nchisholm](https://discourse.julialang.org/u/nchisholm)\
**Post date:** [December 30, 2022, 5:25pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/11 "2022-12-30T17:25:58Z")

</div>

With regard to (ab)using constructors, I did think of that possibility, but I decided against it due to reasons mentioned by others in this thread.

The suggestion to create a wrapper type is a good one. In fact, it is the first approach I took. However, I ran into two small issues:

1. Defining the functions is slightly awkward — you can wrap anonymous functions, use do syntax on the constructor, or wrap an existing regular function
2. Defining new methods is also awkward — AFAIK, you end up having to keep around a (named) unwrapped function to add new methods

Despite the boilerplate, I am now thinking that my original approach is probably best. That’s because

1. It follows Julia’s model for regular functions most closely
2. You can define new methods for subtyped functions as usual, e.g., using `function ... end`.

The LSP’s complaints are annoying but hopefully could be fixed.

I’ll try writing a macro to simplify things and post whatever I come up with here if I am successful… Anything more than simple macros seem to turn into day-long projects for me 😩. I’ll just need to figure out away to automate the naming, creation, and instantiation of a singleton type - hopefully not too challenging.

Still, it would be nice to see dedicated syntax for this sort of thing, e.g.,

```julia
function myfunc(args...) <: MyFuncType
    ...
end

```

as suggested in [Issue 17162](https://github.com/JuliaLang/julia/issues/17162), which could be done when a function is first defined. It appeared there was some support for this, but the issue was eventually closed because of the possibility of defining singleton types manually, as done here.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [December 30, 2022, 6:09pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/12 "2022-12-30T18:09:02Z")

</div>

> [@nchisholm](#):
>
> Still, it would be nice to see dedicated syntax for this sort of thing, e.g.,

See these discussion: [Shorthand syntax for defining functors - Internals & Design - Julia Programming Language (julialang.org)](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380)

> [@nchisholm](#):
>
> I’ll try writing a macro to simplify things and post whatever I come up with here if I am successful…

I’ve actually have written a macro to do this before:

```julia
julia> macro singleton(expr)
           expr = expr::Expr
           @assert Meta.isexpr(expr, :call) && first(expr.args) == :isa "Not an `isa` expression"

           _, name, supertype = expr.args
           typename = gensym(name)

           return quote
               struct $typename <: $(esc(supertype)) end
               const $(esc(name)) = $typename()
               Base.@ __doc__ ($(esc(name)))
           end
       end
@singleton (macro with 1 method)

julia> abstract type MyType <: Function end

julia> begin
           """
           Singleton object `foo` acts as a function with special properties...
           """
           @singleton foo isa MyType
       end
foo

julia> foo() = println("Hello world!")
(::var"##foo#292") (generic function with 1 method)

julia> foo(name) = println("Hello $(name)!")
(::var"##foo#292") (generic function with 2 methods)

julia> foo()
Hello world!

julia> foo("Steve")
Hello Steve!

julia> foo isa MyType
true

julia> foo isa Function
true

help?> foo
search: foo floor pointer_from_objref OverflowError RoundFromZero unsafe_copyto! functionloc StackOverflowError

  Singleton object foo acts as a function with special properties...

```

## Edit:

- Use `isa` instead of `<:`
- Removed `Base.show` definition
- Add support for docstrings with `Base.@ __doc__ `

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [December 30, 2022, 10:07pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/13 "2022-12-30T22:07:25Z")

</div>

> [@Raf](#):
>
> `isa` on objects, `<:` on types.

Yes, that’s the point. Because `!isa(MyConcreteFunction, Function)`, it’s impossible to pass `MyConcreteFunction` to methods specialized on `::Function` arguments, which is the whole point of subtyping `Function` to begin with.

Unless such functions can also be expected to accept `::Type{<:Function}` arguments but I don’t think that’s the case.

---

<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:** [December 30, 2022, 10:16pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/14 "2022-12-30T22:16:17Z")

</div>

> [@uniment](#):
>
> it’s impossible to pass `MyConcreteFunction` to methods specialized on `::Function` arguments, which is the whole point of subtyping `Function` to begin with.

You pass `MyConcreteFunction()`, i.e. an instance, which _is_ a subtype of `Function`.

You wouldn’t pass `Function` to a method expecting `::Function`, or `Int` to a function expecting `::Integer`, after all.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [December 30, 2022, 10:18pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/15 "2022-12-30T22:18:30Z")

</div>

![YeahYesGIF](https://global.discourse-cdn.com/julialang/original/3X/d/1/d15f5573b259b7ef5fc922384d69327716fbcfa4.gif)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [January 1, 2023, 11:18am UTC](https://discourse.julialang.org/t/function-subtypes/92292/16 "2023-01-01T11:18:18Z")

</div>

Here is another approach with a bit of type piracy.

```julia
julia> islinear(::Function) = false
islinear (generic function with 1 method)

julia> function Base.:*(n::Number, f::Function)
           if islinear(f)
               h = (x...) -> 2 * f(x...)
               @eval islinear(::typeof($h)) = true
               return h
           else
               throw(MethodError(*, (n,f)))
           end
       end

julia> function Base.:+(a::Function, b::Function)
           if islinear(a) && islinear(b)
               h = (x...) -> a(x...) + b(x...)
               @eval islinear(::typeof($h)) = true
               return h
           else
               throw(MethodError(+, (a,b)))
           end
       end

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

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

julia> f + g
ERROR: MethodError: no method matching +(::typeof(f), ::typeof(g))
Closest candidates are:
  +(::Function, ::Function) at REPL[3]:1
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:591
Stacktrace:
 [1] +(a::Function, b::Function)
   @ Main ./REPL[3]:7
 [2] top-level scope
   @ REPL[6]:1

julia> islinear(::typeof(f)) = true
islinear (generic function with 2 methods)

julia> islinear(::typeof(g)) = true
islinear (generic function with 3 methods)

julia> f + g
#3 (generic function with 1 method)

julia> h = f + g
#3 (generic function with 1 method)

julia> h(1)
5

julia> h(2)
10

julia> f + h
#3 (generic function with 1 method)

julia> islinear(ans)
true

```

The question then becomes how to avoid the type piracy. You could make your own `+` and `*` in a module:

```julia
julia> module LinearFunctions
           islinear(::Function) = false
           function +(a::Function, b::Function)
                  if islinear(a) && islinear(b)
                      h = (x...) -> Base.:+(a(x...),b(x...))
                      @eval islinear(::typeof($h)) = true
                      return h
                  else
                      throw(MethodError(+, (a,b)))
                  end
              end
           function *(n::Number, f::Function)
                  if islinear(f)
                      h = (x...) -> Base.:*(2,f(x...))
                      @eval islinear(::typeof($h)) = true
                      return h
                  else
                      throw(MethodError(*, (n,f)))
                  end
              end
       end
Main.LinearFunctions

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

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

julia> f(1)
2

julia> g(2)
6

julia> import .LinearFunctions: islinear, +, *

julia> h = f + g
ERROR: MethodError: no method matching +(::typeof(f), ::typeof(g))
Closest candidates are:
  +(::Function, ::Function) at REPL[1]:3
Stacktrace:
 [1] +(a::Function, b::Function)
   @ Main.LinearFunctions ./REPL[1]:9
 [2] top-level scope
   @ REPL[5]:1

julia> islinear(::typeof(f)) = true
islinear (generic function with 2 methods)

julia> islinear(::typeof(g)) = true
islinear (generic function with 3 methods)

julia> h = f + g
#1 (generic function with 1 method)

julia> islinear(h)
true

julia> 1 + 2
ERROR: MethodError: no method matching +(::Int64, ::Int64)
You may have intended to import Base.:+
Stacktrace:
 [1] top-level scope
   @ REPL[10]:1

julia> h(2)
10

```

One way around this would be to use a macro. Here’s a quick version.

```julia
julia> module LinearFunctions
                  islinear(::Function) = false
                  function +(a::Function, b::Function)
                         if islinear(a) && islinear(b)
                             h = (x...) -> Base.:+(a(x...),b(x...))
                             @eval islinear(::typeof($h)) = true
                             return h
                         else
                             throw(MethodError(+, (a,b)))
                         end
                     end
                  function *(n::Number, f::Function)
                         if islinear(f)
                             h = (x...) -> Base.:*(n,f(x...))
                             @eval islinear(::typeof($h)) = true
                             return h
                         else
                             throw(MethodError(*, (n,f)))
                         end
                     end
              macro linear(e)
                  if e.head == :call && e.args[1] ∈ (:+, :*)
                      e.args[1] = :(LinearFunctions.$(e.args[1]))
                      return esc(e)
                  elseif e.head == :(=) && e.args[1].head == :call
                       func = esc(e.args[1].args[1])
                       e = esc(e)
                       quote
                           $e
                           LinearFunctions.islinear(::typeof($func)) = true
                           $func
                       end
                  else
                      return e
                  end
              end
           end
Main.LinearFunctions

julia> import .LinearFunctions: islinear, @linear

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

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

julia> islinear(f)
true

julia> islinear(g)
true

julia> foo = @linear f + g
#1 (generic function with 1 method)

julia> islinear(foo)
true

julia> foo(1)
5

julia> foo(2)
10

julia> h = @linear (@linear 2f) + g
#1 (generic function with 1 method)

julia> h(1)
7

julia> 1 + 2
3

```

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [January 2, 2023, 3:40am UTC](https://discourse.julialang.org/t/function-subtypes/92292/17 "2023-01-02T03:40:36Z")

</div>

> [@nchisholm](#):
>
> the only way to create a function whose supertype is a custom subtype of `Function` is to create a new singleton type, and then define methods on its sole instance.

Can you give a hint of the use case for this? I don’t see `Function` used often, and for good reason. Normally people duck type callables in interfaces to my knowledge?

> [@uniment](#):
>
> it’s impossible to pass `MyConcreteFunction` to methods specialized on `::Function` arguments

I think the use case here would help. Is there a particular package or interface you are planning to use which requires that for dispatching? If so, maybe fixing that signature (eg, usually just removing unnecessary constraints) solves the problem.

This also seems like a classic case for Traits in one form or another since being accessible as a function is often orthogonal to other things you might want to dispatch with for your types. Without built-in traits support in Julia, duck typing is often the way to go.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 2, 2023, 5:55am UTC](https://discourse.julialang.org/t/function-subtypes/92292/18 "2023-01-02T05:55:13Z")

</div>

> [@jlperla](#):
>
> I think the use case here would help. Is there a particular package or interface you are planning to use which requires that for dispatching?

Ha fair, I never questioned the legitimacy of the OP’s desire to subtype `Function`.

Supposing that the OP’s reasons are legitimate, they’re certainly for dispatch.

Here’s an example of methods specializing on `::Function`:

```julia
julia> methods(open)
# 11 methods for generic function "open":
 ⋮
[5] open(f::Function, cmds::Base.AbstractCmd, args...; kwargs...) in Base at process.jl:414
[6] open(f::Function, args...; kwargs...) in Base at io.jl:381
 ⋮

```

> [@mkitti](#):
>
> Here is another approach with a bit of type piracy.

Why go to such lengths to circumvent an amazing type system?

```julia
julia> abstract type AbstractLinearFunction <: Function end

julia> struct Foo <: AbstractLinearFunction end

julia> const foo = Foo()
(::Foo) (generic function with 0 methods)

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

julia> foo(x, y) = 2x + 3y
foo (generic function with 2 methods)

julia> foo(2)
4

julia> foo(2, 3)
13

julia> foo isa Function && foo isa AbstractLinearFunction
true

```

Depending how crazy you want to get…

```julia
julia> struct LinearFunction{A} <: AbstractLinearFunction a::A end

julia> (lf::LinearFunction)(x) = lf.a * x

julia> const id2d = LinearFunction([1 0; 0 1])
(::LinearFunction{Matrix{Int64}}) (generic function with 1 method)

julia> id2d([1, 2])
2-element Vector{Int64}:
 1
 2

julia> using Polynomials

julia> const integrator = LinearFunction(1 // Polynomial((0, 1), :s))
(::LinearFunction{RationalFunction{Int64, :s, Polynomial{Int64, :s}}}) (generic function with 1 method)

julia> (lf::LinearFunction{<:Function})(x) = lf.a(x)

julia> (lf::LinearFunction{<:Polynomials.AbstractRationalFunction})(x) = lf.a(x) 

julia> # because RationalFunction doesn't subtype Function lolwtf

julia> let ω=2π*10; integrator(im*ω) end
0.0 - 0.015915494309189534im

julia> integrator isa Function
true

julia> scale(ν) = Base.Fix2(*, ν)
scale (generic function with 1 method)

julia> Base.:*(f::AbstractLinearFunction, k::Number) = LinearFunction(scale(k) ∘ f)

julia> Base.:*(k::Number, f::AbstractLinearFunction) = LinearFunction(scale(k) ∘ f)

julia> let ω=2π*10; (10integrator)(im*ω) end
0.0 - 0.15915494309189535im

julia> 10integrator isa LinearFunction &&
           10integrator isa AbstractLinearFunction &&
           10integrator isa Function
true

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [January 2, 2023, 6:36am UTC](https://discourse.julialang.org/t/function-subtypes/92292/19 "2023-01-02T06:36:20Z")

</div>

> [@jlperla](#):
>
> This also seems like a classic case for Traits in one form or another

I essentially implemented an `islinear` trait above.

> [@uniment](#):
>
> Why go to such lengths to circumvent an amazing type system?

That amazing type system lacks multiple inheritance for better or for worse. The thought of multiple inheritance and multiple dispatch at the same time gives me a headache, so it’s probably for the better.

However, we clearly have functions such as a `identity`, which are linear functionals, and already belong to a type hierarchy that we cannot change. While we could wrap the function up as you suggest, perhaps we could just add information to the type via `islinear(::typeof(identity)) = true` or alternatively `islinear(::Type{typeof(identity)}) = true`

Note that we could dispatch on this as well:

```julia
foobar(f::Function) = foobar(f, Val(islinear(f)))
foobar(f::Function, linear::Val{true}) = do_with_linear_function(f)
foobar(f::Function, linear::Val{false}) = do_with_nonlinear_function(f)

```

The trait pattern is just another way of using of the type system. We could replace `Val` with something more formal as Tom Kwong details here about the Holy Trait Pattern:  
[https://ahsmart.com/pub/holy-traits-design-patterns-and-best-practice-book/#identifying\_traits](https://ahsmart.com/pub/holy-traits-design-patterns-and-best-practice-book/#identifying_traits)

---

<div class="post-metadata">

**Author:** ![nchisholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nchisholm/32/37414_2.png) [@nchisholm](https://discourse.julialang.org/u/nchisholm)\
**Post date:** [January 3, 2023, 7:15pm UTC](https://discourse.julialang.org/t/function-subtypes/92292/21 "2023-01-03T19:15:10Z")

</div>

Thanks, @dylanxyz. The thread you linked to answers some questions for me. It’s interesting that you can define methods for any instance of a singleton type using the `function` block syntax.

I also appreciate the macro example—I think that’s pretty much as convenient as one can get without adding some built-in syntactic sugar to the language.

[Next page](https://discourse.julialang.org/t/function-subtypes/92292.md?page=2)
