Functor abstract types



Given a concrete type, one can define functor-like methods with:

struct Foo end
(f::Foo)(x) = 2x

and use the object as a function:

f = Foo()

This doesn’t work with abstract types, however; even though they support abstract methods:

abstract type A end
iscool(::A) = false # works just fine
(::A)(x) = 2x # fails, cannot add method to abstract type

Is there any way to define functor-like abstract types? I am just trying to avoid typing the same function for all subtypes of the abstract type manually.

abstract type A end
struct Foo <: A end
struct Goo <: A end

iscool(::A) = false

f = Foo()
g = Goo()

julia> iscool(f)

julia> iscool(g)

(::Type{T})(x) where {T<:A} = 232

Foo(1) == 232
Goo(1) == 232

edit: I think I misunderstood the original question.


Thanks, doesn’t this syntax with where defines the function for all subtypes without the possibility of specialization? I forgot to say that I need to very rarely overwrite the definition for specific subtypes.


I have encountered this before and also did not find a solution I am happy with. We basically work around this using something like

for T in union(subtypes(DistanceLoss), subtypes(MarginLoss))
    @eval (loss::$T)(args...) = value(loss, args...)

but this has a serious drawback (among others) that it only works for subtypes defined before that loop is executed (which is why its the last block of code in the package)

As a side note, fallbacks do work for parametric types

julia> immutable Foo{N} end

julia> (::Foo)(x) = 2x

julia> Foo{2}()(3)

julia> Foo{3}()(3)


Currently no.


Thank you for sharing the issue @yuyichao, I will keep the code as is for now then.


Thanks @Evizero for the workaround, I will keep writing things manually, at least for now when it is still manageable.


Wikipedia have an interesting article about “function object” (often called functor)

Otherwise there is no example for Julia.

Maybe someone could provide an example there?

I also noticed that provide functors… but it’s broken with Julia 0.6 see
Any news about it?

PS: Sorry, I should have post there


This is a classic example of a closure with state:

function make_counter()
    n = 0
        n += 1

c = make_counter()

[c() for _ in 1:10] # will collect numbers from 1 to 10

But you can also get the same behaviour by using a mutable struct and making it callable:

mutable struct Counter

Counter() = Counter(0)

(c::Counter)() = c.n += 1

c = Counter()

[c() for _ in 1:10]

Arguably, the second one is easier to inspect, extend, and debug.


Thanks @Tamas_Papp I’ve just edit Wikipedia page “Function object” to add a Julia example with an accumulator implementation (both with mutable struct and with closure with state).
This example is inspired from Python example


Nice addition. “Such a accumulator” should be “Such an accumulator”


Fixed. Thanks @ggggggggg for catching this