What Clojure Taught Us About Kotlin

We tried to capture lightning in a bottle

  • The Journey so far...
  • Kotlin vs. Clojure
  • Functional, the good bits
    • FP vs. OO
    • OOP done poorly
    • Clojure big wins
    • How to Kotlin better
    • Clojure, caveats

What did we do?

  • Wrote NetApp E-Series
    • In Kotlin
    • Talked about Kotlin at GRJUG's "Alternative Languages on the JVM"
      • Enticed by the Clojure talk
    • Read Clojure for the Brave and True
  • Went to Clojure/Conj
    • Ate Vegan Junkfood
      • http://hotdogscoldbeer.com/
    • Learned more about Clojure
    • Wrote some Clojure - liked it
  • Rewrote NetApp E-Series in Clojure - liked it

What is Clojure?

;; (A LISP)

;; (On the JVM)

;; (Functional Programming Language)
(defn -main
  "This is the main"
  [& args]
  (println "Hello Blue Medora"))


;; (Immutable Data Structures)

;; (Released in 2007, most recent version is 1.8.0 )
;; ((January 2016) 1.9 coming soon!)

((((((Parenthesis))))))

Functional Programming

  • Immutability
    • Make a new copy instead of mutating old copy
  • Pure Functions
    • No side Effects
  • Higher Order Functions
    • Functions that act on functions
  • Recursion

Object Oriented

  • Mutability AND Immutability
  • Functions may have side effects
  • Some support for HOFs
    • Lambdas
  • Iteration preferred
    • Recursion possible

 

// functions

var things = listOf(1, 2, 3, 4)
for (thing in things) {
    things[things.indexOf(thing)] = thing + 1
}

// assoc

var things = listOf("id", "name", "cpu")
var newStuff = MutableMapOf<String, JSONObject>

for (thing in things) {
    newStuff.put(thing, json.get(thing))    
}

// let

fun crazyPills() {
    whatever = listOf("a", "b", "c")
    stuff = listOf(1, 2, 3, 4)
    things = listOf("Perl", "JavaScript", "OCAML")
    for (thing in things){
        for (item in stuff) {
            for (what in whatever) {
                newValue = thing + item + what
            }
        }
    }
}

// lambdas
// TODO Use Lambdas if the language offers them
;; Clojure

;; functions

(map inc [0 1 2 3])

;; assoc

(assoc result-set (keyword sys-id) (build-result-set host port jsessionID sys-id))

;; let

(defn create-metric-from-metric-definition
  [mdefinition drive-json]
  (let [json-name (split (.getMetadata mdefinition "json_name") #" ")]
    (.toMetric mdefinition (get-value mdefinition (get-in drive-json json-name)))))

;; fn (considered fn-amazing)

(map (fn [drive] (create-drive drive arrayID)) drives)
// Kotlin

// functions

fun increment(numbers: List<Number>) = numbers.map { it + 1 }

increment(listOf(1, 2, 3, 4))

// assoc

val valueMap = listOf("id", "name", "cpu").associate { it, json.get(it) }

// let

for (thing in functionThatGetsThings()) {
    println(thing)
}

with is possible, but only for one level deep

// lambdas

val driveList = drives.map { drive -> create-drive(drive, arrayId) }

Clojure it is!

Caveats

Exception in thread "main" java.lang.ClassCastException: com.bluemedora.exuno.result.ExUnoCollectionResult cannot be cast to clojure.lang.IFn, compiling:(/private/var/folders/jb/vdyx1v7n5f1b2djmf16vw71h0000gn/T/form-init9017850513260832378.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7391)
    at clojure.lang.Compiler.loadFile(Compiler.java:7317)
    at clojure.main$load_script.invokeStatic(main.clj:275)
    at clojure.main$init_opt.invokeStatic(main.clj:277)
    at clojure.main$init_opt.invoke(main.clj:277)
    at clojure.main$initialize.invokeStatic(main.clj:308)
    at clojure.main$null_opt.invokeStatic(main.clj:342)
    at clojure.main$null_opt.invoke(main.clj:339)
    at clojure.main$main.invokeStatic(main.clj:421)
    at clojure.main$main.doInvoke(main.clj:384)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: java.lang.ClassCastException: com.bluemedora.exuno.result.ExUnoCollectionResult cannot be cast to clojure.lang.IFn
    at sirani.core$_main.invokeStatic(core.clj:84)
    at sirani.core$_main.invoke(core.clj:75)
    at clojure.lang.Var.invoke(Var.java:383)
    at user$eval5.invokeStatic(form-init9017850513260832378.clj:1)
    at user$eval5.invoke(form-init9017850513260832378.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6927)
    at clojure.lang.Compiler.eval(Compiler.java:6917)
    at clojure.lang.Compiler.load(Compiler.java:7379)
    ... 14 more

Caveats (cont'd)

  • Using ExUno ensures a blend of OO and FP
  • Unfamiliarity
  • (thing(whatever(do(stuff ))))
   (.asProperty
    (.asString
     (.withMetadata
      (.withUnits
       (com.bluemedora.exuno.definition.MetricDefinition. "name" "Name")
       com.bluemedora.exuno.common.ExUnoUnit/UNITLESS)
      (java.util.HashMap. {"json_name" "name"}))))

Is the lightning bottled?

  • Reinvigorated enthusiasm about Kotlin
    • Functional Programming
    • Schooled by a Sophomore
  • Tooling and Community is great
    • Emacs/REPL-Driven Development
    • Leiningen
    • Caveat
      • Too many "Idempotent"s
  • "But if you use Kotlin without embracing any of the functional programming concepts, you aren't going to get much more than just Java" - Kevin Greene

(thanks)

Made with Slides.com