18. int i = 5;
(def i 5)
OR
(let [i 5] ...)
if (x > 5) {
return y;
} else {
return z;
}
(if (> x 5)
y
z)
x * y * z
(* x y z)
foo(x, y, z)
(foo x y z)
object.method(x, y)
(.method object x y)
public String sayHello(String x) {
return "Hello " + x;
}
(defn sayHello [x]
(str "Hello " x))
19. Java Quiz
public static void main(String[] args) {
int bang = 1;
do while (bang>=1)
System.out.print(" bang is "+ bang);
while (bang>1);
}
21. Working with Java classes
static void display(String text) {
JFrame frame = new JFrame("MyFrame");
frame.add(new JLabel(text));
frame.setSize(300, 200);
frame.setVisible(true);
}
(defn display [text]
(let [frame (new JFrame "MyFrame")]
(.add frame (new JLabel text))
(.setSize frame 300 200)
(.setVisible frame true)))
a pattern!
(display "Hello World")
22. Working with Java classes
static void display(String text) {
JFrame frame = new JFrame("MyFrame");
with (frame) {
.add(new JLabel(text));
.setSize(300, 200);
.setVisible(true);
}
}
(defn display [text]
(let [frame (new JFrame "MyFrame")]
(.add frame (new JLabel text))
(.setSize frame 300 200)
(.setVisible frame true)))
23. Working with Java classes
static void display(String text) {
JFrame frame = new JFrame("MyFrame");
with (frame) {
.add(new JLabel(text));
.setSize(300, 200);
.setVisible(true);
}
}
(defn display [text]
(let [frame (new JFrame "MyFrame")]
(doto frame
(.add (new JLabel text))
(.setSize 300 200)
(.setVisible true))))
24. Working with Java classes
static void display(String text) {
JFrame frame = new JFrame("MyFrame");
frame.add(new JLabel(text));
frame.setSize(300, 200);
frame.setVisible(true);
}
(defn display [text]
(doto (new JFrame "MyFrame")
(.add (new JLabel text))
(.setSize 300 200)
(.setVisible true)))
Ok, nice,
but in practice you would
never want something like this?
28. Structure in
Modules!
namespace - first-class, dynamic, import, aliasing!
Abstraction !
defprotocol - can be added later!
Implementation!
defrecord - immutable, equals, hashcode, etc!
deftype - may mutate, only user functionilty!
reify - singleton!
gen-class & proxy - for Java interop
29. Records - creating
(ns my.namespace)
(defrecord Person [firstName lastName])
(new Person "Jan" "Kronquist")
; #my.namespace.Person{:firstName "Jan", :lastName "Kronquist"}
30. Records - field access
(ns my.namespace)
(defrecord Person [firstName lastName])
(new Person "Jan" "Kronquist")
; #my.namespace.Person{:firstName "Jan", :lastName "Kronquist"}
(def person (new Person "Jan" "Kronquist"))
(.firstName person)
; "Jan"
31. Records - named parameters
(ns my.namespace)
(defrecord Person [firstName lastName])
(new Person "Jan" "Kronquist")
; #my.namespace.Person{:firstName "Jan", :lastName "Kronquist"}
(def person (new Person "Jan" "Kronquist"))
(.firstName person)
; "Jan"
(map->Person {:lastName "Kronquist" :firstName "Jan"})
; #my.namespace.Person{:firstName "Jan", :lastName "Kronquist"}
32. Records and protocols
(defprotocol Nameable
(getName [this]))
Person class
implements
Nameable interface
(defrecord Person [firstName lastName]
Nameable
(getName [this] (str firstName " " lastName)))
!
(getName (new Person "Jan" "Kronquist"))
!
; "Jan Kronquist"
Person
Nameable
extended by
after definition!
(defrecord Person [firstName lastName])
!
(extend-protocol Nameable
Person
(getName [this] (str (.firstName this) " " (.lastName this))))
!
(getName (new Person "Jan" "Kronquist"))
!
; "Jan Kronquist"
33. Records and protocols
(defprotocol Nameable
(getName [this]))
(defrecord Person [firstName lastName]
Nameable
(getName [this] (str firstName " " lastName)))
Method getName
exists on Person class
!
(.getName (new Person "Jan" "Kronquist"))
!
; "Jan Kronquist"
(defrecord Person [firstName lastName])
!
(extend-protocol Nameable
Person
(getName [this] (str (.firstName this) " " (.lastName this))))
!
(getName (new Person "Jan" "Kronquist"))
!
; "Jan Kronquist"
34. Records and protocols
(defprotocol Nameable
(getName [this]))
(defrecord Person [firstName lastName]
Nameable
(getName [this] (str firstName " " lastName)))
Method getName
exists on Person class
!
(.getName (new Person "Jan" "Kronquist"))
!
; "Jan Kronquist"
(defrecord Person [firstName lastName])
!
But not in this case!
(extend-protocol Nameable
Person
(getName [this] (str (.firstName this) " " (.lastName this))))
!
(.getName (new Person "Jan" "Kronquist"))
!
; IllegalArgumentException No matching field found: getName
35. Editors and IDEs?
Eclipse - Counterclockwise!
IntelliJ - La Clojure!
Light Table!
Sublime!
Textmate!
Emacs
46. Clojure makes dynamic typing ok
REPL!
Immutable data structure !
Pure functions!
Automated tests
47. Studies
Stefan Hanenberg & Lutz Prechelt!
Dynamic is more productive!
No difference in reliability!
Robert Smallshire - 2 % defects are type errors (GitHub)
48. Still not convinced?
Clojure is compiled to bytecode!
Type hints!
(defn len [^String x]
(.length x))
!
core.typed
(t/ann f [Integer -> Integer])
(defn f [x] (int (inc x)))
50. Convinced?
REPL!
Immutable data structure !
Pure functions!
Automated tests
Dynamic typing is scary
usable
(operation operand1 operand2 ...)
Lisp looks weird
is consistent
Namespaces!
Prototcols!
Records
Interesting language
Just a toy
Lazy seqs!
STM!
Functional
try (Writer writer = new FileWriter(fileName)) {
writer.write(text);
}
Macros? Are you crazy?
Maybe.......
DSL!
Reuse!
Structure