In practice, I've found that kind of use case for polymorphic dispatch to not be especially common — meanwhile, most OO languages strongly encourage making everything objects. There's absolutely a time and place for a good abstract interface, but it's always struck me that classes are overused in general.
That's why I really appreciate the go/rust model, where you can tack interfaces and methods onto structs if you want to, but there's no pressure to do so.
The main reason why OO languages typically make everything objects is that having only one kind of type greatly simplifies the programming language and the experience of programming in it.
There are only three common languages that are OO with a few non-object types: C++, Objective-C and Java. This feature is universally recognized as a serious wart in all three of them. It creates all sorts of little edge cases that you need to learn to program around.
Indeed... in Java this is reasonably clear, but I've never found I have a problem in C++. I suppose if you're inheriting from your template argument and you template on an int? Seems awfully contrived and useless though.
That's why I really appreciate the go/rust model, where you can tack interfaces and methods onto structs if you want to, but there's no pressure to do so.