SlideShare ist ein Scribd-Unternehmen logo
1 von 41
Downloaden Sie, um offline zu lesen
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 1
(not= DSL macros)
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 2
Writing DSLs is hard
●
At least for me
●
Enlive, Moustache, Parsley:
●
Several iterations
●
And counting!
●
Main sin: using macros
●
Learnt some lessons along the way
●
Applied here: github.com/cgrand/regex
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 3
So, what's a DSL?
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 4
DSL in Clojure
●
“mini-languages” in core:
●
destructuring, seq comprehensions, anonymous
fns, syntax quote, pre and post-conditions, -> and
->> etc.
●
ClojureQL, Clout, Hiccup, Matchure, Enlive,
Moustache etc.
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 5
What's a DSL?
●
Domain Specific Language
●
Scope-limited
●
not a General Purpose Language
● not always Turing-complete
●
Internal DSL:
●
Written in the host language (Clojure)
●
Mostly intended for developers
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 6
What's a DSL?
●
Succinct notation for DS things
●
Data
●
Logic
● DSL benefits
●
Usually more declarative
●
Reduce incidental complexity
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 7
What's a DSL?
●
Succinct notation for DS things
●
Data
●
Logic
● DSL benefits
●
Usually more declarative
●
Reduce incidental complexity
Succinct declarative notation
for DS data & logic
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 8
A blurry line
●
A continuum
●
from data schemas
●
to compiler-in-a-macro
● Every API is a DSL
Data
form
at
Functions
M
acros
Com
pilerin
a
m
acro
Complexity
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 9
Complexity
Enlive users complained about:
●
selectors not being first class
●
and being hard to compose
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 10
Complexity
Enlive users complained about:
●
selectors not being first class
●
and being hard to compose
I rewrote it and removed macros
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 11
Complexity
ClojureQL users complained about:
●
queries being too suprising
●
and hard to compose
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 12
Complexity
ClojureQL users complained about:
●
queries being too suprising
●
and hard to compose
Kotarak and Lau are rewriting it
and removing macros
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 13
Complexity
Do you spot a pattern?
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 14
Spoilt users!
●
Users don't want a DSL
●
Users want to use all the power of Clojure
●
Conclusion: Users want values
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 15
Spoilt users!
●
Users don't want a DSL
●
Users want to use all the power of Clojure
●
Conclusion: Users want values
Values + functional core
(+ macros as icing-on-the-cake)
= DSL success!
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 16
Limiting complexity
●
Limit scope
●
Don't reinvent lexical scoping or control flow
●
Rely on Clojure for these
●
Limit syntax
● Use closures
●
Use higher order functions
●
Ugly? Syntax is icing, add it later!
●
No macros
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 17
Start easy, simple, humble
●
Don't rush for macros!
●
Premature optimization
●
Too much rope
● Start humble:
●
Data
●
a handful of functions
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 18
Data
●
Focus on DS values rather than DS Language
●
Give DS semantics to datatypes
●
Clojure's ones
●
Your own ones
●
Except lists and symbols
– Avoid confusion
– Not pretty (need to be quoted)
– Visual escape to regular Clojure
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 19
But I really need macros!
— anonymous macro addict
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 20
You sure? Dynamicity is good...
●
Macros as premature optimization
●
Example: Enlive's commit 944312b1621
●
Make selectors first class
●
Delete 12 defmacros out of 24
●
Allowed for simpler optimizations (caching)
Net result: faster and more dynamic
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 21
Ok, Macros
Decouple binding, step by step:
●
Design your DSL (values and core fns) without
binding (but provision it) but with capturing
●
???
●
Profit!!!
Legitimate usecases Tentative workarounds
Control flow Closures, delays
Binding Decouple binding
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 22
??? explained
●
Create a “binding specs capturing specs” fn→
●
Create a “binding specs binding forms” fn→
Decouple binding and capturing
(defmacro when-match [pattern value & body]
(let [matcher (capturing pattern)
bindings (extract-bindings pattern)]
`(when-let [~bindings
(capture ~matcher value)]
~@body)))
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 23
Example: a DSL for regexes
simplified version of github.com/cgrand/regex
(e.g. no named groups)
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 24
Regex DSL
●
A DSL for regexes in Clojure
●
Compile to host regexes
●
Not that useful: regexes are already a DSL
●
External and composable though
●
Basic building blocks of regexes:
●
Literals, sequences, alternatives, char ranges,
repetitions and a wildcard
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 25
Giving Regex semantics to types
●
Literals
●
Sequences
●
Alternatives
●
Char ranges
●
Repetitions
●
Wildcard
Notations?
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 26
Giving Regex semantics to types
●
Literals
●
Sequences
●
Alternatives
●
Char ranges
●
Repetitions
●
Wildcard
"abc", d
[this then-that and-also]
#{this or-that or-also}
{a z, A Z, 0 9}
(re/repeat this min? max?)
re/any
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 27
Evaluating to Java Patterns
(defprotocol RegexNotation
(pattern [this] "Returns a corresponding pattern (as String)."))
regex is the user fn:
Then, define pattern as a protocol fn
(defn regex [spec]
(-> spec pattern Pattern/compile))
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 28
Evaluating to Java Patterns
;; literals, sequences, alternatives and char ranges
(extend-protocol RegexNotation
String
(pattern [s]
(Pattern/quote s))
Character
(pattern [c]
(pattern (str c)))
clojure.lang.APersistentVector
(pattern [v]
(str/join (map pattern v)))
clojure.lang.APersistentSet
(pattern [s]
(str "(?:" (str/join "|" (map pattern s)) ")"))
clojure.lang.APersistentMap
(pattern [m]
(str "[" (str/join (for [[from to] m]
(str from "-" to)))
"]")))
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 29
Evaluating to Java Patterns
(regex (let [d {0 9}
d2 [d d]
d4 [d2 d2]]
["date: " d4 - d2 - d2]))
;; #"Qdate: E[0-9][0-9][0-9][0-9]Q-E[0-9][0-9]Q-E[0-9][0-9]"
(let [d {0 9}
d2 [d d]
d4 [d2 d2]]
(regex ["date: " d4 - d2 - d2]))
;; or
(let [d {0 9}
d2 [d d]
date (into ["date: " d2] (interpose - [[d2 d2] d2 d2]))]
(regex date))
;; are equivalents
;; DSL fragments are first class,
;; you can use all clojure to build them!
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 30
We need new types!
(defrecord Repetition [spec min max]
RegexNotation
(pattern [r]
(str "(?:" (pattern spec) ")"
"{" (or min 0) "," (or max "") "}")))
(defn repeat
([spec] (repeat spec nil nil))
([spec min] (repeat spec min nil))
([spec min max] (Repetition. spec min max)))
;; any is the only one of its kind -> reify
(def any (reify RegexNotation
(pattern [_] ".")))
Repetition and any need their own types:
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 31
Helper fns
(defn join
([spec separator] (join spec separator nil nil))
([spec separator min] (join spec separator min nil))
([spec separator min max]
(if (zero? (or min 0))
(repeat (join spec separator 1 max) 0 1)
[spec (repeat [separator spec]
(dec min) (when max (dec max)))])))
=> (regex (join [{0 9} {0 9}] - 1 3))
#"[0-9][0-9](?:Q-E[0-9][0-9]){0,2}"
You can easily define helper fns:
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 32
Helper fns
The whole truth is:
●
regex is eval for your DSL
●
Helper fns act like macros for your DSL
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 33
Closing the loop
(extend-protocol RegexNotation
Pattern
(pattern [p] (.pattern p)))
=> (regex #{"hello" "world"})
#"(?:QhelloE|QworldE)"
=> (regex (regex #{"hello" "world"}))
#"(?:QhelloE|QworldE)"
Making regex idempotent
Why does it matter?
●
You can canonicalize your inputs
●
You can "pre-compile" or cache fragments.
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 34
Static optimization
Detecting constant fragments (macros ok...)
●
Simplifying them away
●
Recognizing your own functions:
Don't check syms, check vars!
(when-not (contains? &env sym)
(resolve sym)) ; 1.2
(resolve &env sym) ; 1.3
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 35
Static optimizations
●
Compiling constant fragments
●
“eval” them (e.g. call re/regex)
●
Expand to the value when readable or to a factory
form
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 36
That's all folks!
Questions?
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 37
STOP
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 38
Complexity
Data
form
at
Functions
M
acros
Com
pilerin
a
m
acro
Complexity
●
Complexity for the implementor
●
The joy of tree-walking
●
Complexity for the user
●
Different from regular Clojure code
●
What is first class? What's not?
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 39
DSL Design
●
Code is data
●
Or the other way round
●
Rich range of literals
– Vectors, maps, sets, keywords, numbers, regexes
● No need to quote, walk, extract/unquote
– arguments evaluation without call semantics
[:operator arg1 arg2]
(operator arg1 arg2)
– Unless you use lists
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 40
DSL Design
●
List forms are still cumbersome when doing static
analysis
●
Always use a conservative default
“When in doubt, don't” – Benjamin Franklin
●
&env relieves the pain
● (when-not (contains? &env sym)
(resolve sym))
●
test against vars, not syms
●
no more shadowing problems
somewhat opaque
First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 41
Macros
Decouple binding example, Moustache routes:
●
match-route is functional
●
I could have done without derive-simple-route
Legitimate macros Tentative workarounds
Control flow Closures, delays
Binding Decouple binding
(let [bindings (derive-bindings route-spec)
simple-route (derive-simple-route route-spec)]
`(when-let [~bindings (match-route ~url ~simple-route)]
...))

Weitere ähnliche Inhalte

Was ist angesagt?

Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency IdiomsAlex Miller
 
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume LaforgeGR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume LaforgeGR8Conf
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8confGR8Conf
 
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume LaforgeGR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume LaforgeGR8Conf
 
Qt Framework Events Signals Threads
Qt Framework Events Signals ThreadsQt Framework Events Signals Threads
Qt Framework Events Signals ThreadsNeera Mital
 
Introduction to Groovy runtime metaprogramming and AST transforms
Introduction to Groovy runtime metaprogramming and AST transformsIntroduction to Groovy runtime metaprogramming and AST transforms
Introduction to Groovy runtime metaprogramming and AST transformsMarcin Grzejszczak
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
 
Objective-C Blocks and Grand Central Dispatch
Objective-C Blocks and Grand Central DispatchObjective-C Blocks and Grand Central Dispatch
Objective-C Blocks and Grand Central DispatchMatteo Battaglio
 
Blocks & GCD
Blocks & GCDBlocks & GCD
Blocks & GCDrsebbe
 
ConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyIván López Martín
 
Actor Concurrency
Actor ConcurrencyActor Concurrency
Actor ConcurrencyAlex Miller
 
Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++corehard_by
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Introthnetos
 
Metaprogramming Techniques In Groovy And Grails
Metaprogramming Techniques In Groovy And GrailsMetaprogramming Techniques In Groovy And Grails
Metaprogramming Techniques In Groovy And GrailszenMonkey
 

Was ist angesagt? (20)

Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency Idioms
 
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume LaforgeGR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8conf
 
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume LaforgeGR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
 
Qt Framework Events Signals Threads
Qt Framework Events Signals ThreadsQt Framework Events Signals Threads
Qt Framework Events Signals Threads
 
Introduction to Groovy runtime metaprogramming and AST transforms
Introduction to Groovy runtime metaprogramming and AST transformsIntroduction to Groovy runtime metaprogramming and AST transforms
Introduction to Groovy runtime metaprogramming and AST transforms
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Basic Packet Forwarding in NS2
Basic Packet Forwarding in NS2Basic Packet Forwarding in NS2
Basic Packet Forwarding in NS2
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
 
Objective-C Blocks and Grand Central Dispatch
Objective-C Blocks and Grand Central DispatchObjective-C Blocks and Grand Central Dispatch
Objective-C Blocks and Grand Central Dispatch
 
packet destruction in NS2
packet destruction in NS2packet destruction in NS2
packet destruction in NS2
 
NS2 Classifiers
NS2 ClassifiersNS2 Classifiers
NS2 Classifiers
 
Blocks & GCD
Blocks & GCDBlocks & GCD
Blocks & GCD
 
Ast transformation
Ast transformationAst transformation
Ast transformation
 
ConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with Groovy
 
Actor Concurrency
Actor ConcurrencyActor Concurrency
Actor Concurrency
 
NS2 Shadow Object Construction
NS2 Shadow Object ConstructionNS2 Shadow Object Construction
NS2 Shadow Object Construction
 
Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Metaprogramming Techniques In Groovy And Grails
Metaprogramming Techniques In Groovy And GrailsMetaprogramming Techniques In Groovy And Grails
Metaprogramming Techniques In Groovy And Grails
 

Ähnlich wie (not= DSL macros)

44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...
44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...
44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...44CON
 
44 con slides
44 con slides44 con slides
44 con slidesgeeksec80
 
44 con slides (1)
44 con slides (1)44 con slides (1)
44 con slides (1)geeksec80
 
JavaScript From Hell - CONFidence 2.0 2009
JavaScript From Hell - CONFidence 2.0 2009JavaScript From Hell - CONFidence 2.0 2009
JavaScript From Hell - CONFidence 2.0 2009Mario Heiderich
 
Re-engineering Eclipse MDT/OCL for Xtext
Re-engineering Eclipse MDT/OCL for XtextRe-engineering Eclipse MDT/OCL for Xtext
Re-engineering Eclipse MDT/OCL for XtextEdward Willink
 
PyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with MingPyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with MingAlessandro Molina
 
Go Is Your Next Language — Sergii Shapoval
Go Is Your Next Language — Sergii ShapovalGo Is Your Next Language — Sergii Shapoval
Go Is Your Next Language — Sergii ShapovalGlobalLogic Ukraine
 
ClojureScript for the web
ClojureScript for the webClojureScript for the web
ClojureScript for the webMichiel Borkent
 
Using FXML on Clojure
Using FXML on ClojureUsing FXML on Clojure
Using FXML on ClojureEunPyoung Kim
 
DConf 2016: Keynote by Walter Bright
DConf 2016: Keynote by Walter Bright DConf 2016: Keynote by Walter Bright
DConf 2016: Keynote by Walter Bright Andrei Alexandrescu
 
Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)Eugene Yokota
 
Advanced Node.JS Meetup
Advanced Node.JS MeetupAdvanced Node.JS Meetup
Advanced Node.JS MeetupLINAGORA
 
Trace kernel code tips
Trace kernel code tipsTrace kernel code tips
Trace kernel code tipsViller Hsiao
 
Drools, jBPM OptaPlanner presentation
Drools, jBPM OptaPlanner presentationDrools, jBPM OptaPlanner presentation
Drools, jBPM OptaPlanner presentationMark Proctor
 
Robust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time ChecksRobust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time ChecksStoyan Nikolov
 
In the DOM, no one will hear you scream
In the DOM, no one will hear you screamIn the DOM, no one will hear you scream
In the DOM, no one will hear you screamMario Heiderich
 
TC39: How we work, what we are working on, and how you can get involved (dotJ...
TC39: How we work, what we are working on, and how you can get involved (dotJ...TC39: How we work, what we are working on, and how you can get involved (dotJ...
TC39: How we work, what we are working on, and how you can get involved (dotJ...Igalia
 

Ähnlich wie (not= DSL macros) (20)

44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...
44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...
44CON 2013 - Browser bug hunting - Memoirs of a last man standing - Atte Kett...
 
44 con slides
44 con slides44 con slides
44 con slides
 
44 con slides (1)
44 con slides (1)44 con slides (1)
44 con slides (1)
 
JavaScript From Hell - CONFidence 2.0 2009
JavaScript From Hell - CONFidence 2.0 2009JavaScript From Hell - CONFidence 2.0 2009
JavaScript From Hell - CONFidence 2.0 2009
 
Dconf2015 d2 t3
Dconf2015 d2 t3Dconf2015 d2 t3
Dconf2015 d2 t3
 
Re-engineering Eclipse MDT/OCL for Xtext
Re-engineering Eclipse MDT/OCL for XtextRe-engineering Eclipse MDT/OCL for Xtext
Re-engineering Eclipse MDT/OCL for Xtext
 
PyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with MingPyConUK2013 - Validated documents on MongoDB with Ming
PyConUK2013 - Validated documents on MongoDB with Ming
 
Go Is Your Next Language — Sergii Shapoval
Go Is Your Next Language — Sergii ShapovalGo Is Your Next Language — Sergii Shapoval
Go Is Your Next Language — Sergii Shapoval
 
ClojureScript for the web
ClojureScript for the webClojureScript for the web
ClojureScript for the web
 
Using FXML on Clojure
Using FXML on ClojureUsing FXML on Clojure
Using FXML on Clojure
 
DConf 2016: Keynote by Walter Bright
DConf 2016: Keynote by Walter Bright DConf 2016: Keynote by Walter Bright
DConf 2016: Keynote by Walter Bright
 
Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)
 
Advanced Node.JS Meetup
Advanced Node.JS MeetupAdvanced Node.JS Meetup
Advanced Node.JS Meetup
 
Trace kernel code tips
Trace kernel code tipsTrace kernel code tips
Trace kernel code tips
 
Js on-microcontrollers
Js on-microcontrollersJs on-microcontrollers
Js on-microcontrollers
 
Drools, jBPM OptaPlanner presentation
Drools, jBPM OptaPlanner presentationDrools, jBPM OptaPlanner presentation
Drools, jBPM OptaPlanner presentation
 
Robust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time ChecksRobust C++ Task Systems Through Compile-time Checks
Robust C++ Task Systems Through Compile-time Checks
 
Clojure And Swing
Clojure And SwingClojure And Swing
Clojure And Swing
 
In the DOM, no one will hear you scream
In the DOM, no one will hear you screamIn the DOM, no one will hear you scream
In the DOM, no one will hear you scream
 
TC39: How we work, what we are working on, and how you can get involved (dotJ...
TC39: How we work, what we are working on, and how you can get involved (dotJ...TC39: How we work, what we are working on, and how you can get involved (dotJ...
TC39: How we work, what we are working on, and how you can get involved (dotJ...
 

(not= DSL macros)

  • 1. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 1 (not= DSL macros)
  • 2. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 2 Writing DSLs is hard ● At least for me ● Enlive, Moustache, Parsley: ● Several iterations ● And counting! ● Main sin: using macros ● Learnt some lessons along the way ● Applied here: github.com/cgrand/regex
  • 3. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 3 So, what's a DSL?
  • 4. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 4 DSL in Clojure ● “mini-languages” in core: ● destructuring, seq comprehensions, anonymous fns, syntax quote, pre and post-conditions, -> and ->> etc. ● ClojureQL, Clout, Hiccup, Matchure, Enlive, Moustache etc.
  • 5. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 5 What's a DSL? ● Domain Specific Language ● Scope-limited ● not a General Purpose Language ● not always Turing-complete ● Internal DSL: ● Written in the host language (Clojure) ● Mostly intended for developers
  • 6. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 6 What's a DSL? ● Succinct notation for DS things ● Data ● Logic ● DSL benefits ● Usually more declarative ● Reduce incidental complexity
  • 7. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 7 What's a DSL? ● Succinct notation for DS things ● Data ● Logic ● DSL benefits ● Usually more declarative ● Reduce incidental complexity Succinct declarative notation for DS data & logic
  • 8. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 8 A blurry line ● A continuum ● from data schemas ● to compiler-in-a-macro ● Every API is a DSL Data form at Functions M acros Com pilerin a m acro Complexity
  • 9. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 9 Complexity Enlive users complained about: ● selectors not being first class ● and being hard to compose
  • 10. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 10 Complexity Enlive users complained about: ● selectors not being first class ● and being hard to compose I rewrote it and removed macros
  • 11. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 11 Complexity ClojureQL users complained about: ● queries being too suprising ● and hard to compose
  • 12. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 12 Complexity ClojureQL users complained about: ● queries being too suprising ● and hard to compose Kotarak and Lau are rewriting it and removing macros
  • 13. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 13 Complexity Do you spot a pattern?
  • 14. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 14 Spoilt users! ● Users don't want a DSL ● Users want to use all the power of Clojure ● Conclusion: Users want values
  • 15. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 15 Spoilt users! ● Users don't want a DSL ● Users want to use all the power of Clojure ● Conclusion: Users want values Values + functional core (+ macros as icing-on-the-cake) = DSL success!
  • 16. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 16 Limiting complexity ● Limit scope ● Don't reinvent lexical scoping or control flow ● Rely on Clojure for these ● Limit syntax ● Use closures ● Use higher order functions ● Ugly? Syntax is icing, add it later! ● No macros
  • 17. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 17 Start easy, simple, humble ● Don't rush for macros! ● Premature optimization ● Too much rope ● Start humble: ● Data ● a handful of functions
  • 18. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 18 Data ● Focus on DS values rather than DS Language ● Give DS semantics to datatypes ● Clojure's ones ● Your own ones ● Except lists and symbols – Avoid confusion – Not pretty (need to be quoted) – Visual escape to regular Clojure
  • 19. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 19 But I really need macros! — anonymous macro addict
  • 20. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 20 You sure? Dynamicity is good... ● Macros as premature optimization ● Example: Enlive's commit 944312b1621 ● Make selectors first class ● Delete 12 defmacros out of 24 ● Allowed for simpler optimizations (caching) Net result: faster and more dynamic
  • 21. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 21 Ok, Macros Decouple binding, step by step: ● Design your DSL (values and core fns) without binding (but provision it) but with capturing ● ??? ● Profit!!! Legitimate usecases Tentative workarounds Control flow Closures, delays Binding Decouple binding
  • 22. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 22 ??? explained ● Create a “binding specs capturing specs” fn→ ● Create a “binding specs binding forms” fn→ Decouple binding and capturing (defmacro when-match [pattern value & body] (let [matcher (capturing pattern) bindings (extract-bindings pattern)] `(when-let [~bindings (capture ~matcher value)] ~@body)))
  • 23. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 23 Example: a DSL for regexes simplified version of github.com/cgrand/regex (e.g. no named groups)
  • 24. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 24 Regex DSL ● A DSL for regexes in Clojure ● Compile to host regexes ● Not that useful: regexes are already a DSL ● External and composable though ● Basic building blocks of regexes: ● Literals, sequences, alternatives, char ranges, repetitions and a wildcard
  • 25. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 25 Giving Regex semantics to types ● Literals ● Sequences ● Alternatives ● Char ranges ● Repetitions ● Wildcard Notations?
  • 26. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 26 Giving Regex semantics to types ● Literals ● Sequences ● Alternatives ● Char ranges ● Repetitions ● Wildcard "abc", d [this then-that and-also] #{this or-that or-also} {a z, A Z, 0 9} (re/repeat this min? max?) re/any
  • 27. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 27 Evaluating to Java Patterns (defprotocol RegexNotation (pattern [this] "Returns a corresponding pattern (as String).")) regex is the user fn: Then, define pattern as a protocol fn (defn regex [spec] (-> spec pattern Pattern/compile))
  • 28. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 28 Evaluating to Java Patterns ;; literals, sequences, alternatives and char ranges (extend-protocol RegexNotation String (pattern [s] (Pattern/quote s)) Character (pattern [c] (pattern (str c))) clojure.lang.APersistentVector (pattern [v] (str/join (map pattern v))) clojure.lang.APersistentSet (pattern [s] (str "(?:" (str/join "|" (map pattern s)) ")")) clojure.lang.APersistentMap (pattern [m] (str "[" (str/join (for [[from to] m] (str from "-" to))) "]")))
  • 29. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 29 Evaluating to Java Patterns (regex (let [d {0 9} d2 [d d] d4 [d2 d2]] ["date: " d4 - d2 - d2])) ;; #"Qdate: E[0-9][0-9][0-9][0-9]Q-E[0-9][0-9]Q-E[0-9][0-9]" (let [d {0 9} d2 [d d] d4 [d2 d2]] (regex ["date: " d4 - d2 - d2])) ;; or (let [d {0 9} d2 [d d] date (into ["date: " d2] (interpose - [[d2 d2] d2 d2]))] (regex date)) ;; are equivalents ;; DSL fragments are first class, ;; you can use all clojure to build them!
  • 30. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 30 We need new types! (defrecord Repetition [spec min max] RegexNotation (pattern [r] (str "(?:" (pattern spec) ")" "{" (or min 0) "," (or max "") "}"))) (defn repeat ([spec] (repeat spec nil nil)) ([spec min] (repeat spec min nil)) ([spec min max] (Repetition. spec min max))) ;; any is the only one of its kind -> reify (def any (reify RegexNotation (pattern [_] "."))) Repetition and any need their own types:
  • 31. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 31 Helper fns (defn join ([spec separator] (join spec separator nil nil)) ([spec separator min] (join spec separator min nil)) ([spec separator min max] (if (zero? (or min 0)) (repeat (join spec separator 1 max) 0 1) [spec (repeat [separator spec] (dec min) (when max (dec max)))]))) => (regex (join [{0 9} {0 9}] - 1 3)) #"[0-9][0-9](?:Q-E[0-9][0-9]){0,2}" You can easily define helper fns:
  • 32. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 32 Helper fns The whole truth is: ● regex is eval for your DSL ● Helper fns act like macros for your DSL
  • 33. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 33 Closing the loop (extend-protocol RegexNotation Pattern (pattern [p] (.pattern p))) => (regex #{"hello" "world"}) #"(?:QhelloE|QworldE)" => (regex (regex #{"hello" "world"})) #"(?:QhelloE|QworldE)" Making regex idempotent Why does it matter? ● You can canonicalize your inputs ● You can "pre-compile" or cache fragments.
  • 34. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 34 Static optimization Detecting constant fragments (macros ok...) ● Simplifying them away ● Recognizing your own functions: Don't check syms, check vars! (when-not (contains? &env sym) (resolve sym)) ; 1.2 (resolve &env sym) ; 1.3
  • 35. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 35 Static optimizations ● Compiling constant fragments ● “eval” them (e.g. call re/regex) ● Expand to the value when readable or to a factory form
  • 36. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 36 That's all folks! Questions?
  • 37. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 37 STOP
  • 38. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 38 Complexity Data form at Functions M acros Com pilerin a m acro Complexity ● Complexity for the implementor ● The joy of tree-walking ● Complexity for the user ● Different from regular Clojure code ● What is first class? What's not?
  • 39. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 39 DSL Design ● Code is data ● Or the other way round ● Rich range of literals – Vectors, maps, sets, keywords, numbers, regexes ● No need to quote, walk, extract/unquote – arguments evaluation without call semantics [:operator arg1 arg2] (operator arg1 arg2) – Unless you use lists
  • 40. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 40 DSL Design ● List forms are still cumbersome when doing static analysis ● Always use a conservative default “When in doubt, don't” – Benjamin Franklin ● &env relieves the pain ● (when-not (contains? &env sym) (resolve sym)) ● test against vars, not syms ● no more shadowing problems somewhat opaque
  • 41. First Clojure Conj, Oct 22 2010 (not= DSL macros) / Christophe Grand 41 Macros Decouple binding example, Moustache routes: ● match-route is functional ● I could have done without derive-simple-route Legitimate macros Tentative workarounds Control flow Closures, delays Binding Decouple binding (let [bindings (derive-bindings route-spec) simple-route (derive-simple-route route-spec)] `(when-let [~bindings (match-route ~url ~simple-route)] ...))