Stream: helpdesk (published)

Topic: `convert` to convert eltype of collection, with `UnionAll`


view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 20:23):

Why this behavior?

julia> convert(AbstractFloat, 1)
1.0

julia> convert(Vector{T} where T, [1, 2])
2-element Vector{Int64}:
 1
 2

ulia> convert(Vector{AbstractFloat}, [1, 2])
2-element Vector{AbstractFloat}:
 1.0
 2.0

julia> convert(Vector{T} where T <: AbstractFloat, [1, 2])
ERROR: MethodError: no method matching (Vector{A} where A<:AbstractFloat)(::Vector{Int64})

view this post on Zulip Jakob Nybo Nissen (Jul 27 2021 at 20:34):

The second of your examples is just converting to Vector.

view this post on Zulip Mason Protter (Jul 27 2021 at 20:35):

Note as well that Vector{AbstractFloat} is completely different from Vector{T} where T <: AbstractFloat

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 20:40):

Right, (Vector{T} where T) === Vector

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 20:41):

I know the two types are different :

julia> [1.0, 2.0] isa Vector{AbstractFloat}
false

julia> [1.0, 2.0] isa (Vector{T} where T <: AbstractFloat)
true

julia> AbstractFloat[1.0, 2.0] isa Vector{AbstractFloat}
true

julia> AbstractFloat[1.0, 2.0] isa (Vector{T} where T <: AbstractFloat)
true

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 20:41):

but I am wondering why convert is not defined differently .

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 20:43):

(so that the fourth of my examples does what I expect)

view this post on Zulip Mason Protter (Jul 27 2021 at 20:58):

It basically just comes down to the fact that unionalls are hard to deal with

view this post on Zulip Mason Protter (Jul 27 2021 at 21:00):

e.g.

julia> convert(Complex{AbstractFloat}, 1+im)
1.0 + 1.0im

julia> convert(Complex{T} where T <: AbstractFloat, 1+im)
ERROR: MethodError: no method matching (Complex{T} where T<:AbstractFloat)(::Complex{Int64})
Closest candidates are:
  (::Type{T})(::T) where T<:Number at boot.jl:760
  (::Type{T})(::AbstractChar) where T<:Union{AbstractChar, Number} at char.jl:50
  (::Type{T})(::Base.TwicePrecision) where T<:Number at twiceprecision.jl:243
Stacktrace:
 [1] convert(#unused#::Type{Complex{T} where T<:AbstractFloat}, x::Complex{Int64})
   @ Base ./number.jl:7
 [2] top-level scope
   @ REPL[2]:1

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 21:01):

So, you don't think it would be inconsistent or wrong if those UnionAll MethodError instead worked?

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 21:01):

So long as convert(T, x) isa T

view this post on Zulip Mason Protter (Jul 27 2021 at 21:03):

I don't see any problem with it working. It seems to just be that someone defined some convenient methods, but decided that a fully general system here was too hard to do

view this post on Zulip Mason Protter (Jul 27 2021 at 21:03):

but I have no idea

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 21:10):

The situation that I am in is the following

I have an AbstractSet{CartesianIndex} that is backed by an Array{Bool}. Roughly in(elt, set) = set.array[elt]

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 21:12):

I also have defined a convertmethod from any AbstractSet to MySet. But if I convert a MySet to a MySet, then I just want to use the same underlying array. So I defined a convert method. but this convert method does not handle UnionAlls correctly. Because, as you said, that's hard.

view this post on Zulip Gustavo Goretkin (Jul 27 2021 at 21:31):

I think I can fix my situation by replacing the definition

Base.convert(::Type{T}, s::Foo) where {T <: Foo} = T(s.x)

with

Base.convert(::Type{T}, s::Foo) where {T <: Foo} = s ia T ? s : T(s.x)

like https://github.com/JuliaLang/julia/blob/2fbeef8d712ff9151370fd27a3ae07ea8b2e740d/base/array.jl#L614


Last updated: Oct 02 2023 at 04:34 UTC