Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unthunk getindex and iterate on Composite objects #237

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/differentials/composite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Base.convert(::Type{<:NamedTuple}, comp::Composite{<:Any, <:NamedTuple}) = backi
Base.convert(::Type{<:Tuple}, comp::Composite{<:Any, <:Tuple}) = backing(comp)
Base.convert(::Type{<:Dict}, comp::Composite{<:Dict, <:Dict}) = backing(comp)

Base.getindex(comp::Composite, idx) = getindex(backing(comp), idx)
Base.getindex(comp::Composite, idx) = unthunk(getindex(backing(comp), idx))

# for Tuple
Base.getproperty(comp::Composite, idx::Int) = unthunk(getproperty(backing(comp), idx))
Expand All @@ -82,7 +82,16 @@ end
Base.keys(comp::Composite) = keys(backing(comp))
Base.propertynames(comp::Composite) = propertynames(backing(comp))

Base.iterate(comp::Composite, args...) = iterate(backing(comp), args...)
Base.iterate(comp::Composite) = iterate(comp, 1)

function Base.iterate(comp::Composite, state::Integer)
if state <= length(comp)
return (getindex(comp, state), state + 1)
else
return nothing
end
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or I can replace the entire code block with:

function Base.iterate(comp::Composite, args...)
    out = iterate(backing(comp), args...)
    if out isa Nothing
        return out
    else
        return (unthunk(out[1]), out[2])
    end
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I look at the benchmarks, the current code in the pull request gives me:

julia> @btime iterate(r, 2)
  47.447 ns (1 allocation: 32 bytes)

while the suggested code gives me:

julia> @btime iterate(r, 2)
  224.165 ns (2 allocations: 48 bytes)

Copy link
Member

Choose a reason for hiding this comment

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

my instinct is the suggested code is better. I will take a look into why it is slower

Copy link
Member

Choose a reason for hiding this comment

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

Poking at this, it looks like something funky is happening where it is deciding not to constant fold the state in the iterate.
I get on julia-master no allocations and instant on both.

but when timing: [x for x in $r] the getindex code has 1 allocation and the iterate backing code has 2 allocations.

Weird.
But i guess this is fine

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I've used the iterate approach then.

Copy link
Member

Choose a reason for hiding this comment

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

I mean the getindex appraoch is fine

Base.length(comp::Composite) = length(backing(comp))
Base.eltype(::Type{<:Composite{<:Any, T}}) where T = eltype(T)

Expand Down
4 changes: 4 additions & 0 deletions test/differentials/composite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ end
@test getproperty(Composite{Tuple{Float64,}}(2.0), 1) == 2.0
@test getproperty(Composite{Tuple{Float64,}}(@thunk 2.0^2), 1) == 4.0
@test getproperty(Composite{Tuple{Float64,}}(a=(@thunk 2.0^2),), :a) == 4.0
@test getindex(Composite{Tuple{Float64,}}(@thunk 2.0^2), 1) == 4.0
@test getindex(Composite{Tuple{Float64,}}(a=(@thunk 2.0^2),), 1) == 4.0

@test length(Composite{Foo}(x=2.5)) == 1
@test length(Composite{Tuple{Float64,}}(2.0)) == 1
Expand All @@ -65,6 +67,8 @@ end
# Testing iterate via collect
@test collect(Composite{Foo}(x=2.5)) == [2.5]
@test collect(Composite{Tuple{Float64,}}(2.0)) == [2.0]
@test collect(Float64, Composite{Tuple{Float64,}}(@thunk 2.0^2)) == [4.0]
@test collect(Float64, Composite{Tuple{Float64,}}(a=(@thunk 2.0^2),)) == [4.0]
Copy link
Member

Choose a reason for hiding this comment

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

We don't have tests for dictionary backed composites.
That is probably ok to continue to not have them here
for now.

THough I suspect iterating them will be weird, since they will iterate pairs and only the value, not the whole pair will need to be unthunked.
So perhaps it is worth making sure we do them right in this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

THough I suspect iterating them will be weird, since they will iterate pairs and only the value, not the whole pair will need to be unthunked.

Agreed.

We don't have tests for dictionary backed composites.
That is probably ok to continue to not have them here
for now.

I rather think that having the implementation of Composite{<:Dict, <:Dict} would be better here, since I think that approach of iterate might work better in general for Dict and Tuple's, as the next state for a Composite of Tuple's is state + 1 but may not so for Dict.

WDYT, shall I try that in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We usually get element, state = iterate(collection) so, we would get the state for free by using the iterate approach, but not from the getindex approach.

end

@testset "unset properties" begin
Expand Down