In this case UnionBase is not ad hoc: you had to declare a name for it up front. Ad hoc means you can write the union type wherever types can be written. For example, it’s not possible to write this:
Yes, this is the basic benefit of typed languages. I would not want to refactor a 20 year old code base without type safety - I do want to know what's being returned.
I also want my tools to know what's being returned, as well as my compiler.
Yes, but it doesn't really change the way you could handle it, and what I wanted to point out is that it actually helps with type safety, enabling you to create total functions.