Union splitting over abstract types

If I have an abstract type X whose only subtypes are A and B, will union-splitting kick in and make dispatching over an object inferred as X as efficient as dispatching over one inferred as Union{A, B}?

I am not 100% sure, but from my earlier testing, I don’t think it happens.

1 Like

No, it doesn’t. The reason is that we would then have to invalidate code when you add another subtype of X, which is not something we can currently track in the system (nor is it clear that it’s desirable).

10 Likes

I’m biased, but I really like the approach described in
https://timholy.github.io/SnoopCompile.jl/stable/snoopr/#Inferrable-field-access-for-abstract-types-1

2 Likes

I don’t understand how that would help. My concern is mainly with

struct ClassRoom
    people::Vector{Union{Student, Teacher}}
end

having better runtime performance than

struct ClassRoom
    people::Vector{AbstractClassMember}
end

On a side note, it’s cool that

struct ClassRoom
    people::Vector{subtypes(AbstractClassMember)...}
end

works. With the caveat that it doesn’t support new types of course.

Yeah, it depends on what you’re doing. Basically what it helps with is if people has fields and you write code that accesses those fields: even if it has no idea what kind of object people is, inference now knows what types of objects you’re pulling out of its fields.

I’ve been using this trick in quite a few places in Base and the stdlibs (for LibuvStream, LibuvServer, AbstractPipe, LibGit2.AbstractGitObject, and LibGit2.GitObject) and it’s really cleaned up a lot of inference problems. But these are all cases where the abstract type is essentially a field-container and you don’t do a ton of stuff with the container itself.

2 Likes