I am not saying that traits/protocols/interfaces/typeclasses are necessary for OO, I am saying that they are sufficient.

The object-like construct in Clojure is an instance of a record or a type that implements a protocol. (A deftyped type can even contain mutable fields!) It doesn't matter where the methods live, they apply only to objects that implement the protocol. That's behavior and data bundled together. As far as I am concerned that is an object. A trait is just a different expression of an object from an instance of a class. The interface being defined separately changes nothing; interfaces/traits/typeclasses offer different advantages than subtype polymorphism and inheritance hierarchies.

Would you say CLOS isn't OO?

A trait isn't an object and neither is a class. An instance of a data type that implements a trait is as much an object as an instance of a class.

Rust, Haskell, and Clojure don't advertise support for OOP because in the common taxonomy an object is defined as "an instance of a class".

> Clojure/Script records don't have their methods following them around. You can define the functions for the protocol in another namespace, and then you have to require them separately. They don't tag along with the record.

> Again, the call is made to the protocol functions. Simply importing the record does not make these functions exist within your namespace, you need to require them. And these functions are not scoped within the record. They don't see the fields, they need to access them through the record, like any other function would. Nothing is special about these functions. They're just functions that know how to do something to a concrete datatype.

1. Nothing is special about methods in "OOP" languages either, aside from the dot operator and implicit this. There are object systems that have neither.

2. You have made a factual error here. An implemention of a protocol on a record or a deftyped type(is there a proper non-generic name for this?) DOES have implicit access to the fields of the record or type.

(defprotocol Container
(inventory [this])
(add [this thing]))

(defrecord Box [contents]
Container
(inventory [this] contents)
(add [this thing]
(update this :contents conj thing)))

boot.user=> (-> (->Box [1 2 3])
(add 4)
(inventory))
;; => [1 2 3 4]

The protocol method clearly has access to the contents field of the record, scoped by the record definition. The 'this' argument is a convenience to allow reconstituting the immutable object for return. You could just as easily have been forced to call the constructor again in order to reconstitute the object. If the record contained an atom it would happily carry around mutable state and there'd be no need to reconstitute anything.

Building on my previous example:

(deftype MutableBox [^{:volatile-mutable true} contents]
Container
(inventory [this] contents)
(add [this thing]
(set! contents (conj contents thing))))
boot.user=> (let [b (->MutableBox [1 2 3])]
(add b 4)
(inventory b))
;; => [1 2 3 4]

A type with mutable state, its fields in scope. This isn't even used.

You're correct that the call IS made to the protocol method. And yes, not having the protocol in scope prevents from calling the object's methods. One might even say that methods you don't know about and thus can't refer to are encapsulated. It's an extremely flexible object system--one that eschews mutable state and works well with a functional style and prefix syntax--but it's still an object system.

Object isn't a keyword in any of the languages we've mentioned. But we know how to find them and what they are. I don't understand why you can't see this one.