Skip to content

Conversation

@hyrodium
Copy link
Collaborator

This PR fixes the output values commented on #1122 (comment).

StaticArrays.jl v1.5.12

julia> zero(MVector{3,Any})::MVector{3,Any}
3-element MVector{3, Any} with indices SOneTo(3):
 0.0
 0.0
 0.0

StaticArrays.jl v1.5.13

julia> zero(MVector{3,Any})::MVector{3,Float64} # Float64 !== Any
3-element MVector{3, Float64} with indices SOneTo(3):
 0.0
 0.0
 0.0

After this PR

julia> using StaticArrays

julia> zero(MVector{3,Any})::MVector{3,Float64}
ERROR: MethodError: no method matching zero(::Type{Any})

I think the return value on v1.5.13 is problematic, but I'm not sure the return value on v1.5.12 is correct because zero(Any) throws an error.

@mateuszbaran
Copy link
Collaborator

I was thinking about going back to 1.5.12 behavior when we have Any element type explicitly provided but now I'm not sure, given that zero(Any) throws an error. I would appreciate another opinion on this.

@hyrodium
Copy link
Collaborator Author

@Jollywatt Do you have any thoughts on this?

src/arraymath.jl Outdated
@inline fill(val, ::Type{SA}) where {SA <: StaticArray} = _fill(val, Size(SA), SA)
@generated function _fill(val::U, ::Size{s}, ::Type{SA}) where {U, s, SA <: StaticArray}
@inline fill(val, ::SA) where {SA <: StaticArray{<:Tuple}} = _fill(val, Size(SA), SA)
@inline fill(val::U, ::Type{SA}) where {SA <: StaticArray} where U = fill(val, SA{U})
Copy link

@Jollywatt Jollywatt Feb 16, 2023

Choose a reason for hiding this comment

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

I don't pretend to know much about this code, but is it safe to add the type parameter U to SA{U} like that? (Line 38). What if SA = SVector{N,T} where {N,T} so that SA{U} = SVector{U,T} where T? Then the eltype U would be in the N slot instead of the T slot.

Would something like

@inline fill(val::U, ::Type{SA}) where {SA <: StaticArray{S}} where {U,S} = fill(val, SA{U})

at least ensure that the first type parameter of SA is filled, so that SA{U} fills the second slot? But then what happens when SA = SVector{3,Float64} has no slots to be filled?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree, applying U to an arbitrary subtype of StaticArray is not safe.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the comments! I have replaced SA{U} with Base.typeintersect(SA, AbstractArray{U}).

@Jollywatt
Copy link

Jollywatt commented Feb 16, 2023

I think having zeros(MVector{3,Any}) call zeros(Any) and then error is the most correct. You can always do zeros(MVector{3}) which defaults to Float64, mirroring zeros(dims...).

Less correct would be to return a MVector{3,Any} whose elements are Float64 zeros (or whatever the preferred fallback type is). It's correct in the sense that it returns an object of the type you asked for, but incorrect in the sense that it's not particularly good practice to have Any eltype, not to mention there already existing an obvious way of accomplish it with MVector{3,Any}(zeros(MVector{3,Float64})) if you really wanted to.

Definitely incorrect would be for zeros(MVector{3,Any}) to return a MVector{3,Float64}, which is not a subtype (because Julia types are "invariant, not covariant"). The proper way to have a "default eltype" is to implement zeros(::Type{MVector{S}}) where S = zeros(MVector{S,Float64}).

TL;DR I agree with this PR. Thanks @hyrodium for taking the time to make it!

@hyrodium hyrodium merged commit 2744c81 into JuliaArrays:master Feb 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants