2. Chapter 4, Internal DSL
• Unlike
external
DSLs,
you
don’t
need
to
learn
about
grammars
and
language
parsing.
• Constrain
–
host
language
expression
• Ruby
• Lisp
• fluent
interface
vs
API
2
3. 4.1 Fluent and Command-Query APIs
• Method
Chaining
d1
=
new
Disk(150,
Disk.UNKNOWN_SPEED,
null);
Processor
p
=
new
Processor(2,
2500,
Processor.Type.i386);
Disk
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();
3
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
6
7. 4.2 The Need for a Parsing Layer
• Expression
Builder
• input:
fluent
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.
7
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();
8
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
9
10. 4.3 Using Functions
• nested
func]on
• combines
func]ons
by
making
func]on
calls
arguments
in
higher
level
func]on
calls.
computer(
• reflects
the
logical
syntax
tree
of
the
DSL
• change
in
evalua]on
order
processor(
cores(2),
speed(2500),
i386
),
• “(“,
“)”,
“,”
are
explicit.
noise
–
Lisp
disk(
size(150)
• (third(second(first)))
**
I
found
typo
),
disk(
size(75),
speed(7200),
SATA
)
);
10
11. 4.3 Using Functions
• nested
func]on
• the
hierarchic
structure
of
the
configura]on
is
echoed
by
the
language
constructs
themselves
• reflects
the
logical
syntax
tree
of
the
DSL
• evalua]on
order
• arguments
are
iden]fied
by
posi]on
rather
than
name
11
12. 4.3 Using Functions
• hybrid
computer(
• It
uses
Func]on
Sequence,
each
computer
processor()
func]on
uses
Nested
Func]on,
each
.cores(2)
.speed(2500)
processor
and
disk
is
using
Method
.type(i386),
Chaining.
disk()
.size(150),
• Advantages:
disk()
• Func]on
Sequence:
each
computer
.size(75)
.speed(7200)
defini]on
well
separated.
.iface(SATA)
• Nested
Func]on:
eliminates
a
Context
);
computer(
Variable.
processor()
.cores(4)
• Method
Chaining:
mul]ple
op]onal
);
arguments
12
17. 4.5 Using Grammars to Choose Internal
Elements
Structure
BNF
Consider
Mandatory
list
parent
::=
first
second
third
Nested
Func+on
(357)
Op]onal
list
parent
::=
first
maybeSecond?
Method
Chaining
(373),
maybeThird?
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
17
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
18
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
19
20. 4.7 Parse Tree Manipulation
• parse
tree
manipula]on
4.7 Parse Tree Manipulatio
BinaryExpression
Left Right
MemberAccess ConstantExpression
Member Expression Value
Age aPerson 18
Figure 4.2 A parse tree representation of aPerson.Age > 18
query in another query language, such as SQL. This is essentially what 20
.NET
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
record’s
dynamic
finders
24
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
25