• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Clojure And Swing
 

Clojure And Swing

on

  • 7,907 views

Clojure is a new dialect of LISP that runs on the Java Virtual Machine (JVM). As a functional language, it offers great benefits in terms of programmer productivity; as a language that runs on the ...

Clojure is a new dialect of LISP that runs on the Java Virtual Machine (JVM). As a functional language, it offers great benefits in terms of programmer productivity; as a language that runs on the JVM, it also offers the opportunity to reuse existing Java libraries. Simon’s interest is in using Clojure to build desktop applications with the Java Swing GUI library. In this presentation Simon discusses how the power of Clojure can be applied to Swing, and whether it hits the sweet spot.

Statistics

Views

Total Views
7,907
Views on SlideShare
7,771
Embed Views
136

Actions

Likes
5
Downloads
83
Comments
0

6 Embeds 136

http://skillsmatter.com 100
http://www.slideshare.net 23
http://smash 6
http://run.plnkr.co 3
http://85.92.73.37 2
http://192.168.56.101 2

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • 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

Clojure And Swing Clojure And Swing Presentation Transcript

  • Clojureand Swing – a new productivity sweet spot?
    Simon White
  • Skills Matter
    The UK Open Source Training Company
    Training on: Agile Development, Test Driven Development, Java, Eclipse, Spring, Hibernate, Ajax, Ruby on Rails, Struts Ti, Wicket, JavaServer Faces, Tapestry, Beehive, AOP, RIFE and more!
    Training straight from the Source
    Experts write and teach our courses: Adrian Colyer, Chad Fowler, Howard M. Lewis Ship Craig Larman, Dave Crane, Kevlin Henney, Rob Harrop, Kito Mann, Rod Johnson and many more
    Partners with leading edge companies
    BEA, IBM, Interface21, Sun, Tangosol, wso2
    © Catalysoft Ltd, 2010
  • Speaker Qualifications
    Simon White, IndependentJava developer
    Games published 1985
    PhD Artificial Intelligence
    Written Scientific Software for:
    Remote Sensing
    Drug Discovery
    Medical & Genetics Research
    Swing Developer since 2000
    Author of JIDE Charts
    SkillsMatter Author & Trainer
    © Catalysoft Ltd, 2010
  • 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
  • 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
  • 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
  • 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)))))
  • REPLRead-Evaluate-Print-Loop
    user=> (defn add-one [n] (+ 1 n))
    #'user/add-one
    user=> (add-one 6)
    7
    user=>
  • Java vs. LISP
  • 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
  • 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
  • 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
  • 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)
  • 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)
  • 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)
  • 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)
  • Predicates (Boolean-Valued Tests)
    (= a 10)
    (identical? a b)
    (even? a)
    (odd? a)
    (integer? a)
  • Decisions
    (if (= a 1) 5 0)
    (cond
    (= a 1) 5
    (= a 2) 10
    true 0)
    (when (= a 1) 5)
    a == 1 ? 5 : 0
    Java
  • "Iteration"
    (for [a '(1 2 3)] (+ a 1)) -> (2 3 4)
    (doseq [a (range 5)] a) -> nil
    (doseq [a (range 3)] (println a)) ->
    0
    1
    2
    nil
  • Anonymous Functions
    user=> (fn [a b] (+ a b 1))
    #<user$eval__101$fn__103 ...@a613f8>
    user=> ((fn [a b] (+ a b 1)) 3 4)
    8
    user=> #(+ %1 %2)
    #<user$eval__121$fn__123 ...@56f631>
  • Higher Order Functions
    (inc 1)->2
    (map inc '(1 2 3))->(2 3 4)
    (map + '(1 2 3) '(10 11 12))->(11 13 15)
    (max 1 2 3)->3
    (apply max '(1 2 3))->3
    (filter even? (range 10))->(0 2 4 6 8)
  • Partial Functions
    Partial returns a function
    user=> (def add-two (partial + 2))
    #'user/add-two
    user=> (add-two 5)
    7
  • Java Interoperability
  • 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?
  • 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
  • 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
  • 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);
    }
    }
  • 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
  • Alternative: Use doto
    (defn make-frame []
    (let [f (JFrame. "My Frame")]
    (doto f
    (.setBounds 300 300 600 400)
    (.setVisible true))))
  • Create a Panel & Button
    (ns user
    (:import java.awt.FlowLayout
    (javax.swingJButtonJPanel)))
    (defn make-panel []
    (let [panel (JPanel. (FlowLayout.))
    button (JButton. "Press Me")]
    (doto panel
    (.add button))))
  • Make a Button do Something
    (defn make-panel2 []
    (let [panel (JPanel. (FlowLayout.))
    button (JButton. "Press Me")]
    (.addActionListener button
    (proxy [ActionListener] []
    (actionPerformed [e] (println e))))
    (doto panel
    (.add button))
    )
    )
    #<ActionEventjava.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Press Me...
  • Clojure Custom Component
    (defn make-component [msg]
    (proxy [javax.swing.JComponent] []
    (paintComponent [g]
    (let [height (.getHeight this)
    width (.getWidth this)]
    (doto g
    ...
    )))))
    Detail on next slide
  • Custom Component (cont/d)
    (doto g
    (.setColorColor/gray)
    (.fillOval 20 20 (- width 20) (- height 20))
    (.setColorColor/yellow)
    (.fillOval 0 0 (- width 20) (- height 20))
    (.setFont (.deriveFont (.getFont g) (float 50)))
    (.setColorColor/black)
    (.drawStringmsg
    (int (/ (- width (.stringWidth (.getFontMetrics g) msg)) 2))
    (int (/ height 2))))
  • 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
  • 1. Reducing Boiler-Plate Code
    GridBagConstraints c = new GridBagConstraints();
    c.weighty = 1.0;
    c.weightx = 1.0;
    c.insets = new Insets(5, 5, 5, 5);
    c.gridx = 0;
    c.gridy = 0;
    c.gridheight = 2;
    c.anchor = GridBagConstraints.CENTER;
    c.fill = GridBagConstraints.BOTH;
    add(leftListPane, c);
    c.gridx = 1;
    c.gridy = 0;
    c.gridheight = 1;
    ...
    • GridBagConstraints are unwieldy
    • Use the same options a lot of the time
    • Difficult to understand
  • Using a grid-bag-layout macro
    (def panel
    (doto (JPanel. (GridBagLayout.))
    (grid-bag-layout
    :fill :BOTH, :insets (Insets. 5 5 5 5)
    :gridx 0, :gridy 0
    (JButton. "One")
    :gridy 1
    (JButton. "Two")
    :gridx 1, :gridy 0, :gridheight 2
    (JButton. "Three"))))
    See http://stuartsierra.com/2010/01/05/taming-the-gridbaglayout
  • 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.
  • 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.
  • 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 C)
    :accelerator (accelerator "ctrl C")}))
  • 3. Flexibility and Reusability
    (def *tracing-actions* true)
     
    (defntrace-action [handler]
      (fn [#^ActionEvent e]
        (try
          (when *tracing-actions*
    (print "Doing" (.getActionCommand e)))
          (handler e)
          (finally
            (when *tracing-actions* (println "Done"))))))
  • Swing Worker & Busy Cursor
    (defmacro with-busy-cursor
    [component f]
    `(proxy [SwingWorker] []
    (doInBackground []
    (.setCursor ~component (Cursor/getPredefinedCursor Cursor/WAIT_CURSOR))
    ~f)
    (done []
    (.setCursor ~component (Cursor/getDefaultCursor)))))
    (with-busy-cursor chart
    (load-file data-file))
  • Clojure/Swing in the Real World
  • 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))
  • 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?
  • Closure Example
    (defnplusn [x]
    (fn [y] (+ x y)))
    (def plus5 (plusn 5))
    (plus5 3)
    >> 8