function somemethod(x::Int, y::Int)
function somemethod(x::Int, y::Float64)
function somemethod(x::Float64, y::Float64)
Multiple dispatch is available at least in Common LISP, though I guess that's not considered particularly mainstream.
function somemethod(x::Int, y::Int)
function somemethod(x::Int, y::Float64)
function somemethod(x::Float64, y::Float64)
Multiple dispatch is available at least in Common LISP, though I guess that's not considered particularly mainstream.
It also exists in R, but again, is optional (and slow), and is therefore mostly unused, which limits its usefulness, making it less used, etc. etc.
In Julia, it is default, so everything participates in multiple dispatch. It completely pervades the language, which is what makes it so useful.
(The fact that you can have static dispatch on dynamic types is a pretty subtle point that hurts my head, but the upshot is that you get semantically dynamic dispatch with static performance as an optimization.)
You can find examples where operator overloading and multiple dispatch actually behaves differently and gives different answers, but the comparison works as a first order approximation.
If the language is single dispatch though, animal1.f(animal2) will accurately call the Cat or Dog method for the first argument (before the dot), but the second argument will work like above, it will call the Animal version and not the Cat or Dog ones. If you want a method to call Cat or Dog method based on runtime information you'd have to redispatch on runtime within f(Animal), which is basically a pattern known as Visitor Pattern [1].
In Julia (and multiple dispatch languages) defining f(Cat, Dog) and f(Animal, Animal) means that even when I call f(animal1, animal2) the compiler will convert to the runtime values and if the first animal is Cat and the second is Dog it will call the first method (as a form of specialization) and otherwise it will go for f(Animal, Animal) (which is the more general method). And the Julia compiler is really good at inferring runtime types at compile time, so even though it's runtime values it's still static dispatch (that's why it's also fast).