diff --git a/NEWS.md b/NEWS.md index b02d047..fda309b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -AbsentTypes.jl Release Notes +NullBroadcasts.jl Release Notes ============================ Main diff --git a/Project.toml b/Project.toml index a1809be..cccf987 100644 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,4 @@ -name = "AbsentTypes" +name = "NullBroadcasts" uuid = "0d71be07-595a-4f89-9529-4065a4ab43a6" authors = ["CliMA Contributors "] version = "0.1.0" diff --git a/README.md b/README.md index 22e177a..fa6a1d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# AbsentTypes.jl -A small package for defining absent (i.e., null) types and behaviors +# NullBroadcasts.jl + +A small package for defining null broadcasted types and behaviors diff --git a/docs/Project.toml b/docs/Project.toml index e0ab8f8..7cf91dc 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,4 +1,4 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244" -AbsentTypes = "0d71be07-595a-4f89-9529-4065a4ab43a6" +NullBroadcasts = "0d71be07-595a-4f89-9529-4065a4ab43a6" diff --git a/docs/make.jl b/docs/make.jl index 8b9a839..e7fb113 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,5 +1,5 @@ import Documenter, DocumenterCitations -import AbsentTypes +import NullBroadcasts bib = DocumenterCitations.CitationBibliography(joinpath(@__DIR__, "refs.bib")) @@ -15,17 +15,17 @@ format = Documenter.HTML( Documenter.makedocs(; plugins = [bib], - sitename = "AbsentTypes.jl", + sitename = "NullBroadcasts.jl", format = format, checkdocs = :exports, clean = true, doctest = true, - modules = [AbsentTypes], + modules = [NullBroadcasts], pages = Any["Home"=>"index.md", "API"=>"api.md", "References"=>"references.md"], ) Documenter.deploydocs( - repo = "github.com/CliMA/AbsentTypes.jl.git", + repo = "github.com/CliMA/NullBroadcasts.jl.git", target = "build", push_preview = true, devbranch = "main", diff --git a/docs/src/index.md b/docs/src/index.md index ffc8810..05b1173 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,2 +1,2 @@ -# AbsentTypes.jl +# NullBroadcasts.jl diff --git a/src/AbsentTypes.jl b/src/AbsentTypes.jl deleted file mode 100644 index c0e302e..0000000 --- a/src/AbsentTypes.jl +++ /dev/null @@ -1,76 +0,0 @@ -module AbsentTypes - -""" - Absent() - -A `Base.AbstractBroadcasted` that represents arithmetic object. - -An `Absent()` can be added to, subtracted from, or multiplied by any value in a -broadcast expression without incurring a runtime performance penalty. - -For example, the following rules hold when broadcasting instances of `Absent`: -``` -1 + Absent() == 1 -Absent() + 1 == 1 -1 - Absent() == 1 -1 * Absent() == Absent() -1 / Absent() == Absent() - ``` -""" -struct Absent <: Base.AbstractBroadcasted end -Base.broadcastable(x::Absent) = x - -struct AbsentStyle <: Base.BroadcastStyle end -Base.BroadcastStyle(::Type{<:Absent}) = Absent() - -# Specialize on AbstractArrayStyle to avoid ambiguities with AbstractBroadcasted. -Base.BroadcastStyle(::Absent, ::Base.Broadcast.AbstractArrayStyle) = Absent() -Base.BroadcastStyle(::Base.Broadcast.AbstractArrayStyle, ::Absent) = Absent() - -# Add another method to avoid ambiguity between the previous two. -Base.BroadcastStyle(::Absent, ::Absent) = Absent() - -broadcasted_sum(args) = - if isempty(args) - Absent() - elseif length(args) == 1 - args[1] - else - Base.broadcasted(+, args...) - end -Base.broadcasted(::Absent, ::typeof(+), args...) = - broadcasted_sum(filter(arg -> !(arg isa Absent), args)) - -Base.broadcasted(op::typeof(-), ::Absent, arg) = Base.broadcasted(op, arg) -Base.broadcasted(op::typeof(-), arg, ::Absent) = Base.broadcasted(Base.identity, arg) -Base.broadcasted(op::typeof(-), a::Absent) = Absent() -Base.broadcasted(op::typeof(-), a::Absent, ::Absent) = Base.broadcasted(op, a) - -Base.broadcasted(op::typeof(+), ::Absent, args...) = Base.broadcasted(op, args...) -Base.broadcasted(op::typeof(+), arg, ::Absent) = Base.broadcasted(op, arg) -Base.broadcasted(op::typeof(+), a::Absent, ::Absent) = Base.broadcasted(op, a) - -Base.broadcasted(op::typeof(*), ::Absent, args...) = Absent() -Base.broadcasted(op::typeof(*), arg, ::Absent) = Absent() -Base.broadcasted(op::typeof(*), ::Absent, ::Absent) = Absent() -Base.broadcasted(op::typeof(/), ::Absent, args...) = Absent() -Base.broadcasted(op::typeof(/), arg, ::Absent) = Absent() -Base.broadcasted(op::typeof(/), ::Absent, ::Absent) = Absent() - -function skip_materialize(dest, bc::Base.Broadcast.Broadcasted) - if typeof(bc.f) <: typeof(+) || typeof(bc.f) <: typeof(-) - if length(bc.args) == 2 && - bc.args[1] === dest && - bc.args[2] === Base.Broadcast.Broadcasted(Absent, ()) - return true - else - return false - end - else - return false - end -end - -Base.Broadcast.instantiate(bc::Base.Broadcast.Broadcasted{AbsentStyle}) = x - -end # module AbsentTypes diff --git a/src/NullBroadcasts.jl b/src/NullBroadcasts.jl new file mode 100644 index 0000000..a4e5ac6 --- /dev/null +++ b/src/NullBroadcasts.jl @@ -0,0 +1,81 @@ +module NullBroadcasts + +""" + NullBroadcasted() + +A `Base.AbstractBroadcasted` that represents arithmetic object. + +An `NullBroadcasted()` can be added to, subtracted from, or multiplied by any value in a +broadcast expression without incurring a runtime performance penalty. + +For example, the following rules hold when broadcasting instances of `NullBroadcasted`: +``` +1 + NullBroadcasted() == 1 +NullBroadcasted() + 1 == 1 +1 - NullBroadcasted() == 1 +1 * NullBroadcasted() == NullBroadcasted() +1 / NullBroadcasted() == NullBroadcasted() + ``` +""" +struct NullBroadcasted <: Base.AbstractBroadcasted end +Base.broadcastable(x::NullBroadcasted) = x + +struct NullBroadcastedStyle <: Base.BroadcastStyle end +Base.BroadcastStyle(::Type{<:NullBroadcasted}) = NullBroadcasted() + +# Specialize on AbstractArrayStyle to avoid ambiguities with AbstractBroadcasted. +Base.BroadcastStyle(::NullBroadcasted, ::Base.Broadcast.AbstractArrayStyle) = + NullBroadcasted() +Base.BroadcastStyle(::Base.Broadcast.AbstractArrayStyle, ::NullBroadcasted) = + NullBroadcasted() + +# Add another method to avoid ambiguity between the previous two. +Base.BroadcastStyle(::NullBroadcasted, ::NullBroadcasted) = NullBroadcasted() + +broadcasted_sum(args) = + if isempty(args) + NullBroadcasted() + elseif length(args) == 1 + args[1] + else + Base.broadcasted(+, args...) + end +Base.broadcasted(::NullBroadcasted, ::typeof(+), args...) = + broadcasted_sum(filter(arg -> !(arg isa NullBroadcasted), args)) + +Base.broadcasted(op::typeof(-), ::NullBroadcasted, arg) = Base.broadcasted(op, arg) +Base.broadcasted(op::typeof(-), arg, ::NullBroadcasted) = + Base.broadcasted(Base.identity, arg) +Base.broadcasted(op::typeof(-), a::NullBroadcasted) = NullBroadcasted() +Base.broadcasted(op::typeof(-), a::NullBroadcasted, ::NullBroadcasted) = + Base.broadcasted(op, a) + +Base.broadcasted(op::typeof(+), ::NullBroadcasted, args...) = Base.broadcasted(op, args...) +Base.broadcasted(op::typeof(+), arg, ::NullBroadcasted) = Base.broadcasted(op, arg) +Base.broadcasted(op::typeof(+), a::NullBroadcasted, ::NullBroadcasted) = + Base.broadcasted(op, a) + +Base.broadcasted(op::typeof(*), ::NullBroadcasted, args...) = NullBroadcasted() +Base.broadcasted(op::typeof(*), arg, ::NullBroadcasted) = NullBroadcasted() +Base.broadcasted(op::typeof(*), ::NullBroadcasted, ::NullBroadcasted) = NullBroadcasted() +Base.broadcasted(op::typeof(/), ::NullBroadcasted, args...) = NullBroadcasted() +Base.broadcasted(op::typeof(/), arg, ::NullBroadcasted) = NullBroadcasted() +Base.broadcasted(op::typeof(/), ::NullBroadcasted, ::NullBroadcasted) = NullBroadcasted() + +function skip_materialize(dest, bc::Base.Broadcast.Broadcasted) + if typeof(bc.f) <: typeof(+) || typeof(bc.f) <: typeof(-) + if length(bc.args) == 2 && + bc.args[1] === dest && + bc.args[2] === Base.Broadcast.Broadcasted(NullBroadcasted, ()) + return true + else + return false + end + else + return false + end +end + +Base.Broadcast.instantiate(bc::Base.Broadcast.Broadcasted{NullBroadcastedStyle}) = x + +end # module NullBroadcasts diff --git a/test/runtests.jl b/test/runtests.jl index 2fa98de..3eea262 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,15 +3,15 @@ julia --project using Revise; using TestEnv; TestEnv.activat(); include("test/runtests.jl") =# using Test -using AbsentTypes -using AbsentTypes: Absent +using NullBroadcasts +using NullBroadcasts: NullBroadcasted using Aqua using LazyBroadcast: lazy import Base.Broadcast: instantiate, materialize, Broadcasted, DefaultArrayStyle -@testset "Absent" begin +@testset "NullBroadcasted" begin x = [1] - a = Absent() + a = NullBroadcasted() @test typeof(lazy.(x .+ a)) <: Broadcasted{ DefaultArrayStyle{1}, Tuple{Base.OneTo{Int64}}, @@ -24,8 +24,8 @@ import Base.Broadcast: instantiate, materialize, Broadcasted, DefaultArrayStyle typeof(+), Tuple{Vector{Int64}}, } - @test lazy.(a .* x) isa Absent - @test lazy.(a ./ x) isa Absent + @test lazy.(a .* x) isa NullBroadcasted + @test lazy.(a ./ x) isa NullBroadcasted # + @test materialize(lazy.(a .+ x .+ 1)) == [2] @@ -38,30 +38,30 @@ import Base.Broadcast: instantiate, materialize, Broadcasted, DefaultArrayStyle @test materialize(lazy.(a .- 1 .- x)) == [-2] @test materialize(lazy.(1 .- a .- x)) == [0] @test materialize(lazy.(1 .- x .- a)) == [0] - @test materialize(lazy.(a .- a)) == Absent() + @test materialize(lazy.(a .- a)) == NullBroadcasted() @test materialize(lazy.(1 .- 1 .+ a .- a)) == 0 @test materialize(lazy.(x .- x .+ a .- a)) == [0] # * - @test materialize(lazy.(a .* x .* 1)) == Absent() - @test materialize(lazy.(a .* 1 .* x)) == Absent() - @test materialize(lazy.(1 .* a .* x)) == Absent() - @test materialize(lazy.(1 .* x .* a)) == Absent() + @test materialize(lazy.(a .* x .* 1)) == NullBroadcasted() + @test materialize(lazy.(a .* 1 .* x)) == NullBroadcasted() + @test materialize(lazy.(1 .* a .* x)) == NullBroadcasted() + @test materialize(lazy.(1 .* x .* a)) == NullBroadcasted() # / - @test materialize(lazy.(a ./ x ./ 1)) == Absent() - @test materialize(lazy.(a ./ 1 ./ x)) == Absent() - @test materialize(lazy.(1 ./ a ./ x)) == Absent() - @test materialize(lazy.(1 ./ x ./ a)) == Absent() + @test materialize(lazy.(a ./ x ./ 1)) == NullBroadcasted() + @test materialize(lazy.(a ./ 1 ./ x)) == NullBroadcasted() + @test materialize(lazy.(1 ./ a ./ x)) == NullBroadcasted() + @test materialize(lazy.(1 ./ x ./ a)) == NullBroadcasted() - @test_throws MethodError Absent() + 1 - @test_throws MethodError Absent() - 1 - @test_throws MethodError Absent() * 1 - @test_throws MethodError Absent() / 1 + @test_throws MethodError NullBroadcasted() + 1 + @test_throws MethodError NullBroadcasted() - 1 + @test_throws MethodError NullBroadcasted() * 1 + @test_throws MethodError NullBroadcasted() / 1 - @test materialize(Absent()) isa Absent + @test materialize(NullBroadcasted()) isa NullBroadcasted end @testset "Aqua" begin - Aqua.test_all(AbsentTypes) + Aqua.test_all(NullBroadcasts) end