With records, Clojure has introduced a way to create struct-like objects, while avoiding some of the problems encountered in object orientation. Records don’t hide their data behind custom interfaces, but instead partake in the abstractions that Clojure’s own data types are built on, so that code can treat treat a record like a regular Clojure data type.
Protocols are Clojure’s take on abstract interfaces. They make it possible to extend preexisting types to new methods, and extend preexisting methods to new types, thus avoiding the expression problem.