-
Notifications
You must be signed in to change notification settings - Fork 148
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
Remove final explicit uses of Inference.return_type #330
Conversation
Codecov Report
@@ Coverage Diff @@
## master #330 +/- ##
==========================================
- Coverage 93.14% 93.13% -0.01%
==========================================
Files 37 37
Lines 2654 2651 -3
==========================================
- Hits 2472 2469 -3
Misses 182 182
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Out of curiousity, was does it do for things that are like Union{Null, T}
on v0.6 and v0.7?
src/broadcast.jl
Outdated
return quote | ||
@_inline_meta | ||
@inbounds return similar_type($first_staticarray, $newtype_expr, Size($newsize))(tuple($(exprs...))) | ||
elements = tuple($(exprs...)) | ||
@inbounds return similar_type($first_staticarray, eltype(elements), Size($newsize))(elements) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eltype(::Tuple)
is (or at least, was) a bit pesimised. In util.jl
there is a function called promote_tuple_eltype
that I originally wrote for this kind of stuff. I'm not sure what the current status on which one is better (and it's possible that reducing via typejoin
is a better choice here than promote_type
anyway??)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. I didn't give type reduction a lot of thought TBH, because I'm expecting all the elements to have the same inferred type (How could they not? They're all copies of the same expression unrolled many times.)
In the known bad cases which required the broadcast workaround, the issue seems to be in inferring the type of the element tuple, rather than in the typejoin
step.
An excellent question. On this branch we have (for both 0.7 and 0.6): julia> broadcast(+, SVector(1.0,null), SVector(2.0,3.0))
2-element SVector{2,Any}:
3.0
null Where as, with current StaticArrays master, we have julia> broadcast(+, SVector(1.0,null), SVector(2.0,3.0))
2-element SVector{2,Union{Float64, Nulls.Null}}:
3.0
null which is arguably better (though probably neither is useful on 0.6). I wonder whether it's a problem with the way I've done things on this branch, or a flaw in the "use I guess, if nothing else, what I've done here is to bring these methods in line with the rest of StaticArrays, where we generally infer the static array type from the element tuple. I'm now not quite sure whether to merge this! |
If I replace julia> broadcast(+, SVector(1.0,null), SVector(2.0,3.0))
2-element SVector{2,Union{Float64, Nulls.Null}}:
3.0
null which is an improvement, i think. It's still not type inferrable though. What do you think about |
Ok, I've pushed a change to use The broadcast workaround doesn't seem necessary on 0.7, so presumably the associated inference problem has been sorted out in Base. |
Yeah, |
Hmm, looks like I've broken the test case which asserts that StaticArrays shares the Base behaviour when you have an array of julia> Number[2, 2.0, 4//2, 2+0im] .+ 2
4-element Array{Number,1}:
4
4.0
4//1
4+0im With Honestly, I'm not sure this really matters, and perhaps I could just remove that test case: having an |
16ee6bc
to
98a7e1d
Compare
With this approach based on the eltype of tuple of computed elements, we get the correct dynamic result independently of whether inference can infer the return type. This fixes some of the residual issues from #198.
This allows `Union`s as the output type for mixtures of `Null` and numeric types, which can be more efficient than the `Any` you'd get from typejoin, at least in 0.7. It also makes `SVectors` of abstract types like `Number` become concrete after numerical operations, which is inconsistent with base, but probably not a problem for realisitc uses of this package.
98a7e1d
to
0a78009
Compare
I have this feeling that |
Yes, I was just about to suggest that we might need our own purpose built Regarding promotion vs typejoinn - we do already use promotion in similar circumstances: julia> SVector(1, 1.0)
2-element SVector{2,Float64}:
1.0
1.0 It's arguably a similar kind of thing, and certainly much more predictable and useful behavior from a performance standpoint. (We follow Base here, which has the same array construction conventions.) I do think that it would be nice if arithmetic on a = SVector(1,null)
# inferred: a::SVector{2,Union{Int,Null}}
# runtime: a::SVector{2,Union{Int,Null}}
elements = (1 + a[1], 1 + a[2])
# inferred: elements::Tuple{Union{Int, Null},Union{Int, Null}}
# runtime: elements::Tuple{Int,Null}
newtype = eltype(elements)
# inferred: newtype::Type
# runtime: newtype::Union{Int,Null}
newvec = similar_type(a, newtype)(elements)
# inferred: newvec::SVector{2,_} where _
# runtime: newvec::SVector{2,Union{Int,Null}} [edit - fixed mistakes] Unfortunately, inferring |
I think the time for this has finally come. See #495, #493 and JuliaLang/julia#28981. I think I'll make an updated version of this PR this soon. Upon reflection on what julia> map(-, Union{Float64, Int}[1, 1.0])
2-element Array{Real,1}:
-1
-1.0 |
Implemented by #503 |
With this approach based on the eltype of tuple of computed elements, we get the correct dynamic result independently of whether inference can infer the return type.
This fixes #198, and partially addresses #329.
With the addition of a workaround hack to override a very specific version of
broadcast
in a very specific way it also fixes #329.