internal dsls
DESCRIPTION
My lecture about internal DSL implementation techniques.TRANSCRIPT
internal DSLsZef Hemel
Tuesday, May 18, 2010
Internal DSLs are particular ways of using a host language to give the host language the feel of a particular language.
Martin Fowler
Tuesday, May 18, 2010
Internal DSLs are particular ways of using a host language to give the host language the feel of a particular language.
Martin Fowler
ab
Tuesday, May 18, 2010
fluent interfaces
flexible syntax
reflection
macros
method missing
Tuesday, May 18, 2010
Tuesday, May 18, 2010
fluent interfaces
Tuesday, May 18, 2010
Order o = new Order();Product p1 = new Product(1,Product.find(“Billy”));o.addProduct(p1);Product p2 = new Product(2,Product.find(”Janso"));o.addProduct(p2);Product p3 = new Product(4,Product.find(“Traby"));o.addProduct(p3);o.setPriorityRush(true);customer.addOrder(o);
http://www.st.ewi.tudelft.nl/~bouwers/main/slides/2008jspring.pdf
Tuesday, May 18, 2010
customer.newOrder() .with(1, "Billy") .with(2, "Janso") .with(4, "Traby") .priorityRush() .done();
Tuesday, May 18, 2010
public class Customer { ... public OrderBuilder newOrder() { return new OrderBuilder(this); }}
Tuesday, May 18, 2010
public class OrderBuilder { // ...
public OrderBuilder(Customer customer) { this.customer = customer; this.order = new Order(); }
public OrderBuilder with(int id, String name) { order.addProduct(new Product(id, name)); return this; }
public OrderBuilder priorityRush() { order.setPriorityRush(true); return this; }
public void done() { customer.addOrder(this.order); }}
Tuesday, May 18, 2010
public class OrderBuilder { // ...
public OrderBuilder(Customer customer) { this.customer = customer; this.order = new Order(); }
public OrderBuilder with(int id, String name) { order.addProduct(new Product(id, name)); return this; }
public OrderBuilder priorityRush() { order.setPriorityRush(true); return this; }
public void done() { customer.addOrder(this.order); }}
Tuesday, May 18, 2010
flexible syntax
Tuesday, May 18, 2010
header("Add entry")form { table { row { col { text("Your name:") } col { newEntry.name = input(newEntry.name) } } row { col { text("Your message:") } col { newEntry.text = inputText(newEntry.text) } } } button("Post") { newEntry.save() goto(Home()) }}
Tuesday, May 18, 2010
in Scala
Tuesday, May 18, 2010
case class Home() extends Page { def ui { header("Welcome to my guestbook!") section { header("All entries") list { for (e <- cache("entries", Entry.all)) { listitem { form { text(e.name) text(": ") text(e.text) button("Delete") { e.delete() goto(Home()) } } } } } } }}
Tuesday, May 18, 2010
case class Home() extends Page { def ui { header("Welcome to my guestbook!") section { entries } }
def entries { header("All entries") list { for (e <- cache("entries", Entry.all)) { listitem { form { text(e.name) text(": ") text(e.text) button("Delete") { e.delete() goto(Home()) } } } } } }}
Tuesday, May 18, 2010
object DefaultStyle extends Style { block("headerblock") >> header { fontsize = 30 pt; width = 100 percent; bgcolor = "#eeeeee"; } section >> header { color = "#0c0ccc"; } body { fontfamily = "Helvetica, Arial, Verdana, sans-serif" }}
Tuesday, May 18, 2010
object DefaultStyle extends Style { block("headerblock").>>(header { fontsize = 30 pt; width = 100 percent; bgcolor = "#eeeeee"; }) section.>>(header { color = "#0c0ccc"; }) body { fontfamily = "Helvetica, Arial, Verdana, sans-serif" }}
Tuesday, May 18, 2010
object DefaultStyle extends Style { block("headerblock").>>(header(() => { fontsize = 30 pt; width = 100 percent; bgcolor = "#eeeeee"; })) section.>>(header(() => { color = "#0c0ccc"; })) body(() => { fontfamily = "Helvetica, Arial, Verdana, sans-serif" })}
Tuesday, May 18, 2010
a >> b == a.>>(b)
Tuesday, May 18, 2010
section { header("All entries") ...}
Tuesday, May 18, 2010
section(() => { header("All entries") ...})
Tuesday, May 18, 2010
section(() => { header("All entries") ...})
def section(content : => Unit) { write("<div class='section'>") content write("</div>")}
Tuesday, May 18, 2010
ruby
Tuesday, May 18, 2010
create_table :posts do |t| t.string :name t.string :title t.text :contentend
Tuesday, May 18, 2010
create_table(:posts,do |t| t.string(:name) t.string(:title) t.text (:content)end)
Tuesday, May 18, 2010
class Post < ActiveRecord::Base validates_presence_of :name, :title validates_length_of :title, :minimum => 5end
Tuesday, May 18, 2010
class Post < ActiveRecord::Base validates_presence_of(:name, :title) validates_length_of(:title, :minimum => 5)end
Tuesday, May 18, 2010
method missing
Tuesday, May 18, 2010
scala
Tuesday, May 18, 2010
width = 100 percent;
Tuesday, May 18, 2010
def width_=(w: UnitInt) { ...}
width = 100 percent;
Tuesday, May 18, 2010
width_=(100 percent);
Tuesday, May 18, 2010
width_=(100.percent);
Tuesday, May 18, 2010
width_=(100.percent());
Tuesday, May 18, 2010
implicit def int2UnitInt(i: Int) =new UnitIntWrapper(i)
Tuesday, May 18, 2010
width_=(100.percent());
Tuesday, May 18, 2010
width_=(int2UnitInt(100).percent());
Tuesday, May 18, 2010
class UnitIntWrapper(i: Int) { ...
def percent = new PercentUnitInt(i)
class PercentUnitInt(i: Int) extends UnitInt { override def toString = i + "%" }}
Tuesday, May 18, 2010
ruby
Tuesday, May 18, 2010
Person.find_by_name('Zef')
Tuesday, May 18, 2010
class Person def self.find(key, value) puts "You want results from #{key} with a value of #{value}" endend
Person.find('name', 'Zef')
Tuesday, May 18, 2010
class Person def self.find(key, value) puts "You want results from #{key} with a value of #{value}" end
def self.method_missing(id, *args) if id.id2name =~ /find_by_(.+)/ return self.find(Regexp.last_match(1), args[0]) else raise NoMethodError end endend
Person.find_by_name('Zef')
Tuesday, May 18, 2010
reflection
Tuesday, May 18, 2010
public class Person { @Persistent public String name; @Persistent public int age;}
Tuesday, May 18, 2010
void persist(Object obj) { Class cls = obj.getClass(); Field[] fields = cls.getFields(); for(Field f : fields) { Persistent anno = f.getAnnotation(Persistent.class); if(anno != null) { System.out.println(f.getName()); } }}
Tuesday, May 18, 2010
macros
Tuesday, May 18, 2010
int one() { printf("One!"); return 1;}
int two() { printf("Two!"); return 2;}
...
int c = choice(n == 1, one(), two());
Tuesday, May 18, 2010
int choice(BOOL c, int ifTrue, int ifFalse) { return c ? ifTrue : ifFalse;}
Tuesday, May 18, 2010
int one() { printf("One!"); return 1;}
int two() { printf("Two!"); return 2;}
...
int c = choice(n == 1, one(), two());
Tuesday, May 18, 2010
#define CHOICE(c,ifTrue,ifFalse) \ (c) ? (ifTrue) : (ifFalse)
Tuesday, May 18, 2010
#define CHOICE(c,ifTrue,ifFalse) \ (c) ? (ifTrue) : (ifFalse)
int c = CHOICE(n == 1, one(), two());
Tuesday, May 18, 2010
#define CHOICE(c,ifTrue,ifFalse) \ (c) ? (ifTrue) : (ifFalse)
int c = CHOICE(n == 1, one(), two());
int c = (n == 1) ? (one()) : (two());
Tuesday, May 18, 2010
clojure (a Lisp)
Tuesday, May 18, 2010
homoiconiccode is datadata is code
Tuesday, May 18, 2010
(+ 1 2 3)
Tuesday, May 18, 2010
(+ 1 2 3) = 6
Tuesday, May 18, 2010
'(+ 1 2 3)
Tuesday, May 18, 2010
(first '(+ 1 2 3))
Tuesday, May 18, 2010
(first '(+ 1 2 3)) = +
Tuesday, May 18, 2010
(cons '+ (reverse (rest '(+ 1 2 3))))
Tuesday, May 18, 2010
(cons '+ (reverse (rest '(+ 1 2 3))))
= (+ 3 2 1)
Tuesday, May 18, 2010
(cons '+ (reverse (rest '(+ 1 2 3))))(eval
)
Tuesday, May 18, 2010
(cons '+ (reverse (rest '(+ 1 2 3))))
= 6
(eval)
Tuesday, May 18, 2010
(if (= n 10) (print "It was ten!”) nil)
Tuesday, May 18, 2010
(when (= n 10) (print "It was ten!”))
Tuesday, May 18, 2010
(defn when [c ifTrue] (if c ifTrue nil))
Tuesday, May 18, 2010
(when (= n 10) (print "It was ten!”))
Tuesday, May 18, 2010
(defmacro when [c ifTrue] (list 'if c ifTrue 'nil))
Tuesday, May 18, 2010
(defmacro when [c ifTrue] `(if ~c ~ifTrue nil))
Tuesday, May 18, 2010
(when (= n 10) (print "It was ten!”))
(if (= n 10) (print "It was ten!”) nil)
Tuesday, May 18, 2010
(when (= n 10) (print "It was ten!”))
(if (= n 10) (print "It was ten!”) nil)
Tuesday, May 18, 2010
(loop for i in *random* counting (evenp i) into evens counting (oddp i) into odds summing i into total maximizing i into max minimizing i into min finally (return (list min max total evens odds)))
Tuesday, May 18, 2010
(defent User [:username :string {:unique true}] [:openid :string] [:email :email] [:points :int])
http://github.com/zefhemel/adia
Tuesday, May 18, 2010
(defwebfn show [u User] [:h1 "Posted items"] [:ul (for [i (query Item :where {:author (:_id u)} :order-by {:date -1})] [:li (:title i)])])
Tuesday, May 18, 2010
advantages
Tuesday, May 18, 2010
easy to develop
builds on existing platform
existing community
Tuesday, May 18, 2010
disadvantages
Tuesday, May 18, 2010
<h1>Hello, Rails!</h1>
<%= link_to "My Blog", post_path %>
http://zef.me/2308/when-rails-fails
Tuesday, May 18, 2010
<h1>Hello, Rails!</h1>
<%= link_to "My Blog", post_path %>
post_url failed to generate from {:controller=>"posts", :action=>"show"} – you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["posts", :id] – are they all satisfied?
http://zef.me/2308/when-rails-fails
Tuesday, May 18, 2010
<%= link_to 'Destroy', post, :confrm => 'Are you sure?', :method => :delete %>
Tuesday, May 18, 2010
<%= link_to 'Destroy', post, :confrm => 'Are you sure?', :method => :delete %>
Tuesday, May 18, 2010
class Post < ActiveRecord::Base validates_presence_of :namend
Tuesday, May 18, 2010
class Post < ActiveRecord::Base validates_presence_of :namend
Tuesday, May 18, 2010
no static checking
late discovery of errors
Tuesday, May 18, 2010
no static checking
late discovery of errors
Tuesday, May 18, 2010
Tuesday, May 18, 2010
Tuesday, May 18, 2010
non-domain specific error messages
Tuesday, May 18, 2010
Tuesday, May 18, 2010
errors hard to trace back to origin
Tuesday, May 18, 2010
Table t = table("table").as("t");Table t1 = table("table1").as("t1");Field tId = t.field("id");Field t1Id = t1.field("id");Field t1Time = t1.field("time");
Sql sql = select(tId).from(t).join(inner(t1, tId.eq(t1Id))) .where(and(tId.eq("'a'"), t1Time.between("'1900'", "'2000'"))) .groupBy(tId).having(tId.gt("1")) .orderBy(asc(tId));
http://www.jequel.de
Tuesday, May 18, 2010
limited freedom in syntax
Tuesday, May 18, 2010
+ -quick development lack of static checking
built on existing platform
errors hard to trace back to origin
existing community bad error messages
limited freedom in syntax
Tuesday, May 18, 2010
?Tuesday, May 18, 2010