Invoking parent functors in Julia - 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

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.

Related

Initializing a struct field that is a vector in Julia

I have the following mutable struct:
mutable struct foo
x::Vector{String}
# other field(s)...
# constructor(s)
end
I would like to create an object from this struct and edit it like the following:
bar = foo() # or some other constructor
push!(bar.x, "a")
# Do some stuff...
push!(bar.x, "b")
# Do some more stuff...
push!(bar.x, "c")
To do this, what is the best constructor for foo?
P.S. I have tried the following constructors:
foo() = new()
If I use this and do push!(bar.x, "a"), I get an UndefRefError. I could initialize bar.x outside (like bar.x = []), but I really want to avoid this.
I have also tried:
foo() = new([])
With this, I can do the push operations without a problem. However, if I have many other other fields in the struct that are also vectors, I would have to do this:
mutable struct foo
x::Vector{String}
y::Vector{String}
z::Vector{String}
w::Vector{String}
# maybe dozens more...
foo() = new([], [], [], [], ...) # kind of ugly and wastes time to type
end
Is this the best there is?
You can do:
julia> mutable struct Foo
x::Vector{String}
Foo() = new(String[])
end
julia> Foo()
Foo(String[])
However, for your scenario the most convenient would be Base.#kwdef:
Base.#kwdef mutable struct FooB
x::Vector{String} = String[]
y::Vector{String} = String[]
end
Now of course you can do:
julia> FooB()
FooB(String[], String[])
However other methods are available too:
julia> methods(FooB)
# 3 methods for type constructor:
[1] FooB(; x, y) in Main at util.jl:478
[2] FooB(x::Vector{String}, y::Vector{String}) in Main at REPL[9]:2
[3] FooB(x, y) in Main at REPL[9]:2
So you could do:
julia> FooB(;y=["hello","world"])
FooB(String[], ["hello", "world"])
There's one alternative that is quite concise and almost as fast as writing out the inputs:
struct Foo # Typenames should be uppercase
x::Vector{String}
y::Vector{String}
z::Vector{String}
w::Vector{String}
Foo() = new((String[] for _ in 1:4)...) # using a generator and splatting
# Foo() = new(ntuple(_->String[], 4)...) # also possible
end

Add and call Function to and from Dict in Julia

assume I have a Dict
acts = Dict{String, Function}()
and I have a function foo()
function foo(arg1, arg2)
#info arg1
#info arg2
end
First, How can I store "bar" => foo() in acts Dict?
Second, How can I call bar from acts and run it?
Should be straightforward:
julia> acts = Dict{String, Function}()
Dict{String,Function} with 0 entries
julia> function foo(arg1, arg2)
#info arg1
#info arg2
end
foo (generic function with 1 method)
# add function foo to dict acts with key "bar"
julia> acts["bar"] = foo
foo (generic function with 1 method)
# check that it's there
julia> acts
Dict{String,Function} with 1 entry:
"bar" => foo
# call the foo function from the dict by using its key
julia> acts["bar"]("hi", 2)
[ Info: hi
[ Info: 2

How to pass a function typesafe in julia

Let's say, I want to pass a function to another function:
function foo()
return 0;
end
function bar(func)
return func();
end
print(bar(foo));
But you can make functions typesafe:
function func(t::Int)
print(t);
end
func(0); #produces no error
func("Hello world"); #produces an error
I didn't found out, how I combine both, that means, how can I explicitly define a parameter of bar, like func, to be a function, possibly with certain input / output argument types.
Thanks in advance for any help.
If I understand you correctly you want to make sure the passed function returns a specific type? The simplest thing is to just typeassert the return value at runtime:
julia> function f(func)
val = func()::Int # Error if the return value is not of type Int
return val
end
f (generic function with 1 method)
julia> f(() -> 1)
1
julia> f(() -> 1.0)
ERROR: TypeError: in typeassert, expected Int64, got Float64
Stacktrace:
[1] f(::var"#7#8") at ./REPL[5]:2
[2] top-level scope at REPL[8]:1
Alternatively you can use the FunctionWrappers.jl package (which will convert to the specified return type, or error if the conversion is not possible):
julia> using FunctionWrappers: FunctionWrapper
julia> function f(func::FunctionWrapper{Int,<:Tuple})
val = func()
return val
end;
julia> function f(func)
fw = FunctionWrapper{Int,Tuple{}}(func)
return f(fw)
end;
julia> f(() -> 1)
1
julia> f(() -> 1.0) # Can convert to Int
1
julia> f(() -> 1.2) # Can not convert to Int
ERROR: InexactError: Int64(1.2)
A function is of type Function. You can easily check this:
julia> foo() = 1;
julia> T = typeof(foo)
typeof(foo)
julia> supertype(T)
Function
julia> foo isa Function
true
This will not necessarily cover all callable types, as you can make any type callable:
julia> struct Callable end
julia> (::Callable)(x::Number) = x + one(x)
julia> callable = Callable()
Callable()
julia> callable(5)
6
julia> callable isa Function
false

(Julia 1.x) Getting type of #undef variable

I am looking to get the types of the fields within a struct in order to set the field values correspondingly. Some data types initialise values on instantiation (e.g. Int64, Float64), whereas other types initialise to #undef (e.g. String, Array). Whilst typeof(getfield()) works for the former types, it throws UndefRefError for the latter:
julia> mutable struct MyStruct
a::Int64
b::String
MyStruct() = new()
end
julia> foo = MyStruct()
MyStruct(0, #undef)
julia> typeof(getfield(foo, :a))
Int64
julia> typeof(getfield(foo, :b))
ERROR: UndefRefError: access to undefined reference
Stacktrace:
[1] top-level scope at none:0
Is there is way to get the type of an uninitialised variable or does #undef indicate the distinct lack of a type? Alternatively, is it possible to initialise default values using the inner constructor? e.g.
julia> mutable struct MyStruct
a::Int64
b::String
MyStruct() = new(b = "")
end
You're looking for the fieldtype function:
julia> fieldtype(MyStruct, :a)
Int64
julia> fieldtype(MyStruct, :b)
String
To your other question, you surely can initialize fields.
mutable struct MyStruct
a::Int64
b::String
MyStruct() = new(0,"") # will initialize a as 0 and b as ""
end
Just a follow-on, you can get a tuple of all field types with fieldtypes:
julia> fieldtypes(MyStruct)
(Int64, String)

How to make type attribute be a function of other type attributes?

To declare a new composite type, we use the following syntax
type foo
a::Int64
b::Int64
end
and instantiate like such
x = foo(1,3)
Is there some way to have type attributes that always just a function of other attributes? For example, is there some way to do the following (which is invalid syntax)...
type foo
a::Int64
b::Int64
c = a + b
end
My current workaround is just to define a function which calculates c and returns an instance of the type, like so...
type foo
a::Int64
b::Int64
c::Int64
end
function foo_maker(a, b)
return foo(a, b, a+b)
end
Is there a more elegant solution? Possibly one that can be contained within the type definition?
EDIT - 3/7/14
With Cristóvão's suggestion in mind, I've ended up declaring constructors like the following to allow for keyword args and attributes calculated upon instantiation
# Type with optional keyword argument structure
type LargeType
# Declare all the attributes in order up top
q::Int64
w::Int64
e::Int64
r::Int64
t::Int64
y::Int64
a::Number
b::Number
c::Number
# Declare Longer constructor with stuff going on in the body
LargeType(;q=1,w=1,e=1,r=1,t=1,y=1) = begin
# Large Constructor Example
a = round(r^t - log(pi))
b = a % t
c = a*b
# Return new instance with correctly ordered arguments
return new(q,w,e,r,t,y,a,b,c)
end
end
println(LargeType(r=2,t=5))
Try this:
julia> type foo
a::Int64
b::Int64
c::Int64
foo(a::Int64, b::Int64) = new(a, b, a+b)
end
julia> foo(1,2)
foo(1,2,3)
julia> foo(4,5,6)
no method foo(Int64, Int64, Int64)
However, that won't prevent one from manually changing a, b or c and rendering c inconsistent. To prevent that, if it presents no other problems, you can make foo immutable:
julia> immutable foo
...
There isn't any way to do this currently, but there might be in the future:
https://github.com/JuliaLang/julia/issues/1974

Resources