Make an existing type a child of an abstract type

Is it possible to make an existing type a child of an abstract type?
Something like this?

using StaticArrays
abstract type Abstract3DVector end
struct type SVector{3} <: Abstract3DVector end

Unfortunately it does not work:

julia> SVector{3} <: Abstract3DVector
false

No. But you can wrap it and type the wrapper.

Heres a toy example, AbstractVector3D should actualy be <: AbstractArray{T,N}:

abstract type Vector3D <: AbstracVector3D
    data::SVector{3}
end

Base.parent(a::Vector3D) = a.data

Then you can write out all the SVector methods you need manually like:

getindex(a::Vector3D, I...) = getindex(parent(a), I...)

Or use the @forward macro in Lazy.jl to do them all at once. I can’t recall exactly what you need here.

But first you should have a good reason why you need such specialized types.

2 Likes

Maybe related (and also unsolved): https://github.com/JuliaArrays/StaticArrays.jl/issues/592

1 Like

This seems like a situation where a trait might be more appropriate than an abstract type. Traits, unlike abstract types, are easy to add to any type, even after that type has been defined. For example:

julia> struct ExistingType
         x::Int
       end

julia> is_cool(::Type{T}) where {T} = false
is_cool (generic function with 1 method)

julia> is_cool(::Type{ExistingType}) = true
is_cool (generic function with 2 methods)

julia> function check_coolness(x::T) where {T}
         if is_cool(T)
           println("Cool!")
         else
           println("nope")
         end
       end
check_coolness (generic function with 1 method)

julia> check_coolness(ExistingType(1))
Cool!

In this case, the is_cool is just a function that returns a boolean, and we can use that inside an if statement to check properties of the type. Note that Julia is pretty clever about propagating types and constants, so the actual if statement is optimized away in the resulting code:

julia> @code_warntype check_coolness(ExistingType(1))
Body::Nothing
1 ─ %1 = invoke Main.println("Cool!"::String)::Core.Compiler.Const(nothing, false)
└──      return %1 

If you want your trait to help control method dispatch, then you can use “Holy-traits” and define new types to represent the trait of interest:

julia> struct IsCool end
                                                                                                                                                                                                                                                                                                                                      
julia> struct NotCool end

julia> coolness(::Type{T}) where {T} = NotCool()
coolness (generic function with 1 method)

julia> coolness(::Type{ExistingType}) = IsCool()
coolness (generic function with 2 methods)

julia> check_coolness_trait(x::T) where {T} = check_coolness_trait(coolness(T), x)
check_coolness_trait (generic function with 1 method)

julia> check_coolness_trait(::IsCool, x) = println("$x is cool")
check_coolness_trait (generic function with 2 methods)

julia> check_coolness_trait(::NotCool, x) = println("$x is not cool")
check_coolness_trait (generic function with 3 methods)

And we can use it like so:

julia> check_coolness_trait(1)
1 is not cool

julia> check_coolness_trait(ExistingType(1))
ExistingType(1) is cool

3 Likes