Skip to content

Commit

Permalink
Fix coalesce compat and add other 0.7 compat
Browse files Browse the repository at this point in the history
  • Loading branch information
quinnj committed Jan 18, 2018
1 parent 1d67624 commit a067a4b
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 56 deletions.
114 changes: 61 additions & 53 deletions src/Missings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module Missings

using Compat

export allowmissing, coalesce, disallowmissing, ismissing, missing, missings,
Missing, MissingException, levels, skipmissing
export allowmissing, disallowmissing, ismissing, missing, missings,
Missing, MissingException, levels, coalesce

if VERSION < v"0.7.0-DEV.2762"
"""
Expand All @@ -30,7 +30,7 @@ end
import Base: ==, !=, <, *, <=, !, +, -, ^, /, &, |, xor

if VERSION >= v"0.7.0-DEV.2762"
using Base: coalesce, ismissing, missing, Missing, MissingException
using Base: ismissing, missing, Missing, MissingException
else
"""
missing
Expand Down Expand Up @@ -88,7 +88,7 @@ else
:(Base.log2), :(Base.exponent), :(Base.sqrt), :(Base.gamma), :(Base.lgamma),
:(Base.iseven), :(Base.ispow2), :(Base.isfinite), :(Base.isinf), :(Base.isodd),
:(Base.isinteger), :(Base.isreal), :(Base.isimag), :(Base.isnan), :(Base.isempty),
:(Base.iszero), :(Base.transpose), :(Base.ctranspose), :(Base.float))
:(Base.iszero), :(Base.transpose), :(Base.float))
@eval $(f)(d::Missing) = missing
end

Expand Down Expand Up @@ -204,43 +204,10 @@ else
convert(AbstractArray{Union{U, Missing}}, A)
end
Base.float(A::AbstractArray{Missing}) = A
end

"""
coalesce(x, y...)
Return the first non-`missing` value in the arguments, or `missing` if all arguments are `missing`.
In its broadcasted form, this function can be used to replace all missing values
in an array with a given value (see examples).
# Examples
```jldoctest
julia> coalesce(missing, 1)
1
julia> coalesce(1, missing)
1
julia> coalesce(missing, missing)
missing
julia> coalesce.([missing, 1, missing], 0)
3-element Array{$Int,1}:
0
1
0
julia> coalesce.([missing, 1, missing], [0, 10, 5])
3-element Array{$Int,1}:
0
1
5
```
"""
coalesce(x) = x
coalesce(x, y...) = ifelse(x !== missing, x, coalesce(y...))
@static if isdefined(Base, :adjoint) && !applicable(adjoint, missing)
Base.adjoint(::Missing) = missing
end

T(::Type{Union{T1, Missing}}) where {T1} = T1
Expand All @@ -250,8 +217,8 @@ T(::Type{Any}) = Any

# vector constructors
missings(dims...) = fill(missing, dims)
missings(::Type{T}, dims...) where {T >: Missing} = fill!(Array{T}(dims), missing)
missings(::Type{T}, dims...) where {T} = fill!(Array{Union{T, Missing}}(dims), missing)
missings(::Type{T}, dims...) where {T >: Missing} = fill!(Array{T}(uninitialized, dims), missing)
missings(::Type{T}, dims...) where {T} = fill!(Array{Union{T, Missing}}(uninitialized, dims), missing)

"""
allowmissing(x::AbstractArray)
Expand Down Expand Up @@ -309,10 +276,10 @@ struct EachReplaceMissing{T, U}
x::T
replacement::U
end
Base.iteratorsize(::Type{<:EachReplaceMissing{T}}) where {T} =
Base.iteratorsize(T)
Base.iteratoreltype(::Type{<:EachReplaceMissing{T}}) where {T} =
Base.iteratoreltype(T)
Compat.IteratorSize(::Type{<:EachReplaceMissing{T}}) where {T} =
Compat.IteratorSize(T)
Compat.IteratorEltype(::Type{<:EachReplaceMissing{T}}) where {T} =
Compat.IteratorEltype(T)
Base.length(itr::EachReplaceMissing) = length(itr.x)
Base.size(itr::EachReplaceMissing) = size(itr.x)
Base.start(itr::EachReplaceMissing) = start(itr.x)
Expand All @@ -323,6 +290,8 @@ Base.eltype(itr::EachReplaceMissing) = Missings.T(eltype(itr.x))
(v isa Missing ? itr.replacement : v, s)
end

@static if !isdefined(Base, :skipmissing)
export skipmissing
"""
skipmissing(itr)
Expand Down Expand Up @@ -352,10 +321,10 @@ skipmissing(itr) = EachSkipMissing(itr)
struct EachSkipMissing{T}
x::T
end
Base.iteratorsize(::Type{<:EachSkipMissing}) =
Compat.IteratorSize(::Type{<:EachSkipMissing}) =
Base.SizeUnknown()
Base.iteratoreltype(::Type{EachSkipMissing{T}}) where {T} =
Base.iteratoreltype(T)
Compat.IteratorEltype(::Type{EachSkipMissing{T}}) where {T} =
Compat.IteratorEltype(T)
Base.eltype(itr::EachSkipMissing) = Missings.T(eltype(itr.x))
# Fallback implementation for general iterables: we cannot access a value twice,
# so after finding the next non-missing element in start() or next(), we have to
Expand Down Expand Up @@ -401,6 +370,8 @@ end
(v, _next_nonmissing_ind(itr.x, state))
end

end # isdefined

"""
Missings.fail(itr)
Expand Down Expand Up @@ -428,10 +399,10 @@ fail(itr) = EachFailMissing(itr)
struct EachFailMissing{T}
x::T
end
Base.iteratorsize(::Type{EachFailMissing{T}}) where {T} =
Base.iteratorsize(T)
Base.iteratoreltype(::Type{EachFailMissing{T}}) where {T} =
Base.iteratoreltype(T)
Compat.IteratorSize(::Type{EachFailMissing{T}}) where {T} =
Compat.IteratorSize(T)
Compat.IteratorEltype(::Type{EachFailMissing{T}}) where {T} =
Compat.IteratorEltype(T)
Base.length(itr::EachFailMissing) = length(itr.x)
Base.size(itr::EachFailMissing) = size(itr.x)
Base.start(itr::EachFailMissing) = start(itr.x)
Expand Down Expand Up @@ -466,4 +437,41 @@ end
# Deprecations
@deprecate skip(itr) skipmissing(itr) false

"""
coalesce(x, y...)
Return the first non-`missing` value in the arguments, or `missing` if all arguments are `missing`.
In its broadcasted form, this function can be used to replace all missing values
in an array with a given value (see examples).
# Examples
```jldoctest
julia> coalesce(missing, 1)
1
julia> coalesce(1, missing)
1
julia> coalesce(missing, missing)
missing
julia> coalesce.([missing, 1, missing], 0)
3-element Array{$Int,1}:
0
1
0
julia> coalesce.([missing, 1, missing], [0, 10, 5])
3-element Array{$Int,1}:
0
1
5
```
"""
Compat.coalesce(x::Missing) = missing
Compat.coalesce(x::Missing, y...) = coalesce(y...)

end # module
15 changes: 12 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Base.Test, Missings, Compat
using Compat.Test, Compat.SparseArrays, Missings, Compat

@testset "Missings" begin
# test promote rules
Expand All @@ -17,7 +17,11 @@ using Base.Test, Missings, Compat
@test promote_type(Union{Int, Missing}, Union{Int, Missing}) == Union{Int, Missing}
@test promote_type(Union{Float64, Missing}, Union{String, Missing}) == Any
@test promote_type(Union{Float64, Missing}, Union{Int, Missing}) == Union{Float64, Missing}
@test promote_type(Union{Void, Missing, Int}, Float64) == Any
if VERSION < v"0.7.0-"
@test promote_type(Union{Nothing, Missing, Int}, Float64) == Any
else
@test_broken promote_type(Union{Nothing, Missing, Int}, Float64) == Any
end

bit_operators = [&, |, ]

Expand All @@ -32,7 +36,7 @@ using Base.Test, Missings, Compat
iseven, isodd, ispow2,
isfinite, isinf, isnan, iszero,
isinteger, isreal,
isempty, transpose, ctranspose, float]
isempty, transpose, float]
VERSION < v"0.7.0-DEV" && push!(elementary_functions, isimag)

rounding_functions = [ceil, floor, round, trunc]
Expand All @@ -46,6 +50,11 @@ using Base.Test, Missings, Compat
for f in elementary_functions
@test ismissing(f(missing))
end
@static if isdefined(Base, :adjoint)
@test ismissing(adjoint(missing))
else
@test ismissing(ctranspose(missing))
end

# All rounding functions return missing when evaluating missing as first argument
for f in rounding_functions
Expand Down

1 comment on commit a067a4b

@andreasnoack
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compat.IteratorSize was introduced in v0.45.0 so this should have bumped the version of Compat in REQUIRE.

Please sign in to comment.