Introducing Clojure
Elegant Functional Programming on JVM

Mafinar Rashid Khan
Product Manager
Panacea Systems Limited
@mafinar

About Mafinar

  • Fan of "The Flash"
  • Makes finance systems, micro-frameworks, GIS
  • Works with Python 2 and Clojure[Script]
  • Can be sarcastic
  • Doesn't like Java or OOP or Design Patterns
  • Loves JVM
  • Hates JavaScript
  • Knows Kung-fu

An general purpose , pragmative, dynamic, functional variant of Lisp on top of JVM with concurrency and power in mind...

...Elegance and Simplicity Made Easy...

Why should one care?

LISP

Power and Elegance...

  • Simple in design, elegance in bloodline
  • Functional Programming at its finest
  • Extreme power, extensible even at syntax level
  • Mother of all DSL
  • Good for grokking AI
  • If you can think of anything, in any way, Lisp can do it
  • Futuristic features... since 1950s.

Stuff from legends...

  • "the greatest single programming language ever designed" - Alan Kay
  • "Greenspun's Tenth Rule of Programming: any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp." - Philip Greenspun
  • "Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people." - Matz
  • Lisp isn't a language, it's a building material." - Alan Kay
  • “Within a couple weeks of learning Lisp I found programming in any other language unbearably constraining.” - Paul Graham
  • “Lisp is a language for doing what you've been told is impossible.” - Kent Pitman

Eric Raymond

“Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.”

Edsger Dijkstra

“Lisp has jokingly been called "the most intelligent way to misuse a computer". I think that description is a great compliment because it transmits the full flavor of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.”

JVM

Do I really need to say anything here?

Solid. Performant. Secure. Industry. Enterprise. Innovative. Omnipresent. Concurrent. Parallel. Big Data.

Let's not get into who uses it or what got created with JVM?

Unless you want to give me the whole session or more?

"We were not out to win over the Lisp programmers; we were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp." - Guy Steele

Clojure drags them the other half

LISP + JVM = Clojure

Clojure goodies...

  • Simple and powerful syntax
  • Ability to create awesome DSL
  • Combination of purity and pragmatism
  • Entire Java ecosystem available
  • Making concurrency easier
  • Extremely productive and performant
  • Great community

Who's using it?

  • Akamai
  • BackType
  • CircleCI
  • CITI
  • Cognitect
  • Deutsche Bank
  • eBay
  • Groupon
  • HelpShift
  • Heroku
  • Netflix
  • Panacea Systems
  • Prismatic
  • PuppetLabs
  • SoundCloud
  • Spotify
  • TeraData
  • ThoughtWorks
  • Tulos Capital
  • 2 Sigma
  • Unbound
  • uSwitch
  • Walmart Labs
  • World Singles
  • ZenDesk

Clojure brings the power of Lisp into the glory of JVM...

Making Java[script] fun(ctional), awesomer and less boring

Bringing Lisp on a Java meet-up...

Sword on a Gun-fight?

Gun on a Sword Fight?

Tank on either?

So How do I do this???

Keep it Simple, Stupid!!!

My to-do list...

  • Discuss theories of functional programming
  • Teach Clojure, along with its macro features, concurrency constructs, transducers, monads, lambda calculus
  • Logical/Relational programming while at it
  • Recreate ADA and FORTRAN with Clojure via live-coding
  • Discuss theory of relativity
  • Display round-house kicks
  • Whet your appetite
  • Talking some FP for OOP guys
  • Discuss some simple ideas on how Clojure makes you think

All I can do is make you interested and present you some ideas... and let you in on how Clojurists think

You decide upon it...

Let's learn the language first...

In one slide...

Clojure in one slide...

  • () for LIST, [] for Vectors, {:key value} for maps
  • true is True, false is False, nil is Null
  • You think in Lists (Lisp = LISt Processing, remember?)
  • First element of a Lisp is an operation, the remaining are its arguments
  • Arguments can be lists too, or vector, keyword, number etc.
  • Parentheses all the way...

Congratulations, you know Clojure (and probably all other Lisps)

Source code isn't really the point here.. the concepts are.

Immutability

Functional Programming
Concurrency & Parallelism
Interoperability

Take 1. Immutability

Nothing changes...

People never change, they just become more of what they are

- Count Lestat, Interview with the Vampire

Immutability is...

Basically forgetting about assignments and those little boxes holding values, you play pillow passing with values, values that never change.

But it demands a special data structure to ensure fast operation on immutable data.

One word for you...

Bit Partitioned Vector Trie

(def brown [0 1 2 3 4 5 6 7 8])
(def blue (assoc brown 5 'beef))
(def brown [0 1 2 3 4 5])
(def blue (pop brown))
(def green (pop brown))

Take 2: Functional Programming

Functions as First Class Citizens

You focus on VERBs, not NOUNs

So, it's eat(cat, rat), NOT cat.eat(rat)

(eat cat rat) in Lisp parlance... ;-)

...some pointers

  • Lambda Calculus
  • Higher Order Functions
  • Closure
  • Pure Functions

Lambda Calculus

  • Fancy Name for function?
  • Remember f(x) = x + 1; therefore f(10) = ?
  • (fn [x] (+ x 1))
  • #(* % %)
  • (defn add-a-with-b #(+ %1 %2))
  • I promise, I'm not swearing...
  • yet.

Higher Order Functions

  • Functions can take functions in
  • Functions can return function bodies
  • Also called Functor, Functional Form etc
  • map, reduce, filter etc.
(map square (range 100))

(->> (range 1 100)
     (comp #(square %) #(cube %))
     (apply +))

Closures

  • A data structure storing a function
  • A function body that has its local variable snapshots remembered per call
  • That's how Clojure got its name?
(defn pow [n]
   (fn [x] (apply * (repeat n x))))

(def square (pow 2))
(def qubic (pow 3))

A pure function is a function that always returns the same output for same input

Useful for memoization, but not always pragmatic (database? random number? printing?)

Then there is partial function, laziness, sequence abstraction...

Take 3: Concurrency and Paralellism

Doing multiple things in style

So what are these things? Concurrency and Parallelism?

Concurrency is managing more than one task at the same time.

When you are texting and driving, you're being concurrent. (DON'T by the way)...

But you don't do them at the same time, you "interleave"

Paralellism is actually doing two tasks simultaneously.

Erm... writing with both hands? Can you?

If a task takes two hands, and you have two hands, you cannot do more than two tasks paralelly.

Oh, and having a friend write a text for you while you drive is distribution.

A special case of paralellism?

Know your enemies: 
Shared State

Clojure and Concurrency

  • Futures and Promises
  • Atom
  • Ref
  • Var
  • Agents
  • core.async

Futures dispatch a computation on a different thread

Cheapest way to attain multithreadedness

(def what-is-the-answer-to-life (future 
        (println "[Future] started computation")
        (Thread/sleep 3000) ;; running for 3 seconds
        (println "[Future] completed computation")
        42))
(println "[Main] created future")
(Thread/sleep 1000)
(println "[Main] do other things while waiting for the answer")
(println "[Main] get the answer")
(println "[Main] the result" @what-is-the-answer-to-life)

Promise is like its English meaning, something that promises a delivery sometime in future

(def p (promise)) ;=#'user/p
(realized? p) ;=false
(deliver p "as-promised")
(realized? p) ;=true
@p ;="as-promised"

State Management

  • Refs are for Coordinated Synchronous access to "Many Identities".
  • Atoms are for Uncoordinated synchronous access to a single Identity.
  • Agents are for Uncoordinated asynchronous access to a single Identity.
  • Vars are for thread local isolated identities with a shared default value.

Atom

Primary Operations: swap! and reset! 

(def click-count (atom 0))

(defn counting-component []
  [:div
   "The atom " [:code "click-count"] " has value: "
   @click-count ". "
   [:input {:type "button" :value "Click me!"
            :on-click #(swap! click-count inc)}]])

Ref - STM

  • Software Transactional Memory
  • Similar to ACID (From Database Theory) sans D
  • All actions in a "ref" are atomic, either one or none
  • Automatic retry on failures
  • Operations: ref-set, alter, commute
(def accounts 
 [(ref 0) 
  (ref 10) 
  (ref 20) 
  (ref 30)])

(defn transfer [src-account 
                dest-account 
                amount]
  (dosync
    (alter dest-account + amount)
    (alter src-account - amount)))

(map deref accounts)
;=> (5 5 20 30)


I haven't ever used Agent, so not discussing it here.

Now the most awesome... core.async

Let's do asynchronous programming...

I don't like statically typed language and I have Java anonymous classes. JavaScript is cool so I shall use JavaScript. 

-- NOT me.

var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), 
                                                         {'pk':CustomPKFactory});
p_client.open(function(err, p_client) {
    p_client.dropDatabase(function(err, done) {
        p_client.createCollection('test_custom_key', function(err, collection) {
            collection.insert({'a':1}, function(err, docs) {
                collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {
                    cursor.toArray(function(err, items) {
                        test.assertEquals(1, items.length);
​
                        // Let's close the db​
                        p_client.close();
                    });
                });
            });
        });
    });
});

... Now I have two problems... intertwined ;-)

core.async's Hadouken...

Here's how you do...

  • Create a channel
  • Whenever something happens, pass it on >!
  • Subscribers of the channel will immediately get it <!
  • They know what to do with it.
  • Channels can be blocking or unblocking
  • Reactive Programming FTW!!!
(defn upper-caser
  [in]
  (let [out (chan)]
    (go (while true (>! out (clojure.string/upper-case (<! in)))))
    out))

(defn reverser
  [in]
  (let [out (chan)]
    (go (while true (>! out (clojure.string/reverse (<! in)))))
    out))

(defn printer
  [in]
  (go (while true (println (<! in)))))

(def in-chan (chan))
(def upper-caser-out (upper-caser in-chan))
(def reverser-out (reverser upper-caser-out))
(printer reverser-out)

(>!! in-chan "redrum")
; => MURDER

(>!! in-chan "repaid")
; => DIAPER

Credits: Clojure for the Brave and True

Take 4: Interoperability

Communicating with the hosts

Because you don't want to miss out on the decades of Java.

This is actually simple...

(Integer/parseInt "0")
;; Integer.parseInt("0")
(.toUpperCase "hello")
;; "hello".toUpperCase()
(.. System 
    (getProperties) 
    (get "os.name"))
;; System.getProperties().get("os.name")
(doto (new java.util.HashMap) 
      (.put "a" 1) 
      (.put "b" 2))
; HashMap hm = new HashMap();
; hm.put("a", 1);
; hm.put("b", 1);

Advanced Stuff...

Programming by Wishful Thoughts...

Top-Down Approach

  • Think how you want to see your solution
  • Type the outcome
  • Start Implementing...
  • Remember, you can bend your syntax at will
(def-html page [title, body]
  (title title)
  (body (div (map employee-snippet employee-list))))

(def-snippet employee-snippet [e]
  (table :data (employees) :class "alternate-row"))

(def-form employee-form
  (html-form :map-with (get-employee-structure) 
             :on-click create-employee!))

(defn employee-list 
  (sql
    (select "employee" [:first-name :last-name] :order-by "age")))

(defn create-employee!
  (sql! 
    (create "employee" [:first-name :last-name] ["Mafinar" "Khan"]))

Program your Programming Language

Macro

  • Much like templates, but for programming language
  • Abstract away a snippet into your own liking
  • True power of Lisp
;; UNLESS <YES> <NO> = generate_code("if (!_LOGIC_) { _YES_ } else { _NO_ }")

(defmacro unless [pred a b] `(if (not ~pred) ~a ~b))

Behold the Mighty Leiningen

A Leiningen Project File

A List of Resources and Talks?

... look ahead!

There you go...

Shameless Plug...

This book I am trying to write...

While you're at it-

Introducing Clojure[Script]

By Mafinar Khan

Introducing Clojure[Script]

My slides on the JUGBD 5.0 on Clojure

  • 2,199