Classes and protocols
spork-lang 0.6.0
Define Python-compatible classes and protocol-based polymorphism.
Spork classes compile to Python classes, while protocols provide explicit runtime dispatch over participating types. This page defines their declarations, methods, fields, properties, and extension forms.
Classes#
Basic Class Definition#
defclass takes a class name, an optional vector of base classes, and a body of methods, fields, or class-level definitions. An empty base vector ([]) declares no explicit base class.
(defclass Point []
(defn __init__ [self x y]
(set! self.x x)
(set! self.y y))
(defn distance [self other]
(let [dx (- other.x self.x)
dy (- other.y self.y)]
(** (+ (* dx dx) (* dy dy)) 0.5))))
Inheritance#
(defclass ColorPoint [Point]
(defn __init__ [self x y color]
(.__init__ (super) x y) ; (super).__init__(x, y)
(set! self.color color)))
Decorators#
Decorator metadata appears after defn or defclass and before the function or class name. External Python decorators must be imported; Python built-ins such as staticmethod and classmethod are already available.
(ns example.classes
(:import [dataclasses :refer [dataclass]]))
(defclass ^dataclass Person []
(field name str)
(field age int 0))
(defclass Counter []
(defn ^staticmethod create []
(Counter))
(defn ^classmethod from-value [cls value]
(let [c (cls)]
(set! c.value value)
c)))
Class Fields#
Inside any class, (field name type) emits an annotated field without a default, while (field name type default) includes a default. This is especially useful for dataclasses. field is a Spork class form; it does not need to be imported from dataclasses.
(ns example.config
(:import [dataclasses :refer [dataclass]]))
(defclass ^dataclass Config []
(field host str "localhost")
(field port int 8080)
(field debug bool false))
Protocols#
Protocols provide polymorphic dispatch similar to Clojure protocols or type classes.
Defining Protocols#
(defprotocol IShape
"Protocol for geometric shapes."
(area [self])
(perimeter [self]))
; Structural protocol (duck typing based on methods)
(defprotocol ^structural ICloseable
(close [self]))
Extending Types#
; Extend a type to implement a protocol
(extend-type Circle
IShape
(area [self] (* 3.14 self.radius self.radius))
(perimeter [self] (* 2 3.14 self.radius)))
; Extend multiple types for one protocol
(extend-protocol IShape
Rectangle
(area [self] (* self.width self.height))
(perimeter [self] (* 2 (+ self.width self.height)))
Square
(area [self] (* self.side self.side))
(perimeter [self] (* 4 self.side)))
Using Protocols#
; Call protocol methods
(area my-circle)
(perimeter my-rectangle)
; Explicit extensions also register the type with the protocol ABC
(isinstance my-object IShape)