In my personal experience as a Dylan programmer and amateur compiler maintainer, here's what I liked and disliked about Dylan's types:
- Multiple inheritance and multiple dispatch have surprisingly clean semantics in Dylan, except for limited types. Yes, you really can have complicated multiple inheritance and runtime multiple dispatch in one language. It's not even that hard to implement, if you know the right tricks.
- Limited integer types were a mess, particularly when it came to multiple dispatch. You don't want two overrides of a function, one which applies to values from -1 to 7, and another which applies to values from 6 to 11. Similarly, limited collection types were supposedly used to implement typed collections, but it always felt like it was bolted on.
- Singletons had clean semantics but they made dispatch more expensive.
- Both type unions and subclass types worked quite well in practice.
- Dylan's design suffered from "sufficiently smart compiler syndrome" in several areas. This manifested as language features which were painfully slow in the general case, but which could run quite fast in a few special cases. This made it hard for users to build a good mental model of Dylan performance. It also meant that Dylan compilers needed to provide multiple implementations of certain features and choose between them at compile time.
Dylan was an exceptionally good language for its time, and I had a ton of fun using it. I keep meaning to try out Julia, which apparently inherits quite a few cool features from Dylan.