Search code examples
clojureduck-typing

Type system in Clojure


Is the "programming to abstractions" principle in Clojure the same as duck typing? If not, what are the differences?

Here is a quote from http://www.braveclojure.com/core-functions-in-depth/:

The reason is that Clojure defines map and reduce functions in terms of the sequence abstraction, not in terms of specific data structures. As long as a data structure responds to the core sequence operations (the functions first, rest, and cons, which we’ll look at more closely in a moment), it will work with map, reduce, and oodles of other sequence functions for free. This is what Clojurists mean by programming to abstractions, and it’s a central tenet of Clojure philosophy.

I think of abstractions as named collections of operations. If you can perform all of an abstraction’s operations on an object, then that object is an instance of the abstraction. I think this way even outside of programming. For example, the battery abstraction includes the operation “connect a conducting medium to its anode and cathode,” and the operation’s output is electrical current. It doesn’t matter if the battery is made out of lithium or out of potatoes. It’s a battery as long as it responds to the set of operations that define battery.

Data types are identified to be part of the abstract class by behaviour ("responds to"). Isn't this the essence of duck typing? Thanks for input.


Solution

  • Is the "programming to abstractions" principle in Clojure the same as duck typing?

    No.

    • Clojure is defined in terms of Extensible Abstractions.
    • These are Java interfaces ...
    • ... which are used most prominently to define the core data structures.

    For example, the sequence abstraction is defined by clojure.lang.ISeq:

    public interface ISeq extends IPersistentCollection {
      Object first();
      ISeq next();
      ISeq more();
      ISeq cons(Object o);
    }
    

    Any class that implements ISeq is accepted by Clojure as a sequence (whether is behaves properly is another matter). For example, lists and lazy sequences do so, and are treated impartially as sequences. Contrast this with classic Lisp, where a different set of functions apply to each.

    And we have several different implementations of vectors

    • the core clojure vector type;
    • rrb vectors;
    • fast small vectors.

    I could go on. (Actually, I can't. I don't know enough!)