No, in the first case, the definition of Foo contains the abstract type Bar, since F is not passed as a parameter. In order for Foo to be concrete, the parameter of Bar{F} must be specified, for instance with a type variable, like in your second example.
Usually, you want structs to be defined with (possibly parameterized) concrete types for performance.
For performance, the second case Foo instance is better because it has a concrete type Bar instead of the abstract type Bar. This is seen in the output as well, right?
No, I think that is not a good advice because Function is an abstract type and for performance we should not have a field of this type inside the object. Instead use:
Are you sure about that? There is no way with the Function signature. And when I do this:
function a(v::Int)::Int
v + 1
end
function b(b::Int)::Int
v * 2
end
function just_one(f1::F) where F <: Function
l = Vector{F}()
push!(l, f1)
return l
end
function next_one!(l::Vector{F}, f1::F) where F <: Function
push!(l, f1)
return l
end
l = just_one(a)
next_one!(l, b)
I get:
ERROR: LoadError: MethodError: no method matching next_one!(::Array{typeof(a),1}, ::typeof(b))
Closest candidates are:
next_one!(::Array{F,1}, ::F) where F<:Function at /home/pixel27/test.jl:16
Even though function a and b have the same signature, their Type is different. When calling just_one and passing in function a Julia would compile just_one for that parameters. Now I guess it could recompile the function if I call it passing in b as well. But I suspect the speed improvement for compiling the function specifically for the function parameter would be negated by having to recompile the function every time a different function is passed in.