SlideShare une entreprise Scribd logo
1  sur  30
A little exercise with Macro

          Zehua Liu
Prerequisites
• Basic macro
  (defmacro mywhen [cond-exp & clauses]
    `(if ~cond-exp
       (do
         ~@clauses)))
• Java interop
  (String. "a string")
  (.substring "a string" 0 5)
Motivation
• A script to test a server with a request
  /response protocol
• To send a request to the server, reuse Java
  classes that represent requests in server code
Java Request Classes
Java Request Classes
Sending Login Request
Sending SendMessage Request
Sending Requests
•   Many other types of requests
•   Lots of duplicate codes
•   Refactor them!
•   function?
Refactor using function

(defn send-request [req-pkt sid]
  (let [[new-sid resp-pkts] (send-req req-pkt sid)]
    (if-let [err-msg (check-resp-error resp-pkts)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            (.getName req-pkt) sid req-pkt err-msg))
        [nil nil])
      [new-sid resp-pkts])))
Refactor using function
Refactor using function
• Not too bad
• Can we do better / differently?
• macro?
Login Request Again
Make it work for Login Request
Make it work for Login Request
(defmacro send-request [request username password sid]
  `(let [req-pkt# (doto (requests.LoginRequest.)
                    (.setUsername ~username)
                    (.setPassword ~password))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#])))

(defn login [:Login username password sid]
  (send-request username password sid))
Make it work for Login Request
Make it work for Login Request
(defmacro send-request [request username password sid]
`(let [req-pkt# (doto (new ~(symbol
                                (str "requests."
                                     (name request)
                                     "Request")))
                    (.setUsername ~username)
                    (.setPassword ~password))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#])))

(defn login [username password sid]
  (send-request :Login username password sid))
Make it work for Login Request
(.setUsername ~username) <==>
  (. setUsername ~username)

(.setUsername ~username) <==>
(. (symbol (str "set" (name :Username))) ~username)

(.setUsername ~username)
(.setPassword ~password) <==>
~@(map (fn [[pn pv]]
           `(. ~(symbol (str "set" (name pn))) ~pv))
   {:Username username :Password password})
Make it work for Login Request
(defmacro send-request [request param-map sid]
  `(let [req-pkt# (doto (new ~(symbol
                                (str "requests." (name request)
                                      "Request")))
                    ~@(map (fn [[pn pv]]
                             `(. ~(symbol (str "set" (name pn))) ~pv))
                          param-map))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#])))

(defn login [username password sid]
  (send-request :Login
                {:Username username :Password password} sid))
Refactor using macro

(defn login [username password sid]
  (send-request :Login
                {:Username username
                 :Password password}
                sid))

(defn send-message [message dest-username type sid]
  (send-request :SendMessage
                {:Message message
                 :DestUsername dest-username
                 :Type type}
                sid))
Refactor using macro
•   It works! Hooray!
•   Let’s use it for more fancy stuff.
•   Optional request fields?
•   On server side, SendMessage type default to
    1, if not specified
Optional field

(defn send-message [message dest-username type sid]
  (send-request :SendMessage
                {:Message message
                 :DestUsername dest-username
                 :Type type}
                sid))

(defn send-message [message dest-username sid]
  (send-request :SendMessage
                {:Message message
                 :DestUsername dest-username}
                sid))
Optional field

(defn send-message
  ([message dest-username sid]
    (send-message message dest-username nil sid))
  ([message dest-username type sid]
    (let [param-map-base {:Message message
                          :DestUsername dest-username}
          param-map (if type
                      (assoc param-map-base :Type type)
                      param-map-base)]
    (send-request :SendMessage param-map sid))))
Optional field, FAILED

(defn send-message
  ([message dest-username sid]
    (send-message message dest-username nil sid))
  ([message dest-username type sid]
    (let [param-map-base {:Message message
                          :DestUsername dest-username}
          param-map (if type
                      (assoc param-map-base :Type type)
                      param-map-base)]
    (send-request :SendMessage param-map sid))))

CompilerException java.lang.IllegalArgumentException: Don't
know how to create ISeq from: clojure.lang.Symbol, compiling:
(NO_SOURCE_PATH:10)
Optional field, FAILED
Optional field, FAILED
• macro is evaluated at compile time, not at run
  time
• macro evaluator only knows about symbols
  – {:Username username :Password
    password} is a map (keywords to symbols)
  – But param-map is a symbol
  – At compile time, macro evaluator does not know
    the run time value that the symbol param-map
    represents
• How do we fix it?
Optional field, Fixing it
• How do we fix it?
• One thought:
  – Tell the macro the complete list of fields, and have
    it generate codes like below for every field:
(if-let [v (:Type param-map)]
  (. setType v))
• And then param-map can be a symbol whose
  value macro evalutor does not need to know,
  its value is only needed at run time.
Optional field, Fixing it
(defmacro send-request [request param-list param-map sid]
  (let [param-map# param-map
        r (gensym)]
  `(let [req-pkt# (let [~r (new ~(symbol
                                 (str "requests." (name request)
                                      "Request")))]
                    ~@(map (fn [pn]
                             `(if-let [pv# (~pn ~param-map#)]
                               (. ~r ~(symbol (str "set" (name pn))) pv#)))
                          param-list))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#]))))
Optional field, Fixing it
(defn login [username password sid]
  (send-request :Login [:Username :Password]
                {:Username username :Password password}
                sid))

(defn send-message
  ([message dest-username sid]
    (send-message message dest-username nil sid))
  ([message dest-username type sid]
    (let [param-map-base {:Message message
                           :DestUsername dest-username}
          param-map (if type
                       (assoc param-map-base :Type type)
                       param-map-base)]
    (send-request :SendMessage
                   [:Message :DestUsername :Type]
                   param-map sid))))
Optional field, Fixing it
(macroexpand '(send-request :SendMessage
                            [:Message :DestUsername :Type] param-map nil))

(let*
  [req-pkt__625__auto__
   (clojure.core/let [G__671 (new requests.SendMessageRequest)]
      (clojure.core/if-let [pv__624__auto__ (:Message param-map)]
        (. G__671 setMessage pv__624__auto__))
      (clojure.core/if-let [pv__624__auto__ (:DestUsername param-map)]
        (. G__671 setDestUsername pv__624__auto__))
      (clojure.core/if-let [pv__624__auto__ (:Type param-map)]
        (. G__671 setType pv__624__auto__)))
   vec__672 (scratch.core/send-req req-pkt__625__auto__ nil)
   new-sid__626__auto__ (clojure.core/nth vec__672 0 nil)
   resp-pkts__627__auto__ (clojure.core/nth vec__672 1 nil)]
  (clojure.core/if-let [err-msg__628__auto__
                (scratch.core/check-resp-error resp-pkts__627__auto__)]
    (do
       (clojure.core/println
         (clojure.core/format
           "ERROR: %s failed, sid='%s',req='%s',err='%s'"
           "SendMessage" nil req-pkt__625__auto__ err-msg__628__auto__))
       [nil nil])
    [new-sid__626__auto__ resp-pkts__627__auto__]))
Lessons Learned
• macro is evaluated at compile time, not at run time
• macro evaluator treats code as data
   – {:Username username :Password password}
     is a map of keywords to symbols, not keywrods to strings
     (or whatever type username/password might be)
   – But param-map is a symbol
• At compile time, macro evaluator treats ref/var as
  symbol, knowing nothing about their run time values

Contenu connexe

Tendances

Desarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesDesarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesLuis Curo Salvatierra
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Michael Schwern
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)Night Sailer
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeAijaz Ansari
 
Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기JangHyuk You
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma IntroduçãoÍgor Bonadio
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APISix Apart KK
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門Tsuyoshi Yamamoto
 
Raleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationRaleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationDaniel Yuschick
 
Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)ÇözümPARK
 
F# in the real world (NDC)
F# in the real world (NDC)F# in the real world (NDC)
F# in the real world (NDC)Yan Cui
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsPierre MARTIN
 
ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'Ibuildings
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickHermann Hueck
 
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Cliff Seal
 

Tendances (20)

Desarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesDesarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móviles
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
 
Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma Introdução
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new API
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Python 1
Python 1Python 1
Python 1
 
My First Ruby
My First RubyMy First Ruby
My First Ruby
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
 
issue35 zh-CN
issue35 zh-CNissue35 zh-CN
issue35 zh-CN
 
Raleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationRaleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass Presentation
 
Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)
 
F# in the real world (NDC)
F# in the real world (NDC)F# in the real world (NDC)
F# in the real world (NDC)
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'
 
Ruby 1.9
Ruby 1.9Ruby 1.9
Ruby 1.9
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with Slick
 
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
 

En vedette

Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMsunng87
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Leonardo Borges
 
不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsして不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsしてmitsutaka mimura
 
Macros in Clojure
Macros in ClojureMacros in Clojure
Macros in Clojuresohta
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScriptsohta
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Leonardo Borges
 
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...AboutYouGmbH
 
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なものClojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なものsohta
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)Jacek Laskowski
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojureAbbas Raza
 
プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例sohta
 
Clojure from ground up
Clojure from ground upClojure from ground up
Clojure from ground upDi Xu
 

En vedette (19)

Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
 
A Dive Into Clojure
A Dive Into ClojureA Dive Into Clojure
A Dive Into Clojure
 
Writing Macros
Writing MacrosWriting Macros
Writing Macros
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
 
不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsして不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsして
 
Patterns
PatternsPatterns
Patterns
 
Macros in Clojure
Macros in ClojureMacros in Clojure
Macros in Clojure
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScript
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012
 
Clojure的魅力
Clojure的魅力Clojure的魅力
Clojure的魅力
 
Clojure概览
Clojure概览Clojure概览
Clojure概览
 
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
 
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なものClojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)
 
Clojure: a LISP for the JVM
Clojure: a LISP for the JVMClojure: a LISP for the JVM
Clojure: a LISP for the JVM
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
 
DSL in Clojure
DSL in ClojureDSL in Clojure
DSL in Clojure
 
プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例
 
Clojure from ground up
Clojure from ground upClojure from ground up
Clojure from ground up
 

Similaire à A little exercise with clojure macro

R is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdfR is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdfannikasarees
 
Deep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceAmazon Web Services
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1Ke Wei Louis
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptIngvar Stepanyan
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수용 최
 
R (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support SystemR (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support SystemMaithreya Chakravarthula
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyBrian Aker
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyBrian Aker
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helperslicejack
 
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...Amazon Web Services
 
Designing a database like an archaeologist
Designing a database like an archaeologistDesigning a database like an archaeologist
Designing a database like an archaeologistyoavrubin
 

Similaire à A little exercise with clojure macro (20)

R is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdfR is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdf
 
Deep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line Interface
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1
 
A Shiny Example-- R
A Shiny Example-- RA Shiny Example-- R
A Shiny Example-- R
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Fabric Python Lib
Fabric Python LibFabric Python Lib
Fabric Python Lib
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수
 
DataMapper
DataMapperDataMapper
DataMapper
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
 
R (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support SystemR (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support System
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copy
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copy
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helper
 
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
 
Designing a database like an archaeologist
Designing a database like an archaeologistDesigning a database like an archaeologist
Designing a database like an archaeologist
 
Php functions
Php functionsPhp functions
Php functions
 

Dernier

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 

Dernier (20)

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 

A little exercise with clojure macro

  • 1. A little exercise with Macro Zehua Liu
  • 2. Prerequisites • Basic macro (defmacro mywhen [cond-exp & clauses] `(if ~cond-exp (do ~@clauses))) • Java interop (String. "a string") (.substring "a string" 0 5)
  • 3. Motivation • A script to test a server with a request /response protocol • To send a request to the server, reuse Java classes that represent requests in server code
  • 8. Sending Requests • Many other types of requests • Lots of duplicate codes • Refactor them! • function?
  • 9. Refactor using function (defn send-request [req-pkt sid] (let [[new-sid resp-pkts] (send-req req-pkt sid)] (if-let [err-msg (check-resp-error resp-pkts)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" (.getName req-pkt) sid req-pkt err-msg)) [nil nil]) [new-sid resp-pkts])))
  • 11. Refactor using function • Not too bad • Can we do better / differently? • macro?
  • 13. Make it work for Login Request
  • 14. Make it work for Login Request (defmacro send-request [request username password sid] `(let [req-pkt# (doto (requests.LoginRequest.) (.setUsername ~username) (.setPassword ~password)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))) (defn login [:Login username password sid] (send-request username password sid))
  • 15. Make it work for Login Request
  • 16. Make it work for Login Request (defmacro send-request [request username password sid] `(let [req-pkt# (doto (new ~(symbol (str "requests." (name request) "Request"))) (.setUsername ~username) (.setPassword ~password)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))) (defn login [username password sid] (send-request :Login username password sid))
  • 17. Make it work for Login Request (.setUsername ~username) <==> (. setUsername ~username) (.setUsername ~username) <==> (. (symbol (str "set" (name :Username))) ~username) (.setUsername ~username) (.setPassword ~password) <==> ~@(map (fn [[pn pv]] `(. ~(symbol (str "set" (name pn))) ~pv)) {:Username username :Password password})
  • 18. Make it work for Login Request (defmacro send-request [request param-map sid] `(let [req-pkt# (doto (new ~(symbol (str "requests." (name request) "Request"))) ~@(map (fn [[pn pv]] `(. ~(symbol (str "set" (name pn))) ~pv)) param-map)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))) (defn login [username password sid] (send-request :Login {:Username username :Password password} sid))
  • 19. Refactor using macro (defn login [username password sid] (send-request :Login {:Username username :Password password} sid)) (defn send-message [message dest-username type sid] (send-request :SendMessage {:Message message :DestUsername dest-username :Type type} sid))
  • 20. Refactor using macro • It works! Hooray! • Let’s use it for more fancy stuff. • Optional request fields? • On server side, SendMessage type default to 1, if not specified
  • 21. Optional field (defn send-message [message dest-username type sid] (send-request :SendMessage {:Message message :DestUsername dest-username :Type type} sid)) (defn send-message [message dest-username sid] (send-request :SendMessage {:Message message :DestUsername dest-username} sid))
  • 22. Optional field (defn send-message ([message dest-username sid] (send-message message dest-username nil sid)) ([message dest-username type sid] (let [param-map-base {:Message message :DestUsername dest-username} param-map (if type (assoc param-map-base :Type type) param-map-base)] (send-request :SendMessage param-map sid))))
  • 23. Optional field, FAILED (defn send-message ([message dest-username sid] (send-message message dest-username nil sid)) ([message dest-username type sid] (let [param-map-base {:Message message :DestUsername dest-username} param-map (if type (assoc param-map-base :Type type) param-map-base)] (send-request :SendMessage param-map sid)))) CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling: (NO_SOURCE_PATH:10)
  • 25. Optional field, FAILED • macro is evaluated at compile time, not at run time • macro evaluator only knows about symbols – {:Username username :Password password} is a map (keywords to symbols) – But param-map is a symbol – At compile time, macro evaluator does not know the run time value that the symbol param-map represents • How do we fix it?
  • 26. Optional field, Fixing it • How do we fix it? • One thought: – Tell the macro the complete list of fields, and have it generate codes like below for every field: (if-let [v (:Type param-map)] (. setType v)) • And then param-map can be a symbol whose value macro evalutor does not need to know, its value is only needed at run time.
  • 27. Optional field, Fixing it (defmacro send-request [request param-list param-map sid] (let [param-map# param-map r (gensym)] `(let [req-pkt# (let [~r (new ~(symbol (str "requests." (name request) "Request")))] ~@(map (fn [pn] `(if-let [pv# (~pn ~param-map#)] (. ~r ~(symbol (str "set" (name pn))) pv#))) param-list)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))))
  • 28. Optional field, Fixing it (defn login [username password sid] (send-request :Login [:Username :Password] {:Username username :Password password} sid)) (defn send-message ([message dest-username sid] (send-message message dest-username nil sid)) ([message dest-username type sid] (let [param-map-base {:Message message :DestUsername dest-username} param-map (if type (assoc param-map-base :Type type) param-map-base)] (send-request :SendMessage [:Message :DestUsername :Type] param-map sid))))
  • 29. Optional field, Fixing it (macroexpand '(send-request :SendMessage [:Message :DestUsername :Type] param-map nil)) (let* [req-pkt__625__auto__ (clojure.core/let [G__671 (new requests.SendMessageRequest)] (clojure.core/if-let [pv__624__auto__ (:Message param-map)] (. G__671 setMessage pv__624__auto__)) (clojure.core/if-let [pv__624__auto__ (:DestUsername param-map)] (. G__671 setDestUsername pv__624__auto__)) (clojure.core/if-let [pv__624__auto__ (:Type param-map)] (. G__671 setType pv__624__auto__))) vec__672 (scratch.core/send-req req-pkt__625__auto__ nil) new-sid__626__auto__ (clojure.core/nth vec__672 0 nil) resp-pkts__627__auto__ (clojure.core/nth vec__672 1 nil)] (clojure.core/if-let [err-msg__628__auto__ (scratch.core/check-resp-error resp-pkts__627__auto__)] (do (clojure.core/println (clojure.core/format "ERROR: %s failed, sid='%s',req='%s',err='%s'" "SendMessage" nil req-pkt__625__auto__ err-msg__628__auto__)) [nil nil]) [new-sid__626__auto__ resp-pkts__627__auto__]))
  • 30. Lessons Learned • macro is evaluated at compile time, not at run time • macro evaluator treats code as data – {:Username username :Password password} is a map of keywords to symbols, not keywrods to strings (or whatever type username/password might be) – But param-map is a symbol • At compile time, macro evaluator treats ref/var as symbol, knowing nothing about their run time values