(inc altitude)

"JS-CLOS"

#inst "3912-03-22T15:00:00.000-00:00"
"ympbyc"
"

This is a brief introduction to JS-CLOS. JS-CLOS is a JavaScript library that features multiple inheritance, multiple dispatching and multiple constructors. Multiplicating everything, you get multiple happinesses ;)

JS-CLOS

What is CLOS in the first place?

Common Lisp Object System (CLOS) is a way to do OOP in Lisp. In CLOS, objects are basically just mutable hash-tables holding values. Methods are not included in these hash-tables. Instead, what's called methods in CLOS are implemented as generic functions. Generic functions are functions that work on multiple classes, a combination of them.

Heres a sample code in Tklos, a variant of CLOS.

;; a class representing instruments
 (define-class <instrument> () ())

 ;; flute inherits from <instrument>
 (define-class <flute> (<instrument>) ())

 ;; musicians have a name and the instrument they play
 (define-class <musician> ()
   ((instrument :init-keyword :instrument)
    (name       :init-keyword :name)))

 ;; flute players inherits from <musician> and they play the flute
 (define-class <flute-player> (<musician>)
   ((instrument :init-value (make <flute>))))

 ;; generic function can-play?
 (define-generic can-play?)

 ;; a flute-player can play the flute
 (define-method can-play? ((fp <flute-player>) (f <flute>))
   #t)
 ;; a flute-player can not play other instruments
 (define-method can-play? ((fp <flute-player>) (i <instrument>))
   #f)

 ;; a musician can play an instrument when the musician has the instrument
 (define-method can-play? ((m <musician>) (i <instrument>))
   (is-a? (slot-ref m 'instrument) i))

Implementing it in JS

I found a repository named JS-CLOS on github that someone in Russia has abandoned a year ago unfinished. I forked and made some commits to it. I ended up rewriting almost every line and believe I've come up with a usable solution. Here's what's equivalent to the code above in JS-CLOS. The code is written in CoffeeScript.

## a class representing instruments
instrument = define_class()

## flute inherits from instrument
flute = define_class [instrument]

## musicians have a name and an instrument they play
musician = define_class [], (x) ->
  (slot_exists x, 'instrument', instrument) && (slot_exists x, 'name', 'string')

## flute players inherits from musician and they play the flute
flute_player = define_class [musician], (x) ->
  x.instrument = make flute
  true

## generic function can_play
can_play = define_generic()

## a flute_player can play the flute
define_method can_play, [flute_player, flute], -> true

## a flute-player can not play other instruments
define_method can_play, [flute_player, instrument], -> false

## a musician can play an instrument when the musician has the instrument
define_method can_play, [musician, instrument], (m, i) ->
  is_a m.instrument, i

Extension for Functional Programming

I extended JS-CLOS with some features to support functional style programming. One is for dispatching methods on equality of values. This allows us to do something like this:

fib = define_generic()

define_method fib, [0], -> 0
define_method fib, [1], -> 1
define_method fib, ['number'], (n) ->
  fib (n - 1) + fib (n - 2)

Another such feature is the support for multiple constructors. With this, you can write ML style datatypes.

color = define_class()
Red   = define_constructor color
Green = define_constructor color
Blue  = define_constructor color
WebColor = define_constructor color, (str) ->
  make(color, {webCol:str})

is_a Red(), color
#=>true
is_a (WebColor '#ff0033'), color
#=>true

More sophisticated examples will show up in my gist. Follow me if you are interested.

Thank you for reading. Learn it and hack on!

JS-CLOS

"