SlideShare a Scribd company logo
1 of 68
Clojure Deep
Dive



Howard M. Lewis Ship
TWD Consulting
hlship@gmail.com

                       1   © 2009 Howard Lewis Ship
Agenda
• Core Language

• Standard Tools

• Clojure Compilation

• Clojure Pitfalls




                        2   © 2009 Howard Lewis Ship
Core Language

           3    © 2009 Howard Lewis Ship
What's A Form?
          Constants:      Keywords:        Symbols:

          42              :foo             map
          "hello"         :tag             strutils2/take



                        Data Structures:

                        […]
                        {…}
                        #{ … }


  Callables:
   Special Forms:      Function Call:      Macros Expansion:

   (if …)              (map …)             (and …)
   (var …)                                 (or …)
   (do …)                                  (ns …)



                                 4                             © 2009 Howard Lewis Ship
defn: Define a function
                     Symbol (in current namespace)
                                                              Optional doc string

            (defn to-seq
              "Converts the object to a sequence (a vector)
            unless it is already sequential."
              [obj]
              (if (sequential? obj) obj [obj]))



List of parameters




    user=> (doc to-seq)
    -------------------------
    user/to-seq
    ([obj])
      Converts the object to a sequence (a vector)
    unless it is already sequential.
    nil
    user=>


                                             5                                      © 2009 Howard Lewis Ship
defn: Multiple Arities
One doc string
Series of argument lists / forms

                           (defn not=
                             "Same as (not (= obj1 obj2))"
                             ([x] false)
                             ([x y] (not (= x y)))
                             ([x y & more]
                              (not (apply = x y more))))

              & symbol ➠ provide
              remaining values as a
              seq


user=> (doc not=)
-------------------------
clojure.core/not=
([x] [x y] [x y & more])
  Same as (not (= obj1 obj2))
nil
user=>


                                           6                 © 2009 Howard Lewis Ship
let: local symbols
        (let [center (calc-center-for-frame frame)
             x (get-x center)
             y (get-y center)]
          …)




•Even number: symbol1 form1 symbol2 form2 …

•Not variables: symbols are read-only

•Can re-define symbols




                                     7               © 2009 Howard Lewis Ship
do: evaluate for side-effects

    (if value-found
      (do
        (println "Found the value.")
        value-found))



        Last form is the result




    ; Broken

    (if value-found
      (println "Found the value.")               If true, side effect & return nil
      value-found)




     If false, return value (false or nil)



                                             8                                 © 2009 Howard Lewis Ship
Branching: if, when
                       (if test then-form)
                       (if test then-form else-form)




• Special form: not a function
• Evaluates test, then evaluates & returns either then-form or
  else-form
  • false and nil ➠ logical false
  • anything else ➠ logical true
        (when test then-forms)             (if-not test then-form)
                                           (if-not test then-form else-form)


           Any number of forms in an
           implicit do                          Like (if (not test) then else)


        (when-not test then-forms)
                                       9                                         © 2009 Howard Lewis Ship
if-let, when-let

(if-let [symbol test] then-form)
(if-let [symbol test] then-form else-form)



             Symbol can be referenced


 (when-let [symbol test] then-forms)



              Any number of forms in an
              implicit do




                                          10   © 2009 Howard Lewis Ship
or, and
                                        (or form…)
                                        (and form…)

   • or: first value from list that evaluates to true
      • Will return value of last expression (false or nil)
      • (or) returns nil
   • and: first logical false (nil or false)
      • Returns value of last expression (if prior are logical true)
      • (and) return true
      • Can be used as a "guard"                      Only invoke symbol and find-ns
(defn dispatch-named-function-to-pipeline             if ns-name is non-nil
  [env pipeline]
  (let [split-path (-> env :cascade :split-path)
        [_ ns-name fn-name] split-path
       fn-namespace (and ns-name (find-ns (symbol ns-name)))
       named-function (and fn-namespace fn-name (ns-resolve fn-namespace (symbol fn-name)))
       new-env (assoc-in env [:cascade :extra-path] (drop 3 split-path))]
    (call-pipeline pipeline new-env named-function)))

                                             11                                © 2009 Howard Lewis Ship
Destructuring




                                                                           Bu

                                                                            N wo
                                                                             sy
                                                                              o rk
• Automatically extract values from data structures




                                                                                            !
• Binding forms:

   • Map to extract keys

   • Vector to extract indexed values

• Function parameters
                                                 One un-named parameter
• let, if-let, when-let, etc.                    destructured to two symbols


                 user=> (defn natural-name
                          [{fname :first-name lname :last-name}]
                          (str lname ", " fname))
                 #'user/natural-name
                 user=> (natural-name (persons 1))
                 "Simon, Scott"
                 user=>

                                          12                               © 2009 Howard Lewis Ship
Destructuring
• Binding Forms:

  • symbol                                      (let [x (get-x center)] … )




  • vector of binding forms                         (let [[x y] center] … )




  • map of binding form to map key
                       (let [{fname :first-name lname :last-name} person] …)




                                 13                                © 2009 Howard Lewis Ship
Vector Destructuring
                 center must be sequential


(let [[x y] center] …)




      May be nil if not enough values in center


(let [[first-born second-born & other-children] children] …)



                              & symbol gets the remaining values

(let [[first-born second-born & other-children :as children] (find-children parent)] …)



            Nested binding forms!                 :as symbol gets the full list

user=> (let [[[x1 y1][x2 y2]] [[1 2] [3 4]]]
  [x1 y1 x2 y2])
[1 2 3 4]
user=>
                                             14                                   © 2009 Howard Lewis Ship
Map Destructuring
(defn natural-name [{fname :first-name lname :last-name}] (str lname ", " fname))



(defn natural-name [{:keys [first-name last-name]}] (str last-name ", " first-name))



                    :keys maps a keyword key for each symbol
                    :or sets defaults for missing keys

user=> (defn natural-name [{:keys [first-name last-name]
                            :or {first-name "(none)" last-name "(none)"}}]
         (str last-name ", " first-name))
#'user/natural-name
user=> (natural-name {:first-name "Gromit"})
"(none), Gromit"
user=> (natural-name {:first-name "Gromit" :last-name nil})
", Gromit"
user=>




          :as symbol to get the original map
          :strs ➠ like :keys, but maps to string keys, not keyword keys
          :syms ➠ like :keys, but maps to symbol keys, not keyword keys

                                         15                                  © 2009 Howard Lewis Ship
ns: define namespaces
(ns example.utils)
                                  cascade/dispatcher.clj

                                  (ns cascade.dispatcher
                                    (:import (javax.servlet ServletResponse))
      File: example/utils.clj       (:use (cascade config dom logging path-map pipeline)
                                          (cascade.internal utils)))


(ns namespace
  (:import …)   Optional directives
  (:use …))




                      user=> (defn natural-name
                               [{fname :first-name lname :last-name}]
                               (str lname ", " fname))
                      #'user/natural-name
                      user=> (natural-name (persons 1))
                      "Simon, Scott"
                      user=>

user/natural-name
  Namespace: user
  Symbol: natural-name
                                                 16                           © 2009 Howard Lewis Ship
:import Java Classes
                      Package name, then any number of classes/interfaces

(ns cascade.dispatcher
  (:import (javax.servlet ServletResponse))

  …)


            Repeat for other packages

            Can also list fully qualify class names




                                             17                             © 2009 Howard Lewis Ship
:use Import Namespaces
(:use clojure.contrib.pprint)


         Symbols defined by pprint are available, i.e.
         (pprint [1 2 3])

(:use (clojure.contrib pprint monads))


         Add multiple namespaces under the root
         namespace

(:use (clojure.contrib (str-utils2 :only [join map-str]))



         Uses just join and map-str from str-utils2

(:use (clojure.contrib (str-utils2 :exclude [take replace drop]))

         Exclude just some of the symbols
(:use (clojure.contrib (str-utils2 :rename {take strtake}))

         Use str-utils2, mapping take as strtake

                                            18                      © 2009 Howard Lewis Ship
Other ns directives
• :require ➠ load a namespace but don't import it

• :gen-class ➠ create a Java class from functions in the
  namespace

• :refer-clojure ➠ import selected clojure.core symbols

• :load ➠ load Clojure scripts (not namespaces)




                                19                         © 2009 Howard Lewis Ship
Standard
Tools




           20   © 2009 Howard Lewis Ship
Anonymous Functions
  #() ➠ implicit anonymous function

  (filter #(not (.startsWith % ".")) names)




           % is replaced by the function's parameter

        %n is parameter #n


 (map
   #(assoc %1 :sort-index %2)
   (sort-by :age persons)
   (iterate inc 0))

                                 inline anonymous function


                             (map
                        21
                               (fn [person-map sort-index]
                                  (assoc person-map :sort-index sort-index))
                               (sort-by :age persons)
                               (iterate inc 0))

                                                                               © 2009 Howard Lewis Ship
What are seqs?
                Seqable
              seq() : ISeq




          IPersistentCollection                                      Sequential
              count() : int
   cons(Object): IPersistentCollection
     empty() : IPersistentCollection
        equiv(Object) : boolean




              PersistentSet                       ISeq
                                             first() : Object
                                              next(): ISeq
                                              more(): ISeq
                                           cons(Object): ISeq        Returned from map, for,
                                                                     filter, remove, etc.


                          PersistentList     PersistentVector   LazySeq



                                                         22                               © 2009 Howard Lewis Ship
assoc-in / update-in
user=> (def person { :first-name "Howard" :last-name "Lewis Ship"
  :address { :street "123 NW 12th Ave. #541" :city "Portland" :state "OR" :zip 97309 }})
#'user/person
user=> (assoc-in person [:address :street] "2647 SE 97th Ave.")
{:first-name "Howard", :last-name "Lewis Ship",
 :address {:street "2647 SE 97th Ave.", :city "Portland", :state "OR", :zip 97309}}
user=> (update-in person [:address :zip] + 5)
{:first-name "Howard", :last-name "Lewis Ship",
 :address {:street "123 NW 12th Ave. #541", :city "Portland", :state "OR", :zip 97314}}
user=>

                            :first-name "Howard"
                            :last-name "Lewis Ship"
                            :address :street "123 NW 12th Ave."
                                        :city "Portland"
                                        :state "OR"
                                        :zip 97309


                      (update-in person [:address :zip] + 5)

                                       (+ 97309 5)

                            :first-name "Howard"
                            :last-name "Lewis Ship"
                            :address :street "123 NW 12th Ave."
                                        :city "Portland"
                                        :state "OR"
                                        :zip 97314

                                              23                            © 2009 Howard Lewis Ship
map




                                                                            La
                                                                                zy
                                       f

             :age acts as a function


 user=> (map :age persons)
 (42 44 29)
 user=> (map #(apply str (reverse (% :first-name))) persons)
 ("drawoH" "ttocS" "ylloM")
 user=> (map identity (persons 0))
 ([:first-name "Howard"]            iterate a map ➠ key/value   pairs
  [:last-name "Lewis Ship"]
  [:age 42])
 user=> (seq (persons 0))
 ([:first-name "Howard"]
  [:last-name "Lewis Ship"]
  [:age 42])
 user=>



                                           24                           © 2009 Howard Lewis Ship
map




                                                                            La
                                                                                zy
                                  f


                     N seqs ➠ N parameters


 user=> (map #(assoc %1 :sort-index %2)
             (sort-by :age persons)
             (iterate inc 0))
 ({:sort-index 0, :first-name "Molly", :last-name "Newman", :age 29}
  {:sort-index 1, :first-name "Howard", :last-name "Lewis Ship", :age 42}
  {:sort-index 2, :first-name "Scott", :last-name "Simon", :age 44})
 user=>




                                      25                                © 2009 Howard Lewis Ship
reduce

                                            f
user=> (map :age persons)
(42 44 29 38)
user=> (reduce + (map :age persons))
153



                      (reduce + (map :age persons))




                                       26             © 2009 Howard Lewis Ship
reduce

                                            f
user=> (map :age persons)
(42 44 29 38)
user=> (reduce + (map :age persons))
153



                      (reduce + (map :age persons))

                      (reduce + '(42 44 29 38))




                                       27             © 2009 Howard Lewis Ship
reduce

                                            f
user=> (map :age persons)
(42 44 29 38)
user=> (reduce + (map :age persons))
153



                      (reduce + (map :age persons))

                      (reduce + '(42 44 29 38))

                      (+ (+ (+ 42 44) 29) 38)




                                       28             © 2009 Howard Lewis Ship
reduce

                                            f
user=> (map :age persons)
(42 44 29 38)
user=> (reduce + (map :age persons))
153



                      (reduce + (map :age persons))

                      (reduce + '(42 44 29 38))

                      (+ (+ (+ 42 44) 29) 38)

                      (+ (+ 86 29) 38)




                                       29             © 2009 Howard Lewis Ship
reduce

                                            f
user=> (map :age persons)
(42 44 29 38)
user=> (reduce + (map :age persons))
153



                      (reduce + (map :age persons))

                      (reduce + '(42 44 29 38))

                      (+ (+ (+ 42 44) 29) 38)

                      (+ (+ 86 29) 38)

                      (+ 115 38)


                                       30             © 2009 Howard Lewis Ship
reduce

                                            f
user=> (map :age persons)
(42 44 29 38)
user=> (reduce + (map :age persons))
153



                      (reduce + (map :age persons))

                      (reduce + '(42 44 29 38))

                      (+ (+ (+ 42 44) 29) 38)

                      (+ (+ 86 29) 38)

                      (+ 115 38)

                      153
                                       31             © 2009 Howard Lewis Ship
reduce


                                                         f
                      user=> (def input-string "Clojure is a fascinating language with unique
                      capabilities and total integration with Java.")
                      #'user/input-string
                      user=> (seq input-string)
                      (C l o j u r e space i s space a space f a s c i n a
                      t i n g space l a n g u a g e space w i t h space u
                      n i q u e space c a p a b i l i t i e s space a n d
                      space t o t a l space i n t e g r a t i o n space w
                      i t h space J a v a .)
                      user=> (reduce
                               (fn [m k] (update-in m [k] #(if (nil? %) 1 (inc %))))
Optional initial   value       {}
                               (seq input-string))
                      {space 12, a 12, b 1, C 1, c 2, d 1, e 5, f 1, g 4, h 2, i 11,
                       J 1, j 1, l 4, . 1, n 7, o 3, p 1, q 1, r 2, s 3, t 8, u 4,
                       v 1, w 2}
                      user=>


                                                   32                                © 2009 Howard Lewis Ship
filter / remove




                                                                La
                                                                    zy
                                              f
                                                  ?
user=> (remove #(< (% :age) 30) persons)
({:first-name "Howard", :last-name "Lewis Ship", :age 42}
 {:first-name "Scott", :last-name "Simon", :age 44})
user=> (filter #(< (% :age) 30) persons)
({:first-name "Molly", :last-name "Newman", :age 29})
user=>




                                         33                 © 2009 Howard Lewis Ship
apply

                                             f

  user=> (map :age persons)
  (42 44 29)
  user=> (apply + (map :age persons))
  115
  user=>


                  (apply + (map :age persons))

                  (apply + '(42 44 29))

                  (+ 42 44 29)

                  115



                                        34       © 2009 Howard Lewis Ship
Clojure Compilation

           35         © 2009 Howard Lewis Ship
Function Calls


   (remove nil? coll)



                                                       IFn

                                                invoke() : Object
                                             invoke(Object) : Object
       Namespace                          invoke(Object, Object) : Object
                                                        …
                                              applyTo(ISeq) : Object




       Var
       get()            clojure.core$remove__4782    PersistentMap          Keyword




                              36                                               © 2009 Howard Lewis Ship
Compiled to Bytecode
                                (defn first-non-nil
                                  "Returns the first non-nil value from the collection."
                                  [coll]
                                  (first (remove nil? coll)))



package com.howardlewisship.cascade.internal;

import clojure.lang.*;

public class utils$first_non_nil__24 extends AFunction
{

    public Object invoke(Object coll)
      throws Exception
    {
      return ((IFn)const__0.get()).invoke(((IFn)const__1.get()).
             invoke(const__2.get(), coll = null));
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "first");
    public static final Var const__1 = (Var)RT.var("clojure.core", "remove");
    public static final Var const__2 = (Var)RT.var("clojure.core", "nil?");


    public utils$first_non_nil__24()
    {
    }
}
                                              37                                © 2009 Howard Lewis Ship
Compiled to Bytecode
                                (defn first-non-nil
                                  "Returns the first non-nil value from the collection."
                                  [coll]
                                  (first (remove nil? coll)))



package com.howardlewisship.cascade.internal;

import clojure.lang.*;

public class utils$first_non_nil__24 extends AFunction
{

    public Object invoke(Object coll)
      throws Exception
    {
      return ((IFn)const__0.get()).invoke(((IFn)const__1.get()).
             invoke(const__2.get(), coll = null));
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "first");
    public static final Var const__1 = (Var)RT.var("clojure.core", "remove");
    public static final Var const__2 = (Var)RT.var("clojure.core", "nil?");


    public utils$first_non_nil__24()
    {
    }
}
                                              38                                © 2009 Howard Lewis Ship
Compiled to Bytecode
                                (defn first-non-nil
                                  "Returns the first non-nil value from the collection."
                                  [coll]
                                  (first (remove nil? coll)))



package com.howardlewisship.cascade.internal;

import clojure.lang.*;

public class utils$first_non_nil__24 extends AFunction
{

    public Object invoke(Object coll)
      throws Exception
    {
      return ((IFn)const__0.get()).invoke(((IFn)const__1.get()).
             invoke(const__2.get(), coll = null));
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "first");
    public static final Var const__1 = (Var)RT.var("clojure.core", "remove");
    public static final Var const__2 = (Var)RT.var("clojure.core", "nil?");


    public utils$first_non_nil__24()
    {
    }
}
                                              39                                © 2009 Howard Lewis Ship
Compiled to Bytecode
                                (defn first-non-nil
                                  "Returns the first non-nil value from the collection."
                                  [coll]
                                  (first (remove nil? coll)))



package com.howardlewisship.cascade.internal;

import clojure.lang.*;

public class utils$first_non_nil__24 extends AFunction
{

    public Object invoke(Object coll)
      throws Exception
    {
      return ((IFn)const__0.get()).invoke(((IFn)const__1.get()).
             invoke(const__2.get(), coll = null));
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "first");
    public static final Var const__1 = (Var)RT.var("clojure.core", "remove");
    public static final Var const__2 = (Var)RT.var("clojure.core", "nil?");


    public utils$first_non_nil__24()
    {
    }
}
                                              40                                © 2009 Howard Lewis Ship
Compiled to Bytecode
                                    (defn format-date
                                      [env params]
                                      (let [#^Date date (params :date)
package app1;                           #^DateFormat fmt (DateFormat/getDateTimeInstance
                                                   DateFormat/MEDIUM
import clojure.lang.*;                             DateFormat/MEDIUM)]
import java.text.DateFormat;            (.format fmt date)))
import java.util.Date;

public class fragments$format_date__21 extends AFunction
{

    public Object invoke(Object env, Object params)
    throws Exception
    {
      Object date = ((IFn)params).invoke(const__1);
      Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
      env = null;
      params = null;
      date = null;
      fmt = null;
      return ((DateFormat)fmt).format((Date)date);
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "let");
    public static final Object const__1 = Keyword.intern(Symbol.create(null, "date"));


    public fragments$format_date__21()
    {
    }
}



                                                  41                                       © 2009 Howard Lewis Ship
Compiled to Bytecode
                                    (defn format-date
                                      [env params]
                                      (let [#^Date date (params :date)
package app1;                           #^DateFormat fmt (DateFormat/getDateTimeInstance
                                                   DateFormat/MEDIUM
import clojure.lang.*;                             DateFormat/MEDIUM)]
import java.text.DateFormat;            (.format fmt date)))
import java.util.Date;

public class fragments$format_date__21 extends AFunction
{

    public Object invoke(Object env, Object params)
    throws Exception
    {
      Object date = ((IFn)params).invoke(const__1);
      Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
      env = null;
      params = null;
      date = null;
      fmt = null;
      return ((DateFormat)fmt).format((Date)date);
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "let");
    public static final Object const__1 = Keyword.intern(Symbol.create(null, "date"));


    public fragments$format_date__21()
    {
    }
}



                                                  42                                       © 2009 Howard Lewis Ship
Compiled to Bytecode
                                    (defn format-date
                                      [env params]
                                      (let [#^Date date (params :date)
package app1;                           #^DateFormat fmt (DateFormat/getDateTimeInstance
                                                   DateFormat/MEDIUM
import clojure.lang.*;                             DateFormat/MEDIUM)]
import java.text.DateFormat;            (.format fmt date)))
import java.util.Date;

public class fragments$format_date__21 extends AFunction
{

    public Object invoke(Object env, Object params)
    throws Exception
    {
      Object date = ((IFn)params).invoke(const__1);
      Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
      env = null;
      params = null;
      date = null;
      fmt = null;
      return ((DateFormat)fmt).format((Date)date);
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "let");
    public static final Object const__1 = Keyword.intern(Symbol.create(null, "date"));


    public fragments$format_date__21()
    {
    }
}



                                                  43                                       © 2009 Howard Lewis Ship
Compiled to Bytecode
                                    (defn format-date
                                      [env params]
                                      (let [#^Date date (params :date)
package app1;                           #^DateFormat fmt (DateFormat/getDateTimeInstance
                                                   DateFormat/MEDIUM
import clojure.lang.*;                             DateFormat/MEDIUM)]
import java.text.DateFormat;            (.format fmt date)))
import java.util.Date;

public class fragments$format_date__21 extends AFunction
{

    public Object invoke(Object env, Object params)
    throws Exception
    {
      Object date = ((IFn)params).invoke(const__1);
      Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
      env = null;
      params = null;
      date = null;
      fmt = null;
      return ((DateFormat)fmt).format((Date)date);
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "let");
    public static final Object const__1 = Keyword.intern(Symbol.create(null, "date"));


    public fragments$format_date__21()
    {
    }
}



                                                  44                                       © 2009 Howard Lewis Ship
Compiled to Bytecode
                                    (defn format-date
                                      [env params]
                                      (let [#^Date date (params :date)
package app1;                           #^DateFormat fmt (DateFormat/getDateTimeInstance
                                                   DateFormat/MEDIUM
import clojure.lang.*;                             DateFormat/MEDIUM)]
import java.text.DateFormat;            (.format fmt date)))
import java.util.Date;

public class fragments$format_date__21 extends AFunction
{

    public Object invoke(Object env, Object params)
    throws Exception
    {
      Object date = ((IFn)params).invoke(const__1);
      Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
      env = null;
      params = null;
      date = null;
      fmt = null;
      return ((DateFormat)fmt).format((Date)date);
    }

    public static final Var const__0 = (Var)RT.var("clojure.core", "let");
    public static final Object const__1 = Keyword.intern(Symbol.create(null, "date"));


    public fragments$format_date__21()
    {
    }
}



                                                  45                                       © 2009 Howard Lewis Ship
Ahead of Time Compilation
        app/fragments.clj

       (ns app.fragments
         (:import (java.util Date)
                  (java.text DateFormat)))

       (defn format-date
         [env params]
         (…))




                            Compiler




        app/fragments__init.class


    app/fragments$format_date__21.class


                                       46    © 2009 Howard Lewis Ship
Ahead Of Time Compilation
 build.xml

    <target name="compile" description="Compile Clojure sources.">
      <mkdir dir="${classes.dir}" />

       <pathconvert pathsep=" " property="compile.namespaces">
         <fileset dir="${src.dir}" includes="**/*.clj" />
         <chainedmapper>
           <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" />
           <filtermapper>
             <replacestring from="_" to="-" />
           </filtermapper>
         </chainedmapper>
       </pathconvert>

      <java classname="clojure.lang.Compile">
        <classpath>
          <path refid="libs.path" />
          <path location="${classes.dir}" />
          <path location="${src.dir}" />
        </classpath>
        <sysproperty key="clojure.compile.path" value="${classes.dir}" />
        <arg line="${compile.namespaces}" />
      </java>
    </target>




                                         47                                 © 2009 Howard Lewis Ship
Ahead Of Time Compilation
 build.xml

    <target name="compile" description="Compile Clojure sources.">
      <mkdir dir="${classes.dir}" />

       <pathconvert pathsep=" " property="compile.namespaces">
         <fileset dir="${src.dir}" includes="**/*.clj" />
         <chainedmapper>
           <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" />
           <filtermapper>
             <replacestring from="_" to="-" />
           </filtermapper>                                      Locate *.clj under
         </chainedmapper>                                       ${src.dir} and convert       to
       </pathconvert>
                                                                 namespace names
      <java classname="clojure.lang.Compile">
        <classpath>
          <path refid="libs.path" />
          <path location="${classes.dir}" />
          <path location="${src.dir}" />
        </classpath>
        <sysproperty key="clojure.compile.path" value="${classes.dir}" />
        <arg line="${compile.namespaces}" />
      </java>
    </target>




                                         48                                 © 2009 Howard Lewis Ship
Ahead Of Time Compilation
 build.xml

    <target name="compile" description="Compile Clojure sources.">
      <mkdir dir="${classes.dir}" />

       <pathconvert pathsep=" " property="compile.namespaces">
         <fileset dir="${src.dir}" includes="**/*.clj" />
         <chainedmapper>
           <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" />
           <filtermapper>
             <replacestring from="_" to="-" />
           </filtermapper>
         </chainedmapper>
       </pathconvert>                                   clojure.jar, source
      <java classname="clojure.lang.Compile">
                                                         directory and output
        <classpath>                                    directory must be on
          <path refid="libs.path" />                   classpath
          <path location="${classes.dir}" />
          <path location="${src.dir}" />
        </classpath>
        <sysproperty key="clojure.compile.path" value="${classes.dir}" />
        <arg line="${compile.namespaces}" />
      </java>
    </target>




                                          49                                    © 2009 Howard Lewis Ship
Ahead Of Time Compilation
 build.xml

    <target name="compile" description="Compile Clojure sources.">
      <mkdir dir="${classes.dir}" />

       <pathconvert pathsep=" " property="compile.namespaces">
         <fileset dir="${src.dir}" includes="**/*.clj" />
         <chainedmapper>
           <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" />
           <filtermapper>
             <replacestring from="_" to="-" />
           </filtermapper>
         </chainedmapper>
       </pathconvert>
                                                  Output directory for
      <java classname="clojure.lang.Compile">     generated classes
        <classpath>
          <path refid="libs.path" />
          <path location="${classes.dir}" />
          <path location="${src.dir}" />
        </classpath>
        <sysproperty key="clojure.compile.path" value="${classes.dir}" />
        <arg line="${compile.namespaces}" />
      </java>
    </target>
                                  List of namespaces to
                                  compile
                                         50                                 © 2009 Howard Lewis Ship
Clojure Pitfalls
       51          © 2009 Howard Lewis Ship
IDE Support




              52   © 2009 Howard Lewis Ship
Laziness

           RuntimeException:
             Divide by zero




             53                © 2009 Howard Lewis Ship
Laziness
Clojure 1.0.0-
1:1 user=> (def nums (map / (range 0 10) (reverse (range 0 10))))
#'user/nums
1:2 user=> nums
java.lang.ArithmeticException: Divide by zero
(0 1/8 2/7 1/2 4/5 5/4 2 7/2 1:3 user=> (.. *e getCause printStackTrace)
java.lang.ArithmeticException: Divide by zero
    at clojure.lang.Numbers.divide(Numbers.java:138)
    at clojure.core$_SLASH___3350.invoke(core.clj:575)
    at clojure.core$map__3815$fn__3822.invoke(core.clj:1508)
    at clojure.lang.LazySeq.seq(LazySeq.java:41)
    at clojure.lang.Cons.next(Cons.java:37)
    at clojure.lang.RT.next(RT.java:560)
    at clojure.core$next__3117.invoke(core.clj:50)
    at clojure.core$nthnext__4405.invoke(core.clj:2531)
    at clojure.core$print_sequential__5354.invoke(core_print.clj:53)
    at clojure.core$fn__5439.invoke(core_print.clj:136)
    at clojure.lang.MultiFn.invoke(MultiFn.java:161)
    at clojure.core$pr_on__4145.invoke(core.clj:2020)
    at clojure.core$pr__4148.invoke(core.clj:2030)
    at clojure.lang.AFn.applyToHelper(AFn.java:173)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply__3243.doInvoke(core.clj:390)
    at clojure.lang.RestFn.invoke(RestFn.java:428)
    at clojure.core$prn__4159.doInvoke(core.clj:2053)
    at clojure.lang.RestFn.invoke(RestFn.java:413)
    at clojure.main$repl__5813$read_eval_print__5825.invoke(main.clj:177)
    at clojure.main$repl__5813.doInvoke(main.clj:193)
    at clojure.lang.RestFn.invoke(RestFn.java:876)
    at clojure.contrib.repl_ln$repl__84.doInvoke(repl_ln.clj:259)
    at clojure.lang.RestFn.invoke(RestFn.java:426)
    at clojure.contrib.repl_ln$_main__44.doInvoke(repl_ln.clj:136)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.contrib.repl_ln.main(Unknown Source)
nil
1:7 user=>

                                                  54                        © 2009 Howard Lewis Ship
Lack of Type Checking




           55           © 2009 Howard Lewis Ship
Spot the Error
view_manager.clj

(defn to-dom-node-seq
  [any]
  "Converts the result of a render function to a seq as needed."
  (cond
    (nil? any) nil

      (sequential? any) any

      ; A map is assumed to be a DOM node, wrap it in a vector
      (map? any) [map]

      (string? any) [(struct-map dom-node :type :text :value any)]

    true (throw (RuntimeException. (format "A rendering function returned %s. ↵
Rendering functions should return nil, a string, a seq of DOM nodes, or a single ↵
DOM node."
    (pr-str any))))))




                                           56                              © 2009 Howard Lewis Ship
Exception

ERROR in (simple-view-and-fragment) (test_is.clj:657)
Uncaught exception, not in assertion.
expected: nil
  actual: java.lang.IllegalArgumentException: Wrong number of args passed to: core$map
 at clojure.lang.AFn.throwArity (AFn.java:449)
    clojure.lang.RestFn.invoke (RestFn.java:417)
    com.howardlewisship.cascade.dom$fn__960.doInvoke (dom.clj:58)
    clojure.lang.RestFn.invoke (RestFn.java:443)
    clojure.lang.MultiFn.invoke (MultiFn.java:165)
    com.howardlewisship.cascade.dom/render_xml_with_ns (dom.clj:118)
    com.howardlewisship.cascade.dom/render_xml (dom.clj:125)
    com.howardlewisship.cascade.test_views/render (test_views.clj:27)
    com.howardlewisship.cascade.test_views/test_view (test_views.clj:56)
    com.howardlewisship.cascade.test_views/test_view (test_views.clj:52)
    com.howardlewisship.cascade.test_views/fn (test_views.clj:62)




                    dom.clj

                    (defmulti render-node-xml
                      (fn [node & rest]
                        (node :type)))




                                         57                                © 2009 Howard Lewis Ship
Spot the Error
view_manager.clj

(defn to-dom-node-seq
  [any]
  "Converts the result of a render function to a seq as needed."
  (cond
    (nil? any) nil

      (sequential? any) any

      ; A map is assumed to be a DOM node, wrap it in a vector
      (map? any) [map]

      (string? any) [(struct-map dom-node :type :text :value any)]

    true (throw (RuntimeException. (format "A rendering function returned %s. ↵
Rendering functions should return nil, a string, a seq of DOM nodes, or a single ↵
DOM node."
    (pr-str any))))))



                      Returning function clojure.core/map;
                      should return any (the parameter)




                                           58                              © 2009 Howard Lewis Ship
Bus Factor




             59   © 2009 Howard Lewis Ship
GitHub Factor




           60   © 2009 Howard Lewis Ship
Performance




          61   © 2009 Howard Lewis Ship
Performance
(defn shorts-to-bytes [#^shorts src #^bytes dst words]
 (loop [src-offset (int 0)
        dst-offset (int 0)]
   (when (< src-offset words)
     (let [sample (short (aget src src-offset))]
       (aset-byte dst dst-offset (byte sample))
       (aset-byte dst (inc dst-offset) (byte (bit-shift-right sample 8))))
     (recur (inc src-offset) (unchecked-add 2 dst-offset)))))



 public static void shortsToBytes(short[] src, byte[] dst, int len)
 {
  int idx = 0;                                                                                 900 ms
  short s;

  while (len-- > 0) {
    s = src[idx];
    dst[idx*2] = (byte)s;                                                                     675 ms
    dst[idx*2+1] = (byte)(s>>>8);
    idx++;
  }
 }
                                                                                             450 ms


                                                                                           225 ms


                                                                                          0 ms

                                                           Java              Clojure

                                                  62                                   © 2009 Howard Lewis Ship
API Docs




           63   © 2009 Howard Lewis Ship
Wrap Up


   64     © 2009 Howard Lewis Ship
What's Not Covered?
• multimethods ➠ inheritance-like function
  dispatch

• Concurrency Support ➠ atoms, agents, refs
  & vars
                                             http://www.clojure.org
• loop & recur ➠ iterative-style coding

• clojure.contrib ➠ Community library

• Macros & Meta-Programming ➠ Create the language you want inside
  Clojure

• Tuning Clojure Performance

• More ….
                                    65                       © 2009 Howard Lewis Ship
Stuart Halloway
                               Pragmatic Bookshelf




http://pragprog.com/titles/shcloj/programming-clojure
                          66                   © 2009 Howard Lewis Ship
http://jnb.ociweb.com/jnb/jnbMar2009.html




                   67                 © 2009 Howard Lewis Ship
Image Credits
   © 2005 Jean-Philippe Daigle
   http://www.flickr.com/photos/jpdaigle/59942231/
                                                        © 2007 Howard Gees
                         http://www.flickr.com/photos/cyberslayer/952121271/
   © 2006 Simon Law
   http://www.flickr.com/photos/sfllaw/222795669/
                                                          © 2008 II-cocoy22-II
                     http://www.flickr.com/photos/30954876@N07/3090155264/
   © 2009 Martin Biskoping
   http://www.flickr.com/photos/mbiskoping/3388639698/
                                                            © 2008 sea turtle
                          http://www.flickr.com/photos/sea-turtle/3049443478/
   © 2009 Tulio Bertorini
   http://www.flickr.com/photos/tuliobertorini/3159130251/
                                                          © 2007 Adam Balch
                       http://www.flickr.com/photos/triplemaximus/795758146/
   © 2008 jessamyn west
   http://www.flickr.com/photos/iamthebestartist/2636607001/




                                     68                                          © 2009 Howard Lewis Ship

More Related Content

What's hot

Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)Stephen Chin
 
Starting with Scala : Frontier Developer's Meetup December 2010
Starting with Scala : Frontier Developer's Meetup December 2010Starting with Scala : Frontier Developer's Meetup December 2010
Starting with Scala : Frontier Developer's Meetup December 2010Derek Chen-Becker
 
Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scalascalaconfjp
 
Introductionto fp with groovy
Introductionto fp with groovyIntroductionto fp with groovy
Introductionto fp with groovyIsuru Samaraweera
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scriptingmichid
 
C# Starter L04-Collections
C# Starter L04-CollectionsC# Starter L04-Collections
C# Starter L04-CollectionsMohammad Shaker
 
An Introduction to Scala for Java Developers
An Introduction to Scala for Java DevelopersAn Introduction to Scala for Java Developers
An Introduction to Scala for Java DevelopersMiles Sabin
 
Stepping Up : A Brief Intro to Scala
Stepping Up : A Brief Intro to ScalaStepping Up : A Brief Intro to Scala
Stepping Up : A Brief Intro to ScalaDerek Chen-Becker
 
Java OOP Programming language (Part 8) - Java Database JDBC
Java OOP Programming language (Part 8) - Java Database JDBCJava OOP Programming language (Part 8) - Java Database JDBC
Java OOP Programming language (Part 8) - Java Database JDBCOUM SAOKOSAL
 
Glorp Tutorial Guide
Glorp Tutorial GuideGlorp Tutorial Guide
Glorp Tutorial GuideESUG
 
Hjelp, vi skal kode funksjonelt i Java!
Hjelp, vi skal kode funksjonelt i Java!Hjelp, vi skal kode funksjonelt i Java!
Hjelp, vi skal kode funksjonelt i Java!Fredrik Vraalsen
 
C# v8 new features - raimundas banevicius
C# v8 new features - raimundas baneviciusC# v8 new features - raimundas banevicius
C# v8 new features - raimundas baneviciusRaimundas Banevičius
 

What's hot (20)

Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)
 
Starting with Scala : Frontier Developer's Meetup December 2010
Starting with Scala : Frontier Developer's Meetup December 2010Starting with Scala : Frontier Developer's Meetup December 2010
Starting with Scala : Frontier Developer's Meetup December 2010
 
Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scala
 
Introductionto fp with groovy
Introductionto fp with groovyIntroductionto fp with groovy
Introductionto fp with groovy
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scripting
 
Slickdemo
SlickdemoSlickdemo
Slickdemo
 
C# Starter L04-Collections
C# Starter L04-CollectionsC# Starter L04-Collections
C# Starter L04-Collections
 
Sql
SqlSql
Sql
 
An Introduction to Scala for Java Developers
An Introduction to Scala for Java DevelopersAn Introduction to Scala for Java Developers
An Introduction to Scala for Java Developers
 
scala
scalascala
scala
 
Workshop Scala
Workshop ScalaWorkshop Scala
Workshop Scala
 
All about scala
All about scalaAll about scala
All about scala
 
Scala - brief intro
Scala - brief introScala - brief intro
Scala - brief intro
 
Stepping Up : A Brief Intro to Scala
Stepping Up : A Brief Intro to ScalaStepping Up : A Brief Intro to Scala
Stepping Up : A Brief Intro to Scala
 
Java OOP Programming language (Part 8) - Java Database JDBC
Java OOP Programming language (Part 8) - Java Database JDBCJava OOP Programming language (Part 8) - Java Database JDBC
Java OOP Programming language (Part 8) - Java Database JDBC
 
Best Guide for Javascript Objects
Best Guide for Javascript ObjectsBest Guide for Javascript Objects
Best Guide for Javascript Objects
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
Glorp Tutorial Guide
Glorp Tutorial GuideGlorp Tutorial Guide
Glorp Tutorial Guide
 
Hjelp, vi skal kode funksjonelt i Java!
Hjelp, vi skal kode funksjonelt i Java!Hjelp, vi skal kode funksjonelt i Java!
Hjelp, vi skal kode funksjonelt i Java!
 
C# v8 new features - raimundas banevicius
C# v8 new features - raimundas baneviciusC# v8 new features - raimundas banevicius
C# v8 new features - raimundas banevicius
 

Viewers also liked

Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...
Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...
Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...JSI
 
Good to Great-WSJ
Good to Great-WSJGood to Great-WSJ
Good to Great-WSJKeith Darcy
 
COVER LETTER Oracle Forms Developer
COVER LETTER Oracle Forms DeveloperCOVER LETTER Oracle Forms Developer
COVER LETTER Oracle Forms DeveloperKiemy Vo
 
Designing Usage Dashboards for mHealth Program Monitoring
Designing Usage Dashboards for mHealth Program MonitoringDesigning Usage Dashboards for mHealth Program Monitoring
Designing Usage Dashboards for mHealth Program MonitoringJSI
 
Power distribution, operation and maintenance of comilla palli bidyut samity 1
Power distribution, operation and maintenance of comilla palli bidyut samity 1Power distribution, operation and maintenance of comilla palli bidyut samity 1
Power distribution, operation and maintenance of comilla palli bidyut samity 1Kawsar Ahmed
 
Augmented Reality and Google Glass
Augmented Reality and Google GlassAugmented Reality and Google Glass
Augmented Reality and Google GlassMarta Rauch
 
Resolucion banco oferentes
Resolucion banco oferentesResolucion banco oferentes
Resolucion banco oferentesmcriverah
 

Viewers also liked (11)

Zuberoa
ZuberoaZuberoa
Zuberoa
 
Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...
Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...
Impact Team Network: A Case in Kenya - Unlocking Bottlenecks in Public Health...
 
Good to Great-WSJ
Good to Great-WSJGood to Great-WSJ
Good to Great-WSJ
 
COVER LETTER Oracle Forms Developer
COVER LETTER Oracle Forms DeveloperCOVER LETTER Oracle Forms Developer
COVER LETTER Oracle Forms Developer
 
Designing Usage Dashboards for mHealth Program Monitoring
Designing Usage Dashboards for mHealth Program MonitoringDesigning Usage Dashboards for mHealth Program Monitoring
Designing Usage Dashboards for mHealth Program Monitoring
 
Grezia
GreziaGrezia
Grezia
 
Kroazia
KroaziaKroazia
Kroazia
 
Power distribution, operation and maintenance of comilla palli bidyut samity 1
Power distribution, operation and maintenance of comilla palli bidyut samity 1Power distribution, operation and maintenance of comilla palli bidyut samity 1
Power distribution, operation and maintenance of comilla palli bidyut samity 1
 
Alamat ng ampalaya
Alamat ng ampalayaAlamat ng ampalaya
Alamat ng ampalaya
 
Augmented Reality and Google Glass
Augmented Reality and Google GlassAugmented Reality and Google Glass
Augmented Reality and Google Glass
 
Resolucion banco oferentes
Resolucion banco oferentesResolucion banco oferentes
Resolucion banco oferentes
 

Similar to Clojure Deep Dive

Clojure Intro
Clojure IntroClojure Intro
Clojure Introthnetos
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Howard Lewis Ship
 
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)Howard Lewis Ship
 
(first '(Clojure.))
(first '(Clojure.))(first '(Clojure.))
(first '(Clojure.))niklal
 
Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기JangHyuk You
 
PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...
PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...
PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...Puppet
 
Clojure: Towards The Essence of Programming
Clojure: Towards The Essence of ProgrammingClojure: Towards The Essence of Programming
Clojure: Towards The Essence of ProgrammingHoward Lewis Ship
 
The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)jaxLondonConference
 
Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2Henry S
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghStuart Roebuck
 
Getting started with Clojure
Getting started with ClojureGetting started with Clojure
Getting started with ClojureJohn Stevenson
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - StockholmJan Kronquist
 
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...Eelco Visser
 
A Brief Introduction to Scala for Java Developers
A Brief Introduction to Scala for Java DevelopersA Brief Introduction to Scala for Java Developers
A Brief Introduction to Scala for Java DevelopersMiles Sabin
 
Miles Sabin Introduction To Scala For Java Developers
Miles Sabin Introduction To Scala For Java DevelopersMiles Sabin Introduction To Scala For Java Developers
Miles Sabin Introduction To Scala For Java DevelopersSkills Matter
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
Леонид Шевцов «Clojure в деле»
Леонид Шевцов «Clojure в деле»Леонид Шевцов «Clojure в деле»
Леонид Шевцов «Clojure в деле»DataArt
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?osfameron
 

Similar to Clojure Deep Dive (20)

Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Codemash-Clojure.pdf
Codemash-Clojure.pdfCodemash-Clojure.pdf
Codemash-Clojure.pdf
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)
 
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
 
Pune Clojure Course Outline
Pune Clojure Course OutlinePune Clojure Course Outline
Pune Clojure Course Outline
 
(first '(Clojure.))
(first '(Clojure.))(first '(Clojure.))
(first '(Clojure.))
 
Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기
 
PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...
PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...
PuppetConf 2017: What's in a Name? Scaling ENC with DNS- Cameron Nicholson, A...
 
Clojure: Towards The Essence of Programming
Clojure: Towards The Essence of ProgrammingClojure: Towards The Essence of Programming
Clojure: Towards The Essence of Programming
 
The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)
 
Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 
Getting started with Clojure
Getting started with ClojureGetting started with Clojure
Getting started with Clojure
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - Stockholm
 
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
 
A Brief Introduction to Scala for Java Developers
A Brief Introduction to Scala for Java DevelopersA Brief Introduction to Scala for Java Developers
A Brief Introduction to Scala for Java Developers
 
Miles Sabin Introduction To Scala For Java Developers
Miles Sabin Introduction To Scala For Java DevelopersMiles Sabin Introduction To Scala For Java Developers
Miles Sabin Introduction To Scala For Java Developers
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Леонид Шевцов «Clojure в деле»
Леонид Шевцов «Clojure в деле»Леонид Шевцов «Clojure в деле»
Леонид Шевцов «Clojure в деле»
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?
 

More from Howard Lewis Ship

Testing Web Applications with GEB
Testing Web Applications with GEBTesting Web Applications with GEB
Testing Web Applications with GEBHoward Lewis Ship
 
Spock: A Highly Logical Way To Test
Spock: A Highly Logical Way To TestSpock: A Highly Logical Way To Test
Spock: A Highly Logical Way To TestHoward Lewis Ship
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserHoward Lewis Ship
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapHoward Lewis Ship
 
Have Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for JavaHave Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for JavaHoward Lewis Ship
 
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)Howard Lewis Ship
 
Arduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd PerspectiveArduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd PerspectiveHoward Lewis Ship
 
Practical Clojure Programming
Practical Clojure ProgrammingPractical Clojure Programming
Practical Clojure ProgrammingHoward Lewis Ship
 
Tapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting EaseTapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting EaseHoward Lewis Ship
 
Brew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with CappuccinoBrew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with CappuccinoHoward Lewis Ship
 
Tapestry: State of the Union
Tapestry: State of the UnionTapestry: State of the Union
Tapestry: State of the UnionHoward Lewis Ship
 

More from Howard Lewis Ship (13)

Testing Web Applications with GEB
Testing Web Applications with GEBTesting Web Applications with GEB
Testing Web Applications with GEB
 
Spock: A Highly Logical Way To Test
Spock: A Highly Logical Way To TestSpock: A Highly Logical Way To Test
Spock: A Highly Logical Way To Test
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter Bootstrap
 
Have Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for JavaHave Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for Java
 
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
 
Arduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd PerspectiveArduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd Perspective
 
Practical Clojure Programming
Practical Clojure ProgrammingPractical Clojure Programming
Practical Clojure Programming
 
Codemash-Tapestry.pdf
Codemash-Tapestry.pdfCodemash-Tapestry.pdf
Codemash-Tapestry.pdf
 
Tapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting EaseTapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting Ease
 
Brew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with CappuccinoBrew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with Cappuccino
 
Cascade
CascadeCascade
Cascade
 
Tapestry: State of the Union
Tapestry: State of the UnionTapestry: State of the Union
Tapestry: State of the Union
 

Recently uploaded

SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 

Recently uploaded (20)

SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 

Clojure Deep Dive

  • 1. Clojure Deep Dive Howard M. Lewis Ship TWD Consulting hlship@gmail.com 1 © 2009 Howard Lewis Ship
  • 2. Agenda • Core Language • Standard Tools • Clojure Compilation • Clojure Pitfalls 2 © 2009 Howard Lewis Ship
  • 3. Core Language 3 © 2009 Howard Lewis Ship
  • 4. What's A Form? Constants: Keywords: Symbols: 42 :foo map "hello" :tag strutils2/take Data Structures: […] {…} #{ … } Callables: Special Forms: Function Call: Macros Expansion: (if …) (map …) (and …) (var …) (or …) (do …) (ns …) 4 © 2009 Howard Lewis Ship
  • 5. defn: Define a function Symbol (in current namespace) Optional doc string (defn to-seq "Converts the object to a sequence (a vector) unless it is already sequential." [obj] (if (sequential? obj) obj [obj])) List of parameters user=> (doc to-seq) ------------------------- user/to-seq ([obj]) Converts the object to a sequence (a vector) unless it is already sequential. nil user=> 5 © 2009 Howard Lewis Ship
  • 6. defn: Multiple Arities One doc string Series of argument lists / forms (defn not= "Same as (not (= obj1 obj2))" ([x] false) ([x y] (not (= x y))) ([x y & more] (not (apply = x y more)))) & symbol ➠ provide remaining values as a seq user=> (doc not=) ------------------------- clojure.core/not= ([x] [x y] [x y & more]) Same as (not (= obj1 obj2)) nil user=> 6 © 2009 Howard Lewis Ship
  • 7. let: local symbols (let [center (calc-center-for-frame frame) x (get-x center) y (get-y center)] …) •Even number: symbol1 form1 symbol2 form2 … •Not variables: symbols are read-only •Can re-define symbols 7 © 2009 Howard Lewis Ship
  • 8. do: evaluate for side-effects (if value-found (do (println "Found the value.") value-found)) Last form is the result ; Broken (if value-found (println "Found the value.") If true, side effect & return nil value-found) If false, return value (false or nil) 8 © 2009 Howard Lewis Ship
  • 9. Branching: if, when (if test then-form) (if test then-form else-form) • Special form: not a function • Evaluates test, then evaluates & returns either then-form or else-form • false and nil ➠ logical false • anything else ➠ logical true (when test then-forms) (if-not test then-form) (if-not test then-form else-form) Any number of forms in an implicit do Like (if (not test) then else) (when-not test then-forms) 9 © 2009 Howard Lewis Ship
  • 10. if-let, when-let (if-let [symbol test] then-form) (if-let [symbol test] then-form else-form) Symbol can be referenced (when-let [symbol test] then-forms) Any number of forms in an implicit do 10 © 2009 Howard Lewis Ship
  • 11. or, and (or form…) (and form…) • or: first value from list that evaluates to true • Will return value of last expression (false or nil) • (or) returns nil • and: first logical false (nil or false) • Returns value of last expression (if prior are logical true) • (and) return true • Can be used as a "guard" Only invoke symbol and find-ns (defn dispatch-named-function-to-pipeline if ns-name is non-nil [env pipeline] (let [split-path (-> env :cascade :split-path) [_ ns-name fn-name] split-path fn-namespace (and ns-name (find-ns (symbol ns-name))) named-function (and fn-namespace fn-name (ns-resolve fn-namespace (symbol fn-name))) new-env (assoc-in env [:cascade :extra-path] (drop 3 split-path))] (call-pipeline pipeline new-env named-function))) 11 © 2009 Howard Lewis Ship
  • 12. Destructuring Bu N wo sy o rk • Automatically extract values from data structures ! • Binding forms: • Map to extract keys • Vector to extract indexed values • Function parameters One un-named parameter • let, if-let, when-let, etc. destructured to two symbols user=> (defn natural-name [{fname :first-name lname :last-name}] (str lname ", " fname)) #'user/natural-name user=> (natural-name (persons 1)) "Simon, Scott" user=> 12 © 2009 Howard Lewis Ship
  • 13. Destructuring • Binding Forms: • symbol (let [x (get-x center)] … ) • vector of binding forms (let [[x y] center] … ) • map of binding form to map key (let [{fname :first-name lname :last-name} person] …) 13 © 2009 Howard Lewis Ship
  • 14. Vector Destructuring center must be sequential (let [[x y] center] …) May be nil if not enough values in center (let [[first-born second-born & other-children] children] …) & symbol gets the remaining values (let [[first-born second-born & other-children :as children] (find-children parent)] …) Nested binding forms! :as symbol gets the full list user=> (let [[[x1 y1][x2 y2]] [[1 2] [3 4]]] [x1 y1 x2 y2]) [1 2 3 4] user=> 14 © 2009 Howard Lewis Ship
  • 15. Map Destructuring (defn natural-name [{fname :first-name lname :last-name}] (str lname ", " fname)) (defn natural-name [{:keys [first-name last-name]}] (str last-name ", " first-name)) :keys maps a keyword key for each symbol :or sets defaults for missing keys user=> (defn natural-name [{:keys [first-name last-name] :or {first-name "(none)" last-name "(none)"}}] (str last-name ", " first-name)) #'user/natural-name user=> (natural-name {:first-name "Gromit"}) "(none), Gromit" user=> (natural-name {:first-name "Gromit" :last-name nil}) ", Gromit" user=> :as symbol to get the original map :strs ➠ like :keys, but maps to string keys, not keyword keys :syms ➠ like :keys, but maps to symbol keys, not keyword keys 15 © 2009 Howard Lewis Ship
  • 16. ns: define namespaces (ns example.utils) cascade/dispatcher.clj (ns cascade.dispatcher (:import (javax.servlet ServletResponse)) File: example/utils.clj (:use (cascade config dom logging path-map pipeline) (cascade.internal utils))) (ns namespace (:import …) Optional directives (:use …)) user=> (defn natural-name [{fname :first-name lname :last-name}] (str lname ", " fname)) #'user/natural-name user=> (natural-name (persons 1)) "Simon, Scott" user=> user/natural-name Namespace: user Symbol: natural-name 16 © 2009 Howard Lewis Ship
  • 17. :import Java Classes Package name, then any number of classes/interfaces (ns cascade.dispatcher (:import (javax.servlet ServletResponse)) …) Repeat for other packages Can also list fully qualify class names 17 © 2009 Howard Lewis Ship
  • 18. :use Import Namespaces (:use clojure.contrib.pprint) Symbols defined by pprint are available, i.e. (pprint [1 2 3]) (:use (clojure.contrib pprint monads)) Add multiple namespaces under the root namespace (:use (clojure.contrib (str-utils2 :only [join map-str])) Uses just join and map-str from str-utils2 (:use (clojure.contrib (str-utils2 :exclude [take replace drop])) Exclude just some of the symbols (:use (clojure.contrib (str-utils2 :rename {take strtake})) Use str-utils2, mapping take as strtake 18 © 2009 Howard Lewis Ship
  • 19. Other ns directives • :require ➠ load a namespace but don't import it • :gen-class ➠ create a Java class from functions in the namespace • :refer-clojure ➠ import selected clojure.core symbols • :load ➠ load Clojure scripts (not namespaces) 19 © 2009 Howard Lewis Ship
  • 20. Standard Tools 20 © 2009 Howard Lewis Ship
  • 21. Anonymous Functions #() ➠ implicit anonymous function (filter #(not (.startsWith % ".")) names) % is replaced by the function's parameter %n is parameter #n (map #(assoc %1 :sort-index %2) (sort-by :age persons) (iterate inc 0)) inline anonymous function (map 21 (fn [person-map sort-index] (assoc person-map :sort-index sort-index)) (sort-by :age persons) (iterate inc 0)) © 2009 Howard Lewis Ship
  • 22. What are seqs? Seqable seq() : ISeq IPersistentCollection Sequential count() : int cons(Object): IPersistentCollection empty() : IPersistentCollection equiv(Object) : boolean PersistentSet ISeq first() : Object next(): ISeq more(): ISeq cons(Object): ISeq Returned from map, for, filter, remove, etc. PersistentList PersistentVector LazySeq 22 © 2009 Howard Lewis Ship
  • 23. assoc-in / update-in user=> (def person { :first-name "Howard" :last-name "Lewis Ship" :address { :street "123 NW 12th Ave. #541" :city "Portland" :state "OR" :zip 97309 }}) #'user/person user=> (assoc-in person [:address :street] "2647 SE 97th Ave.") {:first-name "Howard", :last-name "Lewis Ship", :address {:street "2647 SE 97th Ave.", :city "Portland", :state "OR", :zip 97309}} user=> (update-in person [:address :zip] + 5) {:first-name "Howard", :last-name "Lewis Ship", :address {:street "123 NW 12th Ave. #541", :city "Portland", :state "OR", :zip 97314}} user=> :first-name "Howard" :last-name "Lewis Ship" :address :street "123 NW 12th Ave." :city "Portland" :state "OR" :zip 97309 (update-in person [:address :zip] + 5) (+ 97309 5) :first-name "Howard" :last-name "Lewis Ship" :address :street "123 NW 12th Ave." :city "Portland" :state "OR" :zip 97314 23 © 2009 Howard Lewis Ship
  • 24. map La zy f :age acts as a function user=> (map :age persons) (42 44 29) user=> (map #(apply str (reverse (% :first-name))) persons) ("drawoH" "ttocS" "ylloM") user=> (map identity (persons 0)) ([:first-name "Howard"] iterate a map ➠ key/value pairs [:last-name "Lewis Ship"] [:age 42]) user=> (seq (persons 0)) ([:first-name "Howard"] [:last-name "Lewis Ship"] [:age 42]) user=> 24 © 2009 Howard Lewis Ship
  • 25. map La zy f N seqs ➠ N parameters user=> (map #(assoc %1 :sort-index %2) (sort-by :age persons) (iterate inc 0)) ({:sort-index 0, :first-name "Molly", :last-name "Newman", :age 29} {:sort-index 1, :first-name "Howard", :last-name "Lewis Ship", :age 42} {:sort-index 2, :first-name "Scott", :last-name "Simon", :age 44}) user=> 25 © 2009 Howard Lewis Ship
  • 26. reduce f user=> (map :age persons) (42 44 29 38) user=> (reduce + (map :age persons)) 153 (reduce + (map :age persons)) 26 © 2009 Howard Lewis Ship
  • 27. reduce f user=> (map :age persons) (42 44 29 38) user=> (reduce + (map :age persons)) 153 (reduce + (map :age persons)) (reduce + '(42 44 29 38)) 27 © 2009 Howard Lewis Ship
  • 28. reduce f user=> (map :age persons) (42 44 29 38) user=> (reduce + (map :age persons)) 153 (reduce + (map :age persons)) (reduce + '(42 44 29 38)) (+ (+ (+ 42 44) 29) 38) 28 © 2009 Howard Lewis Ship
  • 29. reduce f user=> (map :age persons) (42 44 29 38) user=> (reduce + (map :age persons)) 153 (reduce + (map :age persons)) (reduce + '(42 44 29 38)) (+ (+ (+ 42 44) 29) 38) (+ (+ 86 29) 38) 29 © 2009 Howard Lewis Ship
  • 30. reduce f user=> (map :age persons) (42 44 29 38) user=> (reduce + (map :age persons)) 153 (reduce + (map :age persons)) (reduce + '(42 44 29 38)) (+ (+ (+ 42 44) 29) 38) (+ (+ 86 29) 38) (+ 115 38) 30 © 2009 Howard Lewis Ship
  • 31. reduce f user=> (map :age persons) (42 44 29 38) user=> (reduce + (map :age persons)) 153 (reduce + (map :age persons)) (reduce + '(42 44 29 38)) (+ (+ (+ 42 44) 29) 38) (+ (+ 86 29) 38) (+ 115 38) 153 31 © 2009 Howard Lewis Ship
  • 32. reduce f user=> (def input-string "Clojure is a fascinating language with unique capabilities and total integration with Java.") #'user/input-string user=> (seq input-string) (C l o j u r e space i s space a space f a s c i n a t i n g space l a n g u a g e space w i t h space u n i q u e space c a p a b i l i t i e s space a n d space t o t a l space i n t e g r a t i o n space w i t h space J a v a .) user=> (reduce (fn [m k] (update-in m [k] #(if (nil? %) 1 (inc %)))) Optional initial value {} (seq input-string)) {space 12, a 12, b 1, C 1, c 2, d 1, e 5, f 1, g 4, h 2, i 11, J 1, j 1, l 4, . 1, n 7, o 3, p 1, q 1, r 2, s 3, t 8, u 4, v 1, w 2} user=> 32 © 2009 Howard Lewis Ship
  • 33. filter / remove La zy f ? user=> (remove #(< (% :age) 30) persons) ({:first-name "Howard", :last-name "Lewis Ship", :age 42} {:first-name "Scott", :last-name "Simon", :age 44}) user=> (filter #(< (% :age) 30) persons) ({:first-name "Molly", :last-name "Newman", :age 29}) user=> 33 © 2009 Howard Lewis Ship
  • 34. apply f user=> (map :age persons) (42 44 29) user=> (apply + (map :age persons)) 115 user=> (apply + (map :age persons)) (apply + '(42 44 29)) (+ 42 44 29) 115 34 © 2009 Howard Lewis Ship
  • 35. Clojure Compilation 35 © 2009 Howard Lewis Ship
  • 36. Function Calls (remove nil? coll) IFn invoke() : Object invoke(Object) : Object Namespace invoke(Object, Object) : Object … applyTo(ISeq) : Object Var get() clojure.core$remove__4782 PersistentMap Keyword 36 © 2009 Howard Lewis Ship
  • 37. Compiled to Bytecode (defn first-non-nil "Returns the first non-nil value from the collection." [coll] (first (remove nil? coll))) package com.howardlewisship.cascade.internal; import clojure.lang.*; public class utils$first_non_nil__24 extends AFunction { public Object invoke(Object coll) throws Exception { return ((IFn)const__0.get()).invoke(((IFn)const__1.get()). invoke(const__2.get(), coll = null)); } public static final Var const__0 = (Var)RT.var("clojure.core", "first"); public static final Var const__1 = (Var)RT.var("clojure.core", "remove"); public static final Var const__2 = (Var)RT.var("clojure.core", "nil?"); public utils$first_non_nil__24() { } } 37 © 2009 Howard Lewis Ship
  • 38. Compiled to Bytecode (defn first-non-nil "Returns the first non-nil value from the collection." [coll] (first (remove nil? coll))) package com.howardlewisship.cascade.internal; import clojure.lang.*; public class utils$first_non_nil__24 extends AFunction { public Object invoke(Object coll) throws Exception { return ((IFn)const__0.get()).invoke(((IFn)const__1.get()). invoke(const__2.get(), coll = null)); } public static final Var const__0 = (Var)RT.var("clojure.core", "first"); public static final Var const__1 = (Var)RT.var("clojure.core", "remove"); public static final Var const__2 = (Var)RT.var("clojure.core", "nil?"); public utils$first_non_nil__24() { } } 38 © 2009 Howard Lewis Ship
  • 39. Compiled to Bytecode (defn first-non-nil "Returns the first non-nil value from the collection." [coll] (first (remove nil? coll))) package com.howardlewisship.cascade.internal; import clojure.lang.*; public class utils$first_non_nil__24 extends AFunction { public Object invoke(Object coll) throws Exception { return ((IFn)const__0.get()).invoke(((IFn)const__1.get()). invoke(const__2.get(), coll = null)); } public static final Var const__0 = (Var)RT.var("clojure.core", "first"); public static final Var const__1 = (Var)RT.var("clojure.core", "remove"); public static final Var const__2 = (Var)RT.var("clojure.core", "nil?"); public utils$first_non_nil__24() { } } 39 © 2009 Howard Lewis Ship
  • 40. Compiled to Bytecode (defn first-non-nil "Returns the first non-nil value from the collection." [coll] (first (remove nil? coll))) package com.howardlewisship.cascade.internal; import clojure.lang.*; public class utils$first_non_nil__24 extends AFunction { public Object invoke(Object coll) throws Exception { return ((IFn)const__0.get()).invoke(((IFn)const__1.get()). invoke(const__2.get(), coll = null)); } public static final Var const__0 = (Var)RT.var("clojure.core", "first"); public static final Var const__1 = (Var)RT.var("clojure.core", "remove"); public static final Var const__2 = (Var)RT.var("clojure.core", "nil?"); public utils$first_non_nil__24() { } } 40 © 2009 Howard Lewis Ship
  • 41. Compiled to Bytecode (defn format-date [env params] (let [#^Date date (params :date) package app1; #^DateFormat fmt (DateFormat/getDateTimeInstance DateFormat/MEDIUM import clojure.lang.*; DateFormat/MEDIUM)] import java.text.DateFormat; (.format fmt date))) import java.util.Date; public class fragments$format_date__21 extends AFunction { public Object invoke(Object env, Object params) throws Exception { Object date = ((IFn)params).invoke(const__1); Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); env = null; params = null; date = null; fmt = null; return ((DateFormat)fmt).format((Date)date); } public static final Var const__0 = (Var)RT.var("clojure.core", "let"); public static final Object const__1 = Keyword.intern(Symbol.create(null, "date")); public fragments$format_date__21() { } } 41 © 2009 Howard Lewis Ship
  • 42. Compiled to Bytecode (defn format-date [env params] (let [#^Date date (params :date) package app1; #^DateFormat fmt (DateFormat/getDateTimeInstance DateFormat/MEDIUM import clojure.lang.*; DateFormat/MEDIUM)] import java.text.DateFormat; (.format fmt date))) import java.util.Date; public class fragments$format_date__21 extends AFunction { public Object invoke(Object env, Object params) throws Exception { Object date = ((IFn)params).invoke(const__1); Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); env = null; params = null; date = null; fmt = null; return ((DateFormat)fmt).format((Date)date); } public static final Var const__0 = (Var)RT.var("clojure.core", "let"); public static final Object const__1 = Keyword.intern(Symbol.create(null, "date")); public fragments$format_date__21() { } } 42 © 2009 Howard Lewis Ship
  • 43. Compiled to Bytecode (defn format-date [env params] (let [#^Date date (params :date) package app1; #^DateFormat fmt (DateFormat/getDateTimeInstance DateFormat/MEDIUM import clojure.lang.*; DateFormat/MEDIUM)] import java.text.DateFormat; (.format fmt date))) import java.util.Date; public class fragments$format_date__21 extends AFunction { public Object invoke(Object env, Object params) throws Exception { Object date = ((IFn)params).invoke(const__1); Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); env = null; params = null; date = null; fmt = null; return ((DateFormat)fmt).format((Date)date); } public static final Var const__0 = (Var)RT.var("clojure.core", "let"); public static final Object const__1 = Keyword.intern(Symbol.create(null, "date")); public fragments$format_date__21() { } } 43 © 2009 Howard Lewis Ship
  • 44. Compiled to Bytecode (defn format-date [env params] (let [#^Date date (params :date) package app1; #^DateFormat fmt (DateFormat/getDateTimeInstance DateFormat/MEDIUM import clojure.lang.*; DateFormat/MEDIUM)] import java.text.DateFormat; (.format fmt date))) import java.util.Date; public class fragments$format_date__21 extends AFunction { public Object invoke(Object env, Object params) throws Exception { Object date = ((IFn)params).invoke(const__1); Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); env = null; params = null; date = null; fmt = null; return ((DateFormat)fmt).format((Date)date); } public static final Var const__0 = (Var)RT.var("clojure.core", "let"); public static final Object const__1 = Keyword.intern(Symbol.create(null, "date")); public fragments$format_date__21() { } } 44 © 2009 Howard Lewis Ship
  • 45. Compiled to Bytecode (defn format-date [env params] (let [#^Date date (params :date) package app1; #^DateFormat fmt (DateFormat/getDateTimeInstance DateFormat/MEDIUM import clojure.lang.*; DateFormat/MEDIUM)] import java.text.DateFormat; (.format fmt date))) import java.util.Date; public class fragments$format_date__21 extends AFunction { public Object invoke(Object env, Object params) throws Exception { Object date = ((IFn)params).invoke(const__1); Object fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); env = null; params = null; date = null; fmt = null; return ((DateFormat)fmt).format((Date)date); } public static final Var const__0 = (Var)RT.var("clojure.core", "let"); public static final Object const__1 = Keyword.intern(Symbol.create(null, "date")); public fragments$format_date__21() { } } 45 © 2009 Howard Lewis Ship
  • 46. Ahead of Time Compilation app/fragments.clj (ns app.fragments (:import (java.util Date) (java.text DateFormat))) (defn format-date [env params] (…)) Compiler app/fragments__init.class app/fragments$format_date__21.class 46 © 2009 Howard Lewis Ship
  • 47. Ahead Of Time Compilation build.xml <target name="compile" description="Compile Clojure sources."> <mkdir dir="${classes.dir}" /> <pathconvert pathsep=" " property="compile.namespaces"> <fileset dir="${src.dir}" includes="**/*.clj" /> <chainedmapper> <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" /> <filtermapper> <replacestring from="_" to="-" /> </filtermapper> </chainedmapper> </pathconvert> <java classname="clojure.lang.Compile"> <classpath> <path refid="libs.path" /> <path location="${classes.dir}" /> <path location="${src.dir}" /> </classpath> <sysproperty key="clojure.compile.path" value="${classes.dir}" /> <arg line="${compile.namespaces}" /> </java> </target> 47 © 2009 Howard Lewis Ship
  • 48. Ahead Of Time Compilation build.xml <target name="compile" description="Compile Clojure sources."> <mkdir dir="${classes.dir}" /> <pathconvert pathsep=" " property="compile.namespaces"> <fileset dir="${src.dir}" includes="**/*.clj" /> <chainedmapper> <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" /> <filtermapper> <replacestring from="_" to="-" /> </filtermapper> Locate *.clj under </chainedmapper> ${src.dir} and convert to </pathconvert> namespace names <java classname="clojure.lang.Compile"> <classpath> <path refid="libs.path" /> <path location="${classes.dir}" /> <path location="${src.dir}" /> </classpath> <sysproperty key="clojure.compile.path" value="${classes.dir}" /> <arg line="${compile.namespaces}" /> </java> </target> 48 © 2009 Howard Lewis Ship
  • 49. Ahead Of Time Compilation build.xml <target name="compile" description="Compile Clojure sources."> <mkdir dir="${classes.dir}" /> <pathconvert pathsep=" " property="compile.namespaces"> <fileset dir="${src.dir}" includes="**/*.clj" /> <chainedmapper> <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" /> <filtermapper> <replacestring from="_" to="-" /> </filtermapper> </chainedmapper> </pathconvert> clojure.jar, source <java classname="clojure.lang.Compile"> directory and output <classpath> directory must be on <path refid="libs.path" /> classpath <path location="${classes.dir}" /> <path location="${src.dir}" /> </classpath> <sysproperty key="clojure.compile.path" value="${classes.dir}" /> <arg line="${compile.namespaces}" /> </java> </target> 49 © 2009 Howard Lewis Ship
  • 50. Ahead Of Time Compilation build.xml <target name="compile" description="Compile Clojure sources."> <mkdir dir="${classes.dir}" /> <pathconvert pathsep=" " property="compile.namespaces"> <fileset dir="${src.dir}" includes="**/*.clj" /> <chainedmapper> <packagemapper from="${basedir}/${src.dir}/*.clj" to="*" /> <filtermapper> <replacestring from="_" to="-" /> </filtermapper> </chainedmapper> </pathconvert> Output directory for <java classname="clojure.lang.Compile"> generated classes <classpath> <path refid="libs.path" /> <path location="${classes.dir}" /> <path location="${src.dir}" /> </classpath> <sysproperty key="clojure.compile.path" value="${classes.dir}" /> <arg line="${compile.namespaces}" /> </java> </target> List of namespaces to compile 50 © 2009 Howard Lewis Ship
  • 51. Clojure Pitfalls 51 © 2009 Howard Lewis Ship
  • 52. IDE Support 52 © 2009 Howard Lewis Ship
  • 53. Laziness RuntimeException: Divide by zero 53 © 2009 Howard Lewis Ship
  • 54. Laziness Clojure 1.0.0- 1:1 user=> (def nums (map / (range 0 10) (reverse (range 0 10)))) #'user/nums 1:2 user=> nums java.lang.ArithmeticException: Divide by zero (0 1/8 2/7 1/2 4/5 5/4 2 7/2 1:3 user=> (.. *e getCause printStackTrace) java.lang.ArithmeticException: Divide by zero at clojure.lang.Numbers.divide(Numbers.java:138) at clojure.core$_SLASH___3350.invoke(core.clj:575) at clojure.core$map__3815$fn__3822.invoke(core.clj:1508) at clojure.lang.LazySeq.seq(LazySeq.java:41) at clojure.lang.Cons.next(Cons.java:37) at clojure.lang.RT.next(RT.java:560) at clojure.core$next__3117.invoke(core.clj:50) at clojure.core$nthnext__4405.invoke(core.clj:2531) at clojure.core$print_sequential__5354.invoke(core_print.clj:53) at clojure.core$fn__5439.invoke(core_print.clj:136) at clojure.lang.MultiFn.invoke(MultiFn.java:161) at clojure.core$pr_on__4145.invoke(core.clj:2020) at clojure.core$pr__4148.invoke(core.clj:2030) at clojure.lang.AFn.applyToHelper(AFn.java:173) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply__3243.doInvoke(core.clj:390) at clojure.lang.RestFn.invoke(RestFn.java:428) at clojure.core$prn__4159.doInvoke(core.clj:2053) at clojure.lang.RestFn.invoke(RestFn.java:413) at clojure.main$repl__5813$read_eval_print__5825.invoke(main.clj:177) at clojure.main$repl__5813.doInvoke(main.clj:193) at clojure.lang.RestFn.invoke(RestFn.java:876) at clojure.contrib.repl_ln$repl__84.doInvoke(repl_ln.clj:259) at clojure.lang.RestFn.invoke(RestFn.java:426) at clojure.contrib.repl_ln$_main__44.doInvoke(repl_ln.clj:136) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.contrib.repl_ln.main(Unknown Source) nil 1:7 user=> 54 © 2009 Howard Lewis Ship
  • 55. Lack of Type Checking 55 © 2009 Howard Lewis Ship
  • 56. Spot the Error view_manager.clj (defn to-dom-node-seq [any] "Converts the result of a render function to a seq as needed." (cond (nil? any) nil (sequential? any) any ; A map is assumed to be a DOM node, wrap it in a vector (map? any) [map] (string? any) [(struct-map dom-node :type :text :value any)] true (throw (RuntimeException. (format "A rendering function returned %s. ↵ Rendering functions should return nil, a string, a seq of DOM nodes, or a single ↵ DOM node." (pr-str any)))))) 56 © 2009 Howard Lewis Ship
  • 57. Exception ERROR in (simple-view-and-fragment) (test_is.clj:657) Uncaught exception, not in assertion. expected: nil actual: java.lang.IllegalArgumentException: Wrong number of args passed to: core$map at clojure.lang.AFn.throwArity (AFn.java:449) clojure.lang.RestFn.invoke (RestFn.java:417) com.howardlewisship.cascade.dom$fn__960.doInvoke (dom.clj:58) clojure.lang.RestFn.invoke (RestFn.java:443) clojure.lang.MultiFn.invoke (MultiFn.java:165) com.howardlewisship.cascade.dom/render_xml_with_ns (dom.clj:118) com.howardlewisship.cascade.dom/render_xml (dom.clj:125) com.howardlewisship.cascade.test_views/render (test_views.clj:27) com.howardlewisship.cascade.test_views/test_view (test_views.clj:56) com.howardlewisship.cascade.test_views/test_view (test_views.clj:52) com.howardlewisship.cascade.test_views/fn (test_views.clj:62) dom.clj (defmulti render-node-xml (fn [node & rest] (node :type))) 57 © 2009 Howard Lewis Ship
  • 58. Spot the Error view_manager.clj (defn to-dom-node-seq [any] "Converts the result of a render function to a seq as needed." (cond (nil? any) nil (sequential? any) any ; A map is assumed to be a DOM node, wrap it in a vector (map? any) [map] (string? any) [(struct-map dom-node :type :text :value any)] true (throw (RuntimeException. (format "A rendering function returned %s. ↵ Rendering functions should return nil, a string, a seq of DOM nodes, or a single ↵ DOM node." (pr-str any)))))) Returning function clojure.core/map; should return any (the parameter) 58 © 2009 Howard Lewis Ship
  • 59. Bus Factor 59 © 2009 Howard Lewis Ship
  • 60. GitHub Factor 60 © 2009 Howard Lewis Ship
  • 61. Performance 61 © 2009 Howard Lewis Ship
  • 62. Performance (defn shorts-to-bytes [#^shorts src #^bytes dst words]  (loop [src-offset (int 0)         dst-offset (int 0)]    (when (< src-offset words)      (let [sample (short (aget src src-offset))]        (aset-byte dst dst-offset (byte sample))        (aset-byte dst (inc dst-offset) (byte (bit-shift-right sample 8))))      (recur (inc src-offset) (unchecked-add 2 dst-offset)))))  public static void shortsToBytes(short[] src, byte[] dst, int len)  {   int idx = 0; 900 ms   short s;   while (len-- > 0) {     s = src[idx];     dst[idx*2] = (byte)s; 675 ms     dst[idx*2+1] = (byte)(s>>>8);     idx++;   }  } 450 ms 225 ms 0 ms Java Clojure 62 © 2009 Howard Lewis Ship
  • 63. API Docs 63 © 2009 Howard Lewis Ship
  • 64. Wrap Up 64 © 2009 Howard Lewis Ship
  • 65. What's Not Covered? • multimethods ➠ inheritance-like function dispatch • Concurrency Support ➠ atoms, agents, refs & vars http://www.clojure.org • loop & recur ➠ iterative-style coding • clojure.contrib ➠ Community library • Macros & Meta-Programming ➠ Create the language you want inside Clojure • Tuning Clojure Performance • More …. 65 © 2009 Howard Lewis Ship
  • 66. Stuart Halloway Pragmatic Bookshelf http://pragprog.com/titles/shcloj/programming-clojure 66 © 2009 Howard Lewis Ship
  • 67. http://jnb.ociweb.com/jnb/jnbMar2009.html 67 © 2009 Howard Lewis Ship
  • 68. Image Credits © 2005 Jean-Philippe Daigle http://www.flickr.com/photos/jpdaigle/59942231/ © 2007 Howard Gees http://www.flickr.com/photos/cyberslayer/952121271/ © 2006 Simon Law http://www.flickr.com/photos/sfllaw/222795669/ © 2008 II-cocoy22-II http://www.flickr.com/photos/30954876@N07/3090155264/ © 2009 Martin Biskoping http://www.flickr.com/photos/mbiskoping/3388639698/ © 2008 sea turtle http://www.flickr.com/photos/sea-turtle/3049443478/ © 2009 Tulio Bertorini http://www.flickr.com/photos/tuliobertorini/3159130251/ © 2007 Adam Balch http://www.flickr.com/photos/triplemaximus/795758146/ © 2008 jessamyn west http://www.flickr.com/photos/iamthebestartist/2636607001/ 68 © 2009 Howard Lewis Ship