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

promote_eltype does not support objects that do not have elements (such as Types) #53287

Open
wheeheee opened this issue Feb 11, 2024 · 8 comments
Labels
domain:iteration Involves iteration or the iteration protocol

Comments

@wheeheee
Copy link

wheeheee commented Feb 11, 2024

I know this function is not exported, but after #51135, this function does not seem to produce the correctly promoted type for some inputs.
Due to the change, my example would try to promote the type DataType of Float64 with Float64, and produces Any where Float64 is expected, which doesn't seem to be the intention of the function.

julia> b = [1,2,3]
3-element Vector{Int64}:
 1
 2
 3

julia> Base.promote_eltype(b, 1.0, Float64)
Float64

julia> Base.promote_eltype(b, 1.0, Float64, Float64)
Any

I believe a simple change from the offending line

promote_eltype(v1::T, vs::T...) where {T} = eltype(T)

to this, replacing T with v1, would suffice.

promote_eltype(v1::T, vs::T...) where {T} = eltype(v1)
@ctkelley
Copy link

I'd like this to be exported if it can be done with reasonable effort. If I can promote a Float32 to a Float64 without allocating for the entire Float64, that'd be really cool. I understand that I may be asking the impossible (what if the Float32 is between some other stuff in memory?). @wheeheee, what is your use case for this?

@wheeheee
Copy link
Author

Nothing spectacular, just type promotion to allocate output arrays, e.g. Base.promote_eltype(b, a, T, S)

@vtjnash
Copy link
Sponsor Member

vtjnash commented Feb 12, 2024

Hmm, neither of those results are particularly satisfying, but it is not particularly supposed to mean anything either, since types are not iterable, they don't have an eltype themselves. It is sort of just an accident that a mixed group here works out this way since code is not supposed to end up here.

Perhaps you meant to call promote_type or something like that?

@vtjnash
Copy link
Sponsor Member

vtjnash commented Feb 12, 2024

Note that in either case (with the current method, your method, or the old method), it gets the incorrect result for Types, as it tries to treat them as Types instead of Kinds

julia>  Base.promote_eltype(b, 1.0, Float64, String) # with your method
Float64

julia> Base.promote_eltype(b, 1.0, Float64, Float32) # without either method
Float64

In that regard this new method seems most correct, as it actually treats Types as values (returning Any for their promotion).

@vtjnash vtjnash added the domain:iteration Involves iteration or the iteration protocol label Feb 12, 2024
@vtjnash vtjnash changed the title Inconsistency with promote_eltype promote_eltype does not support objects that do not have elements (such as Types) Feb 12, 2024
@wheeheee
Copy link
Author

wheeheee commented Feb 12, 2024

Hmm, neither of those results are particularly satisfying, but it is not particularly supposed to mean anything either, since types are not iterable, they don't have an eltype themselves. It is sort of just an accident that a mixed group here works out this way since code is not supposed to end up here.

But types T <: Number and T <: AbstractArray are defined to have an eltype, as in

julia> eltype(Vector{Float64})
Float64

julia> eltype(Float64)
Float64

@vtjnash
Copy link
Sponsor Member

vtjnash commented Feb 12, 2024

The values of those types are defined to have eltypes, but the types themselves do not:

julia> eltype(Type{Float64})
Any

julia> eltype(typeof(Float64))
Any

@wheeheee
Copy link
Author

wheeheee commented Feb 12, 2024

Yes, my fix was just wrong. Nevertheless, I think most people expect promote_eltype(vs...)'s output to be equivalent to promote_type(map(eltype, vs)...), as it is in the original implementation, which is in general not always consistent with promote_type(map(eltype ∘ typeof, vs)...), in at least the case that eltype is defined for a type, and I think

promote_eltype(v1::T, vs::T...) where {T} = eltype(T)

does the latter. Isn't promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) enough to fix #51011?

@vtjnash
Copy link
Sponsor Member

vtjnash commented Feb 12, 2024

I am not sure why people should expect anything of an undocumented function that will never get called with those arguments. Where it is used, it is used to compute the result type of indexing into the object or iterating it. Passing Type arguments doesn't permit those operations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:iteration Involves iteration or the iteration protocol
Projects
None yet
Development

No branches or pull requests

3 participants