5 ms·
The last example in the post doesn't really show off the power of protocols (well, it does, but it's buried a bit deep). In your example (and in David's) the i
by stevelosh 15y ago
The last example in the post doesn't really show off the power of protocols (well, it does, but it's buried a bit deep).
In your example (and in David's) the implementation of the slice function is locked into the definition of that function. The real power of protocols comes when you use them to decouple this.
Here's an example (in Clojure because I don't know the names of the types Clojurescript uses off the top of my head, but the ideas are the same):
(defprotocol Sliceable
(slice [this start end]))
(extend-protocol Sliceable
clojure.lang.PersistentVector
(slice [this start end]
(subvec this start end)))
(extend-protocol Sliceable
java.lang.String
(slice [this start end]
(.substring this start end)))
(slice "Hello" 0 2)
(slice [:a :b :c] 0 2)
Here we've defined a protocol called "Sliceable" and added support for it to two built-in classes. We've done so in a safe way -- the "slice" function isn't visible anywhere outside this namespace unless you import it.
Now say you come along and want to use my little "slicing" library to carve up someone else's data structures. You can add support without touching my files or their files:
(ns foo
(:use fancylists [:only (FancyList)])
(:use stevelosh.slicing [:only (Sliceable)]))
(extend-protocol Sliceable
FancyList
(slice [this start end]
(... slice up the fancylist here ...)))
And now in another file you want to slice up a FancyList:
(ns bar
(:use fancylists [:only (FancyList)])
(:use stevelosh.slicing [:only (slice)]))
(def my-fancy-list (FancyList 1 2 "cat" "dog"))
(slice my-fancy-list 2 4)
; => (a FancyList containing "cat" and "dog")
Now you've added support for some random person's FancyList library to my Slicing library, without touching the code in either of them. This is the really cool part about Protocols.
This concept actually does appear in David's post when he adds support for his Slice type to the IFn protocol, but it's a bit obscured by the fact that function calling has some syntactic sugar so you don't have to write -invoke.
- jashkenas 15y agoYes, that's a much nicer protocol demo. When you end up writing switches on types in your protocol implementation ... it fails to demonstrate any particular advantage over switching on types in a simple function.
- swannodette 15y agoGlad you think so. Thanks stevelosh. I avoided taking the extra step since I was writing for people of varying levels of familiarity with JavaScript, CoffeeScript, and ClojureScript. But perhaps I'm a bit old school - I explained something with a minor flaw to leave something for the reader to solve :)
- iamgilesbowkett 15y agoAs a busy person who finds your ideas interesting but has no time for riddles, I would really appreciate it if you could at least drop some hints here.
- nxn 15y agoIn this context this looks somewhat similar to Haskell's type classes, and maybe to a lesser, or greater(?), extent C#'s extension methods. The latter I guess lacks the concept of the "protocol" as extensions methods live at the namespace level in a way (they're wrapped in a static class, but this is somewhat meaningless). Then again, the protocol concept here seems to be mainly used for the same purpose of having a namespace for storing implementations and also importing them?
- duelin_markers 15y agoAn important difference between Clojure protocols and C# extension methods is that protocols are one of the tools for polymorphism in Clojure, the (only?) other being multi-methods, whereas extension methods are just syntactic sugar for static methods and therefore aren't polymorphic.
- Mikera 15y agoClojure also supports prototype-based polymorphism via Associative objects, inheritance polymorphism via Java interop/proxy, interface-based polymorphism with deftype/defrecord, polymorphism via abstraction (see the Clojure sequence operations for example, which use Java interfaces under the hood but you'd never know....). And probably a few more I can't remember right now..... there's a reason Rich Hickey calls it "polymorphism a la carte".
- jpatte 15y agoWhat seems really interesting to me here is the ability to extend an existing class by implementing an interface (instead of a set of extension methods), and therefore becoming able to cast any instance of this type as an instance of this interface. I'd love to have that in C#, as it would simplify (if not eliminate) the creation of wrappers around types you don't own.