Complex{AbstractFloat}: Not working as intended

I want to write a type-generic function with signature
foo(parameter::Complex{AbstractFloat})

such that I can use it like

Input = 42 + 42*im
foo(convert(Complex{Float32}, Input))
foo(convert(Complex{Float64}, Input))
foo(convert(Complex{BigFloat}, Input))

this works just fine for realtypes, i.e., without the Complex{}. But for complex types, I get the error:

ERROR: LoadError: MethodError: no method matching foo(::ComplexF64)
Closest candidates are:
  foo(::Complex{AbstractFloat})

I guess there is a shortcut for Complex{AbstractFloat}, but I couldn’t find it in the docs.

note the <:

1 Like

Use foo(parameter::Complex{<:AbstractFloat}) or foo(parameter::Complex{T}) where T<:AbstractFloat
The reason your original signature does not work is that

julia> Complex{Float64} <: Complex{AbstractFloat}
false

See Types · The Julia Language and in particular the yellow box in that section :slight_smile:

7 Likes

Note that it’s often unnecessary to type signatures like foo(parameter::Complex{<:AbstractFloat}).
Is your function really only correct for AbstractFloat components in the Complex? Most code, unless very low level, would likely work for any Complex number, such that foo(parameter::Complex) would be sufficient. Is it really not sensible to want to call foo(3+4im)? For that matter, foo(6) might still make sense and you should only require Number.

If the number needs to be float-backed at some point in the function, using float(parameter) in that position should be all you need. Although in most cases automatic promotion should make even that unnecessary.

Keeping function signatures maximally generic is what makes Julia composable and powerful. Type parameters in functions should mainly be used for dispatching to different versions of functions. You should aim to use duck typing wherever sensible.

1 Like