How do I get the expected return type of a polymorphic function at compile time?

This is in general a tricky issue, and it’s been discussed before (see Ridiculous idea: types from the future and the various threads that link to it).

But before we get too deep into the weeds of the various solutions to the problem, it would be helpful to understand what you actually want. NaN is a specific value of type Float64. If f() returns columns whose element type is also Float64, then the behavior of your function is obvious. But what if it doesn’t? If f() returns a Float32, then do you want a to have an element type of Float64 ? Or do you want a to have element type Float32 with all the NaNs replaced with their 32-bit equivalents? And what if f() returns a type which does not have a NaN (like Int, for example)? Should the element type of a be Union{Float64, Int} ?

Unless you actually mean NaN in the IEEE floating-point sense, I would actually suggest not using it at all and instead using Union{T, Missing} or Union{T, Nothing} (where T is the output element type of f(). See First-Class Statistical Missing Values Support in Julia 0.7 for more on why this is now a recommended approach in Julia 1.0.