Having recently seen a presentation of Clojure Protocols, I was quite impressed by the clean way extensions to existing types can be done this way. However, I was pretty sure to have already seen a similar way of doing this in some other language and after some time I found out it was Groovy Categories.
Compare this:
@Category(String) class StringCategory {
String lower() {
return this.toLowerCase()
}
}
use (StringCategory) {
println("TeSt".lower())
assert "test" == "TeSt".lower()
}
to the Clojure Protocol equivalent (taken from mikera's answer below and tested in ideone.com)
(defprotocol Lowerable
(lower [x]))
(extend-protocol Lowerable
String
(lower [s]
(.toLowerCase s)))
(println (lower "HELLO"))
my question is:
Disclaimer: I am a complete Clojure newbie!
Here's the rough equivalent Clojure code using protocols:
(defprotocol Lowerable
(lower [x]))
(extend-protocol Lowerable
String
(lower [s]
(.toLowerCase s)))
(lower "HELLO")
=> "hello"
The key distinctions to note about Clojure protocols (which I believe make it distinctive from the Groovy categories version)
lower
to work on a Rope. lower
is a proper first class function. So you can use it to build higher order abstractions (via higher order functions) that in turn will accept any arguments to which the Lowerable protocol has been extended. Clojure protocols are actually a fairly unique solution to the Expression Problem (linked video is pretty interesting). I think the closest equivalent to Clojure protocols in another language is actually Haskell type classes. Even then it's a bit of a stretch since Haskell is statically typed and Clojure is dynamically typed....
The Clojure feature he's referring to looks like:
(defprotocol StringMunging
(lower [this]))
(extend-protocol StringMunging
String
(lower [this]
(.toLowerCase this))
clojure.lang.Keyword
(lower [this]
(keyword (lower (name this)))))
user> (lower "TeSt")
"test"
user> (lower :TeSt)
:test
Implementations can be added for any type at any time - there's no need for the two implementations I wrote to cooperate in any way.
However, I don't understand the Groovy well enough to make any substantive comments on the question itself; I can only help describe the question's Clojure side.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With