DSL - Domain Specific Languages, Chapter 4, Internal DSL
-
date post
18-Oct-2014 -
Category
Technology
-
view
636 -
download
4
Embed Size (px)
description
Transcript of DSL - Domain Specific Languages, Chapter 4, Internal DSL
Domain Specific Languages
Hiro Yoshioka March 15th, 2013 Rakuten Tower 2, Shinagawa, Tokyo, Japan
2
Chapter 4, Internal DSL
Unlike external DSLs, you dont need to learn about grammars and language parsing.
Constrain host language expression Ruby Lisp
uent interface vs API
3
4.1 Fluent and Command-Query APIs
Method Chaining Processor p = new Processor(2, 2500, Processor.Type.i386); Disk d1 = new Disk(150, Disk.UNKNOWN_SPEED, null); Disk d2 = new Disk(75, 7200, Disk.Interface.SATA); return new Computer(p, d1, d2); Method Chaining computer() .processor() .cores(2) .speed(2500) .i386() .disk() .size(150) .disk() .size(75) .speed(7200) .sata() .end();
4
4.1 Fluent and Command-Query APIs
Func]on Sequence computer() processor(); cores(2); speed(2500); i386(); disk(); size(150); disk(); size(75); speed(7200); sata();
5
4.1 Fluent and Command-Query APIs
6
4.1 Fluent and Command-Query APIs
Command-query separa]on Command: may change state, but not
return value Query: does not change state Name without context
Fluent: Name context is important
7
4.2 The Need for a Parsing Layer
Expression Builder input: uent interface output: a sequence of command-query API
Seman]c model Separa]ng the Seman]c model from
Expression Builders You can test them independently.
8
4.3 Using Functions
func]on most successful packaging, (also called subrou]ne, procedure, method)
computer(); processor(); cores(2); speed(2500); i386(); disk(); size(150); disk(); size(75); speed(7200); sata();
9
4.3 Using Functions Method Chaining and Func]on Sequence
Scope of the func]ons Func]on Sequence: ensure the func]ons
resolve properly global func]on complica]ng
namespace and introducing global variables for parsing data. Context Variables
Method Chaining avoids global object scoping avoid globalness,
extensibility nested func]on avoid context
variables
10
4.3 Using Functions
nested func]on combines func]ons by making func]on
calls arguments in higher level func]on calls.
reects the logical syntax tree of the DSL change in evalua]on order (, ), , are explicit. noise Lisp
(third(second(rst))) ** I found typo
computer( processor( cores(2), speed(2500), i386 ), disk( size(150) ), disk( size(75), speed(7200), SATA ) );
11
4.3 Using Functions
nested func]on the hierarchic structure of the
congura]on is echoed by the language constructs themselves
reects the logical syntax tree of the DSL evalua]on order arguments are iden]ed by posi]on rather
than name
12
4.3 Using Functions
hybrid It uses Func]on Sequence, each computer
func]on uses Nested Func]on, each processor and disk is using Method Chaining.
Advantages: Func]on Sequence: each computer
deni]on well separated. Nested Func]on: eliminates a Context
Variable. Method Chaining: mul]ple op]onal
arguments
computer( processor() .cores(2) .speed(2500) .type(i386), disk() .size(150), disk() .size(75) .speed(7200) .iface(SATA) ); computer( processor() .cores(4) );
13
4.3 Using Functions
hybrid problems punctua]onal confusion
comma, periods, semicolons,
14
4.4 Literal Collections
literal list
-- Java or C# computer( processor (...), disk(...), disk(...) ); -- Ruby computer [ processor(...), disk(...), disk(...) ]
15
4.4 Literal Collections
literal map named parameters symbol
immutable, symbol lookup :symbol (ruby syntax)
-- Ruby computer(processor(:cores => 2, :type => :i386), disk(:size => 150), disk(:size => 75, :speed => 7200, :interface => :sata)) -- Ruby 2.0 has a keyword arguments
16
4.4 Literal Collections
symbol
-- Ruby computer(processor(:cores => 2, :type => :i386), disk(:size => 150), disk(:size => 75, :speed => 7200, :interface => :sata))
17
4.5 Using Grammars to Choose Internal Elements
Structure BNF Consider
Mandatory list parent ::= rst second third Nested Func+on (357)
Op]onal list parent ::= rst maybeSecond? maybeThird?
Method Chaining (373), Literal Map (419)
Homogenous bag parent ::= child* Literal List (417), Func+on Sequence (351)
Hetrogenous bag parent ::= (this | that | theOther)* Method Chaining
Set n/a Literal Map
18
4.6 Closures
lambdas, blocks, anonymous func]ons
#ruby... ComputerBuilder.build do |c| c.processor do |p| p.cores 2 p.i386 p.speed 2.2 end c.disk do |d| d.size 150 end c.disk do |d| d.size 75 d.speed 7200 d.sata end end
19
4.6 Closures
Nested Closures inline nes]ng deferred evalua]on limited-scope variables
#ruby... ComputerBuilder.build do |c| c.processor do |p| p.cores 2 p.i386 p.speed 2.2 end c.disk do |d| d.size 150 end c.disk do |d| d.size 75 d.speed 7200 d.sata end end
20
4.7 Parse Tree Manipulation
parse tree manipula]on
ptg9438845
BinaryExpression
MemberAccess
Left
ConstantExpression
Right
Age
Member
aPerson
Expression
18
Value
Figure 4.2 A parse tree representation of aPerson.Age > 18
query in another query language, such as SQL. This is essentially what .NETsLinq language does. Linq allows you to express many SQL queries in C#, whichmany programmers prefer.
The strength of Parse Tree Manipulation is in allowing you to write expressionsin the host language that can then be converted into different expressions thatpopulate the Semantic Model (159) in ways that are beyond just storing the closureitself.
In C#s case above, this manipulation is done with an object model representa-tion of the parse tree. In Lisps case, this manipulation is done by macro transfor-mations on Lisp source code. Lisp is well suited to this because the structure ofits source code is very close to that of a syntax tree. Parse Tree Manipulation ismore widely used in Lisp for DSL workso much so that Lispers often wail atthe lack of macros in other languages. My view is that manipulating an objectmodel of the parse tree in C# style is a more effective way of doing Parse TreeManipulation than Lisp macrosalthough this may be due to my lack of practicewith Lisps macro processing.
Whatever mechanism you use, the next question is how important Parse TreeManipulation is as a technique for DSLs. One very prominent use is in LinqaMicrosoft technology that allows you to express query conditions in C# and turnthem into different query languages for various target data structures. In thisway, one C# query can be turned into SQL for relational databases and XPathfor XML structures, or kept in C# for in-memory C# structures. Its essentiallya mechanism that allows application code to do runtime code translation,generating arbitrary code from C# expressions.
Parse Tree Manipulation is a powerful, but somewhat complex, technique thathasnt been supported much by languages in the past, but these days has beengetting a lot more attention due to its support in C# 3 and Ruby. Since its rela-tively new (at least outside the Lisp world), its hard to evaluate how truly usefulit is. My current perception is that its a marginal techniquesomething that israrely needed but very handy on the occasions when that need arises. Translating
4.7 Parse Tree Manipulation 83
4: Implementingan Internal DSL
From the Library of Hiro Yoshioka
21
4.8 Annotation
Auribute in C#
class Person
validates_length_of :last_name, :maximum => 30
22
4.9 Literal Extension
Method Chaining chain begins on a literal integer,
e.g. 5.days.ago add methods to external library classes Cons: methods globally
23
4.10 Reducing the Syntactic Noise
Textual Polishing
24
4.11 Dynamic Reception
handle an unexpected call by run]me to a special method. programmers can override the method to do other things. method_missing in Ruby, doesNotUnderstand in Smalltalk
e.g., Rails Ac]ve records dynamic nders
25
4.12 Providing Some Type Checking
sta]c type checking or not type checking at compile ]me or run ]me modern IDEs provide excellent support based
on sta]c typing
26
Yoshioka