They don't avoid them, they embrace them using the pattern match syntax. But functional programming is largely orthogonal to object oriented programming, so absolute majority of "functional" languages are also object oriented¹, including clojure. In fact clojure's multi-methods are even better than plain virtual methods of Java, because they can dynamically dispatch on types of multiple arguments, not just the first one. There is one purely functional language that does not have dynamic polymorphism, Haskell. In Haskell you can define multi-methods via type classes, but the types are resolved at compile time. To have varying types at runtime, you have to create a union type and you either have to write the function with pattern match (which is like the if chain, but with more convenient syntax) or ask the compiler to derive the method by composing the methods of the constituent types. Or use the GHC `forall` extension. --- ¹ By object-oriented I mean that the language has some form of dynamic polymorphism with dispatch based on actual runtime type. Many new languages only have “trait-based” polymorphism where only interfaces can be inherited; I count that as object-oriented and for purpose of this answer it is sufficient.