ClojureScript Painkiller (for OOP)

When I learned and used ClojureScript, I really hated writing code that looks like this:

(defn Bag []
  (this-as this
           (set! (.-store this) (array))

(set! (.. Bag -prototype -add)
      (fn [val]
        (this-as this
                 (.push (.-store this) val))))

(set! (.. Bag -prototype -print)
      (fn []
        (this-as this
                 (.log js/console (.-store this)))))

(def mybag (Bag.))
(.add mybag 5)
(.add mybag 7)
(.print mybag)

That’s so much ceremony and repeated waste!

I know it’s not how you’re supposed to write ClojureScript, but sometimes you have to (for example when working with OO libraries).

What do you do with such code? Cover it with macros!

So I wrote two little macros that you can just pick up and use right away in your ClojureScript, so that it can look like:

(defn Bag []
  (this-as this
           (set! (.-store this) (array))

(set-obj-fn Bag.prototype.add [val]
            (.push (.-store this) val))

(set-obj-fn Bag.prototype.print [val]
            (.log js/console (.-store this)))

Or just a this-as shortcut:

(set! (.. Bag -prototype -add)
      (obj-fn [val]
        (.push (.-store this) val)))

Source with complete sample is on github. The library is on Clojars, so to use it all you need is [cljs-painkiller "0.1.0"] in your project.cljs. Enjoy!

One thought on “ClojureScript Painkiller (for OOP)

  1. You could also use protocols which gives you namespaced methods and a more idiomatic syntax:

    (defprotocol MyBag
    (add [this val])
    (print [this]))

    (extend-type Bag
    (add [this val]
    (.push (.-store this) val))
    (print [this]
    (.log js/console (.-store this))))

    (def mybag (Bag.))
    (add mybag 2)
    (add mybag 3)
    (print mybag)
    ;;> [2, 3]

Leave a Reply

Your email address will not be published. Required fields are marked *

Spam protection by WP Captcha-Free