What is the difference between the following two cases (if there is any difference at all):

``````struct Bar{F}
f::F
end

struct Foo
bar::Bar
end
``````

and:

``````struct Bar{F}
f::F
end

struct Foo{F}
bar::Bar{F}
end
``````

Are both cases completely the same?

Thanks!

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 `struct`s to be defined with (possibly parameterized) concrete types for performance.

3 Likes

Let’s assume I am using the definitions given in the first case:

``````julia> b1 = Bar(t -> sin(t))
Bar{var"#34#35"}(var"#34#35"())

julia> Foo(b1)
Foo(Bar{var"#34#35"}(var"#34#35"()))
``````

Now, In the second case I get:

``````julia> b1 = Bar(t -> sin(t))
Bar{var"#34#35"}(var"#34#35"())

julia> Foo(b1)
Foo{var"#9#10"}(Bar{var"#9#10"}(var"#9#10"()))
``````

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?

Thanks!

I believe if “f” is always going to be a function then you might just want to go:

``````struct Bar
f::Function
end
struct Foo
bar::Bar
end
``````

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:

``````struct Bar{F<:Function}
f::F
end
``````
3 Likes

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.

The problem here is that you probably shouldn’t be storing functions in a vector, as that loses the type info of the function.

Yes, I am.

Exactly.