- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
promote_op() fixes #16995
promote_op() fixes #16995
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,4 +63,16 @@ zero{T<:Number}(::Type{T}) = convert(T,0) | |
one(x::Number) = oftype(x,1) | ||
one{T<:Number}(::Type{T}) = convert(T,1) | ||
|
||
promote_op{R,S<:Number}(::Type{R}, ::Type{S}) = (@_pure_meta; R) # to fix ambiguities | ||
function promote_op{T<:Number}(op, ::Type{T}) | ||
S = typeof(op(one(T))) | ||
# preserve the most general (abstract) type when possible | ||
return isleaftype(T) ? S : typejoin(S, T) | ||
end | ||
function promote_op{R<:Number,S<:Number}(op, ::Type{R}, ::Type{S}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can write
and remove the ones for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I thought about that possibility too. In general though, I think it's considered more Julian to dispatch on types. That solution would be quite appealing to avoid ambiguities with the methods for comparison operators, but we still need to take care of ambiguities with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I now dispatching in types is more Julian. The problem here, if I understand Jeff right, is that any method that ignores op, that is The methods that have
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I suspect there's a type-instability somewhere. These tests already caught one in a corner case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Found a minimum reproducer: |
||
T = typeof(op(one(R), one(S))) | ||
# preserve the most general (abstract) type when possible | ||
return isleaftype(R) && isleaftype(S) ? T : typejoin(R, S, T) | ||
end | ||
|
||
factorial(x::Number) = gamma(x + 1) # fallback for x not Integer |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -222,10 +222,8 @@ minmax(x::Real, y::Real) = minmax(promote(x, y)...) | |
# for the multiplication of two types, | ||
# promote_op{R<:MyType,S<:MyType}(::typeof(*), ::Type{R}, ::Type{S}) = MyType{multype(R,S)} | ||
promote_op(::Any) = (@_pure_meta; Bottom) | ||
promote_op(::Any, T) = (@_pure_meta; T) | ||
promote_op(::Any, ::Any, ::Any...) = (@_pure_meta; Any) | ||
promote_op{T}(::Type{T}, ::Any) = (@_pure_meta; T) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this is still useful for doing things like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems to work without it. :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A potential issue to be aware of here is that e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not? Sounds like a case where you might want to store non- julia> x = Real.([1+0im])
1-element Array{Real,1}:
1
julia> x[1] = 1.5
1.5 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fine with adding it back, but then where should we place the limit? It's annoying that the fallback is slow in any case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just noticed that you have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fallback is not necessarily that slow --- in cases we can infer, there is no significant slowdown at all. However there is a chance we will lose some SIMD optimizations (though I haven't analyzed it in detail), so we should keep using the old approach for +, -, *, etc. I'm also ok with adding back this definition. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added it back, that's an important special case and it doesn't create any issues. |
||
promote_op{R,S}(::Any, ::Type{R}, ::Type{S}) = (@_pure_meta; promote_type(R, S)) | ||
promote_op(op, T, S, U, V...) = (@_pure_meta; promote_op(op, T, promote_op(op, S, U, V...))) | ||
|
||
## catch-alls to prevent infinite recursion when definitions are missing ## | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've removed this method when squashing since it doesn't make sense to use the output type as an input type now that the fallback to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense 👍. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, because |
||
|
||
|
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.
Why is this necessary? It seems like this will be slower e.g. for
Complex{BigFloat}
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.
Because of the type instability it creates for
Float16
:Maybe better write it as
T(2*zr*zi)
?(I wonder whether that promotion exception for
Float16
is really a good idea...)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.
Yes, I think
T(2*zr*zi)
seems like a better way to do it.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.
See #17259.