Search code examples
juliadispatch

Invoking parent functors in Julia


Since version 1.3 Julia allows functor dispatch on abstract types. Therefore, I was wondering whether it is possible to explicitly invoke the parent functor from a child object.

E.g. in the example below, is there any way to call (x::Foo)() through the bar::Bar object?

abstract type Foo end
(x::Foo)() = "Invoked Foo functor."

struct Bar <: Foo end
(x::Bar)() = "Invoked Bar functor."

bar = Bar()
@info "Calling bar functor directly."
bar() |> println
@info "Invoking parent functor."
# ??? - how to invoke parent functor (x::Foo)() (e.g. desired output "Invoked Foo functor")
invoke(bar,Tuple{Bar}, bar) |> println

Solution

  • what about using a default struct?

    abstract type Foo end
    (x::Foo)() = "Invoked Foo functor."
    
    struct Bar <: Foo end
    (x::Bar)() = "Invoked Bar functor."
    
    struct DefaultFoo <: Foo end
    #here we dont define an specialized method, DefaultFoo calls Foo
    
    #an interface to define default methods: 
    default(x::Type{Foo}) = DefaultFoo
    
    
    function parent(x::T) where {T}
         y = default(supertype(T))
         return y()
    end
    

    finally, you can do this to call the default function:

    bar = Bar()
    foo = parent(bar)
    foo()
    

    this requires a definition of a defaultFoo type and a default(x::Type{T}) for each supertype . you can automate this with the following macro:

    macro create_default_functor(type)
        a = gensym(type)
        esc(quote
            struct $a <: $type end
            default(x::Type{$type})  = $a
        end)
    end
    

    using the macro, and your code:

    abstract type Foo end
    (x::Foo)() = "Invoked Foo functor."
    @create_default_functor Foo
    struct Bar <: Foo end
    (x::Bar)() = "Invoked Bar functor."
    
    function parent(x::T) where {T}
         y = default(supertype(T))
         return y()
    end
    
    #calling bar
    bar = Bar()
    bar()
    #calling foo
    foo = parent(bar)
    foo()
    

    I don't have the macro knowledge right now to call the macro directly on the abstract type definition, but is a start. The thing about abstract functors is that is a very new feature (1.3 is not out yet) and maybe this can be added on future versions of julia (something like call_parent(Foo,args...), ) if you add a PR suggesting the feature.