Clojure and Swing – a new productivity sweet spot? discusses how Clojure, a Lisp dialect that runs on the JVM, can be used to develop graphical user interfaces (GUIs) using Java Swing in a more productive way than plain Java. It presents several advantages of Clojure for Swing development, such as reducing boilerplate code, easier definition of actions and event bindings, and increased flexibility and reusability through functional programming techniques. Examples are provided of common Swing programming tasks implemented more concisely and readably in Clojure compared to Java. The document concludes that Clojure is a powerful and flexible language that offers opportunities to apply Lisp concepts to Swing GUI development
4. What is Clojure? A functional language that runs on the JVM A new dialect of LISP Not Closure Not Clozure MYTH: LISP is slow MYTH: Therefore Clojure is slow
5. Functional Languages What is a function? a mathematical relation such that each element of a given set (the domain of the function) is associated with an element of another set (the range of the function)) [Wordnet] Focus on the input/output relation e.g. length of a string maps a string to an integer Immutability Good; Side-effects Bad
6. LISP Syntax (functor param1 param2 ... paramn) for example, (+ 1 2) Brackets denote evaluation A single quote protects from evaluation so '(x y z) does not use x as a function With nested expressions, evaluate inner expression first: (+ (+ 2 3) (* 2 3)) is 11 Special forms like let, cond deviate from the syntax and must be learned
7. Hello Factorial n! = n × (n-1) × (n-2) × ... × 1 Also 0! = 1 (defnfac “Computes the factorial of n” [n] (if (= n 0) 1 (* n (fac (- n 1)))))
10. Why mix Java and LISP? To get the best of both: Speedy development of custom code in LISP Speedy development through library reuse in Java Speedy development of applications with concurrent processing
11. LISP Promotes Agility LISP was agile long before agility was respected Easy to mix and match function application Accommodate changing requirements Many small functions => very reusable code REPL Encourages ad-hoc testing Functional style makes it easy to write unit tests
12. Clojureas a LISP dialect Simplified syntax compared to Common LISP cond, let Not object-oriented But you can define structures and multi-methods No multiple value returns Arguably syntactic sugar anyway Lazy evaluation of sequences Destructuring Structural pattern matching on function parameters Concurrency
13. Data Structures 1: Lists (list 'a 'b 'c) -> (a b c) (first '(a b c)) -> a (rest '(a b c)) -> (b c) (nth '(a b c) 1) -> b (cons 'a '(b c)) -> (a b c) (concat '(a b) '(c d)) -> (a b c d)
14. Data Structures 2: Vectors (vector 'a 'b 'c) -> [a b c] (first '[a b c]) -> a (rest '[a b c]) -> (b c) (nth '[a b c] 1) -> b (cons 'a '[b c]) -> (a b c) (conj '[a b] 'c) -> [a b c] (concat '[a b] '[c d]) -> (a b c d)
15. Data Structures 3: Maps Key-Value Pairs (get '{a 1, b 2} 'b) -> 2 (assoc '{a 1, b 2} 'c 3) -> {c 3, a 1, b 2} (dissoc '{a 1, b 2} 'b) -> {a 1} (defstruct book :title :author) (struct-map book :title "Jungle Book" :author "Rudyard Kipling") (bean obj)
16. Everything is a Sequence Lists, Vectors and Maps are all sequences first, rest & cons always return a sequence (range 5) -> (0 1 2 3 4) (take 2 (range 5)) -> (0 1) (take 3 (repeat 'x)) -> (x xx)
24. A GUI in a functional language? Functional languages use functions as mathematical models of computation: f(x1, x2, ...) -> x’ Great for factorials, but how does it work with user-interfaces? Forms? Keyboard & Mouse? Events?
25. Need to Think Differently Values of functions ‘computed’ as the result of a user-interaction Consider y-or-n-p CL> (y-or-n-p "Do you really want to quit?") T
26. Modelling Change of State f(x) -> x’ Name: “George” DOB: “11-Jul-73” Address: “16 Goldman Square” Name: “George” DOB: “11-Jul-73” Address: “3 Elm Avenue” This is a new (immutable) value, not a modified one
27. Java Swing: Create a JFrame import javax.swing.JFrame; public class MyClass { ... public static void main(String[] args) { JFrame frame = new JFrame("My Frame"); frame.setBounds(300, 300, 600, 400); frame.setVisible(true); } }
28. Clojure Swing: Create a JFrame (ns user (:import (javax.swingJFrame))) (defn make-frame [] (let [f (JFrame. "My Frame")] (.setBounds f 300 300 600 400) (.setVisible f true) f ) ) f is the return value
29. Alternative: Use doto (defn make-frame [] (let [f (JFrame. "My Frame")] (doto f (.setBounds 300 300 600 400) (.setVisible true))))
34. Three ways in which Clojure can help Swing Reducing boiler-plate code Easy to write code that generates the required patterns Definitions of actions and easier binding Easier to separate configuration (name, icon, keyboard shortcut, ...) from code hook Flexibility and Reusability Using functions as parameters for user customisation of behaviour
38. 2. Defining Swing Actions Swing Actions are a nice idea, but have problems. Typically, you might have: Lots of inner classes with repeated boiler plate code, or: Separate classes that extend AbstractAction but are too tightly coupled to a main class so that they have the necessary context for the actionPerformed() method.
39. Clojure Actions: Defer binding for actionPerformed method With an Action in Clojure it’s possible to preset the ‘constant’ variables like Name, Icon, Accelerator ; but defer the binding for the handler. This means we can easily separate the creation of an action according to some template from its binding to a response function.
40. Create an Action when the handler function is known (defmacro copy-action [handler] `(make-action {:name "Copy" :command-key "copy" :icon (ImageIcon. (fetch-image "copy.png")) :handler ~handler :mnemonic (mnemonic ) :accelerator (accelerator "ctrl C")}))
44. Creating a Chart Model (defn make-model "Create and return a ChartModel using the supplied rows and picking out the x and y columns" [model-name rows #^String x-col #^String y-col] (let [model (DefaultChartModel. model-name)] (doseq [row rows] (let [x (get row x-col) y (get row y-col)] (when (and (number? x) (number? y)) (.addPoint model (double x) (double y)))) ) model))
45. Summary Clojureis Powerful and Flexible Excellent Java Interoperability Opportunities to apply LISP power to Swing GUI development Can be used for Real World Applications A Secret Weapon for Productivity?
A closure is a feature provided by some languages that capture the lexical context in which a code fragment was written. The free variables in that lexical context are ‘closed over’ so the code fragment can be passed around and used elsewhere.Clozure is a dialect of LISP for the Mac (formerly Macintosh Common LISP)
defn defines a function
You can also create GUI elements such as JFrames and JButtons on the fly.
There are only few libraries in LISP compared to Java because it is a niche language.However, the fact that it is a niche language could make it your secret weapon.
For is actually a list comprehension
Reasons for using partial functions: Binding parameters at different times (when they become known) Clearer semantics
ns specifies the name space for the functions that followlet allows you to define some local variables
ns specifies the name space for the functions that followlet allows you to define some local variables
Or if you create a new GridBagConstraints object often, you might not remember what all the constructor arguments are
The example with-busy-cursor is intended as an illustration only