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
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.