Check that all fields are concrete types?


#1

I’ve discovered that I may have introduced some performance-sapping code into my project because of the following issue. I have two structs A and B like this:

    struct A
        field1::Int
    end
    struct B
        containedA::A
    end

Later I decide to rewrite A with a parameter:

    struct A{T}
        field1::T  
    end

According to my understanding of the language, I should now also parametrize B with T, else the contained field A is an abstract type and anything that uses B will involve run-time dispatch. However, in many places in my code, I forgot to do this and am just now noticing the issue.

First, is my understanding correct? Is there a performance hit for not parameterizing B?

Second, if this is indeed the case, is there a technique to discover this problem (i.e., a technique to confirm that all fields of a struct are concrete) aside from running code_warntype and poring over the output?


#2

Yes,

you could use a macro (only tested on 0.7):

macro concrete(expr)
    @assert expr.head == :struct
    S = expr.args[2]
    return quote
        $(esc(expr))

        for n in fieldnames($S)
            if !isconcretetype(fieldtype($S, n))
                error("field $n is not concrete")
            end
        end
    end
end
julia> @concrete struct Foo
           v::Array{Int}
       end
ERROR: field v is not concrete
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] top-level scope at REPL[1]:9

julia> struct Bar{Int} end

julia> @concrete struct Foob
           v::Bar
       end
ERROR: field v is not concrete
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] top-level scope at REPL[1]:9

julia> @concrete struct Foobar
           v::Bar{Float64}
       end

#3

A quick question about this macro: could it be simplified by invoking isconcretetype on S itself instead of on the fields?


#4
struct S
  ...
end

is always concrete.