Writing Explicitly-Typed Functions for all Vector{Float} or Vector{Number} / and missing?!


#1

dear julia experts—I would like to define a function with explicit typing, which works for all types of float vectors. Its output should be the same type as its input.

I know how to do this for one specific type, such as Float64.

julia> x64= [ 3.0, NaN, 2.0 ];

julia> function lag64( a::Vector{Float64}, n::Int=1 )::Vector{Float64};
          vcat( fill(NaN, n), a[1:(end-n)] ); end

julia> lag64( x64 )
3-element Array{Float64,1}:
 NaN
   3.0
 NaN

I could define the same function repeatedly (Float16, Float32, Float64, BigFloat), but this seems like a bad idea—if only because I would need to hand-propagate subsequent function changes. (And, ideally, I also want it to work with Float+missing.)

Here is a simple example (out of many) that I have tried:

julia> x32=Vector{Float32}( [1.0, NaN, -1.0 ] );

julia> function lagA( a::Vector{AbstractFloat}, n::Int=1 )::Vector{AbstractFloat};
            vcat( fill(NaN, n), a[1:(end-n)] ); end
julia> ## lag64( x32 )  ## of course not
## ERROR: MethodError: no method matching lag64(::Array{Float32,1})
julia> lagA( x32 )
ERROR: MethodError: no method matching lagA(::Array{Float32,1})
julia> lagA( x64 )
ERROR: MethodError: no method matching lagA(::Array{Float64,1})

Although my question is in terms of Float, it is really more generic.

how do I define functions that input not just one specific type, but a set of types; and which then return the same type—say, a Vector{Number} and return a Vector{Number} forced to be of the same type. When the function is called with a Vector{Int16}, it will return a Vector{Int16}. And, because Missing seems to become a quasi-basetype in terms of its importance, I need to write functions that grok base types with missing, too.

Advice appreciated. Julia is fun, but has a good learning curve, so apologies for so many questions.

/iaw


#2
function lagfloat(v::Vector{T}) where T<:AbstractFloat
  someone(v)::Vector{T}
end

If you must be explicit. May be your code don’t to be


#3

Use a method to determine the type of the element you want to fill with, and leave the rest to dispatch and promotion:

using Missings
filler(::Type{T}) where {T <: AbstractFloat} = T(NaN)
filler(::Type) = missing
lag(v::AbstractVector{T}, n = 1) where T = vcat(fill(filler(T), n), v[1:(end-n)])

then the following work fine:

julia> lag(Float32.([1, 2, 3]), 1)
3-element Array{Float32,1}:
 NaN32  
     1.0
     2.0

julia> lag([:a, :b, :c], 1)
3-element Array{Union{Missings.Missing, Symbol},1}:
 missing
 :a     
 :b     

#4
obj = Vector{Float64}([3, NaN, 2])
function lag(obj::Vector{T}, n::Integer = 1) where T <: AbstractFloat
    @assert n < length(obj) "n must be less than the length of the vector."
    vcat(fill(NaN, n), obj[1:(end - n)])::Vector{T}
end

Alternatively,

using Missings
function otherlag(obj::Vector{T}, n::Integer = 1) where T <: Union{AbstractFloat, Union{AbstractFloat, Missing}}
    @assert n < length(obj) "n must be less than the length of the vector."
    vcat(fill(missing, n), obj[1:(end - n)])::Vector{Union{T,Missing}}
end