Interfaces in Clojure
In Clojure, we don’t have interfaces in the same way as Go, but we can use protocols to achieve similar functionality. Here’s how we can implement the geometric shapes example:
(ns geometry
(:require [clojure.math :as math]))
;; Define a protocol for geometric shapes
(defprotocol Geometry
(area [shape])
(perim [shape]))
;; Implement the protocol for rectangles
(defrecord Rectangle [width height]
Geometry
(area [this] (* (:width this) (:height this)))
(perim [this] (* 2 (+ (:width this) (:height this)))))
;; Implement the protocol for circles
(defrecord Circle [radius]
Geometry
(area [this] (* Math/PI (:radius this) (:radius this)))
(perim [this] (* 2 Math/PI (:radius this))))
;; A function to measure any shape that implements the Geometry protocol
(defn measure [shape]
(println shape)
(println (area shape))
(println (perim shape)))
(defn -main []
(let [r (->Rectangle 3 4)
c (->Circle 5)]
(measure r)
(measure c)))In this Clojure code:
We define a
Geometryprotocol withareaandperimmethods, which is similar to thegeometryinterface in the original code.We use
defrecordto defineRectangleandCircletypes, which implement theGeometryprotocol. This is analogous to defining structs and implementing methods for them in Go.The
measurefunction takes any shape that implements theGeometryprotocol, demonstrating polymorphism.In the
-mainfunction, we create instances ofRectangleandCircleand callmeasureon them.
To run this program:
$ clj -M geometry.clj
#geometry.Rectangle{:width 3, :height 4}
12
14
#geometry.Circle{:radius 5}
78.53981633974483
31.41592653589793This Clojure implementation achieves the same functionality as the original Go code, using protocols instead of interfaces, and records instead of structs. The measure function demonstrates how we can work with any shape that implements the Geometry protocol, showcasing Clojure’s polymorphism capabilities.
Clojure’s protocols provide a flexible way to define abstract behaviors that can be implemented by different types, similar to interfaces in other languages. This allows for polymorphic behavior while maintaining the benefits of Clojure’s functional programming paradigm.