310 likes | 334 Views
Explore the concept, motivation, and types of DSLs to enhance productivity and customization in software development. Learn about external and internal DSLs, theory of compilation, and building menus using DSLs.
E N D
Domain Specific Languages Based on http://martinfowler.com/dslwip
PROGRAMS=ex1_connect ex2_select all: $(PROGRAMS) clean: rm -f $(PROGRAMS) *.o include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk OPTIMIZE=$(OPTIMIZEG) .SUFFIXES: .o .cc .cc.o: $(CCC) $(CFLAGSCC) -c $< ex1_connect: ex1_connect.o $(LINKCC) ex1_connect.o $(SHARED_OCCILIBS) ex2_select: ex2_select.o $(LINKCC) ex2_select.o $(SHARED_OCCILIBS)
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app> <display-name>IMDB</display-name> <description>Internet Movie Database</description> <context-param> <param-name>db-url</param-name> <param-value>www.imdb.com/datacenter</param-value> </context-param> <servlet> <servlet-name>search</servlet-name> <servlet-class>my.package.SearchServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>search</servlet-name> <url-pattern>/search.html</url-pattern> </servlet-mapping> </web-app>
<menubar> <item name="File"> <item name="Open" mnemonic="O">commands.Open</item> <item name="Save" mnemonic="S">commands.Save</item> <item name="Save As" mnemonic="A">commands.SaveAs</item> </item> <item name="Edit"> <item name="Cut" mnemonic="T">commands.Cut</item> <item name="Copy" mnemonic="C">commands.Copy</item> <item name="Paste" mnemonic="P">commands.Paste</item> </item> </menubar>
last.file.name=c:\\files\\input.dat x=105 y=99 width=527 height=401
DSL • A language designed for solving a specific class of problems • “Do one thing well” • Less powerful than a general-purpose language (GPL) • Usually not Turing complete • If it’s not simpler to use than a GPL – no reason to use it
Motivation for DSLs • Initially: Customizability • Currently: Productivity
DSL: Customizability • Allow users to customize a program • Without recompiling it • Imagine: Unix’s make without the DSL • Make will be a library • User will write a program that uses the library • Will use API for defining the dependencies, actions, etc. • Compile & Run • In the good old days compilation was an issue
DSL: Productivity • In its domain a DSL is more productive than a general purpose language • Because it does one thing well • Example: String matching • Very easy with regular expressions • Much harder with manually written Java code • The direct result: DSLs are all over the place • Even if no user-customizability is needed
DSL Oriented Development • Development that focuses on building and using DSLs to develop a system • Various DSLs float around – each one solves a particular problem within the broader context • One cannot build a whole program with one DSL • Don’t overdo it – implementing a DSL takes effort
External DSL A DSL represented in a separate language to the host programming language
External DSL Highlights • Syntax • Custom-made • (Or) Follows a common format CSV, XML, etc. • Stages • Parsing and tree Construction • Semantic Model construction • Execution • Not all stages must exist • Developer may choose to do execution while parsing
[{ name: "File", shortcut:'F', children: [ { name:"Open", shortcut:'o', action:"p1.Main$FileOpen"}, { name:"Exit", shortcut:'x', action:"p1.Main$FileExit"} ] }, { name: "Edit", shortcut:'E', children: [ { name:"Cut", shortcut:'t', action:"p1.Main$EditCut"}, { name:"Paste", shortcut:'p', action:"p1.Main$EditPaste"} ] }]
Theory of Compilation & DSLs • Compilation courses often focus on advanced parsing issues • In practice, simple recursive descent parsers are fine • Even lexical scanners are not always needed • => No need to use parser generators • If you do want to use them: modern tools (Antlr, Javacc) are much simpler than Lex/Yacc • Bottom line: don’t panic
Internal DSL A DSL expressed within the syntax of a general purpose language. A stylized use of the language for a domain specific purpose.
Menu Definition API public class Menu { public Menu add(Menu m) { // add m as a child return this; } } public Menu item(String name){ ... } public Menu item(String name, char mnemonic) } ... } public Menu item(String name, char accelerator) } ... } public Menu item(String name, char mnemonic, char accelerator) } ... } public Menu item(String name, char mnemonic, ActionListener l) { ... } public Menu menubar(){ return new Menu(); }
Defining a Menu menubar() .add( item("File", 'f') .add(item("Open", 'o', new FileOpen())) .add(item("Exit", 'o', new FileExit()))) .add( item("Edit", 'e') .add(item("Cut", 'c', new EditCut())) .add(item("Paste", 'p', new EditPaste())));
Difficulties of the Proposed API • Order of parameters • Too many parenthesis • Must create an item() method for each subset of desired menu properties
A Better API public interface MenuBuilder { public MenuBuilder child(String name); public MenuBuilder shortcut(char c); public MenuBuilder action(ActionListener al); public MenuBuilder up(); // ... and a few more }
Defining a Menu (Again) new MenuBuilder() .child("File").shortcut('f') .child("Open") .shortcut('o').action(new FileOpen()) .up() .child("Exit") .shortcut('x').action(new FileExit()) .up() .up() .child("Edit").shortcut('e') .child("Cut") .shortcut('c').action(new EditCut()) .up() .child("Paste") .shortcut('p').action(new EditPaste()) .up() .up()
Internal DSL Highlights • Syntax • Based on the API • Heavy use of fluent interfaces • Stages • Semantic Model construction • Execution • Not all stages must exist • API may do the actual execution when called
Comparison • Pros: External DSL • Full control over syntax, semantics • User customizability • Pros: Internal DSL • Integration with the host language • IDE support
Rake File • Rake: A build system for the Ruby world • Similar to Java’s Ant, Unix’s Make • As expected uses a DSL for building program • Here’s a sample Rake file • Q: is this an internal or external DSL?
require 'rake/clean' PROG = "foo" LIBNAME = PROG LIBFILE = "lib#{LIBNAME}.a" SRC = FileList['**/*.c'] OBJDIR = 'obj' OBJ = SRC.collect { |fn| File.join(OBJDIR, File.basename(fn).ext('o')) } CLEAN.include(OBJ, OBJDIR, LIBFILE) CLOBBER.include(PROG) task :default => [:build, :run] # continued on next slide
# continued from previous slide task :build => [PROG] task :run => [PROG] do sh "./#{PROG}" end file PROG => [LIBFILE] do sh "cc -o #{PROG} -L . -l#{LIBNAME}" end file LIBFILE => OBJ do sh "ar cr #{LIBFILE} #{OBJ}" sh "ranlib #{LIBFILE}" end
DSL & Dynamic Languages • Dynamic languages are flexible • Syntax • Offer new constructs • Redefining semantics of existing constructs • Thus, they can support a wide spectrum of internal DSL syntaxes • The best of both worlds • Integration with the host language • IDE support • User customizability • (Almost) Flexible syntax
Language Workbench • A design approach • For a heavily used DSL • Multiple formats • Multiple editors • Minimal duplication of the DSL logic
The Trio • Abstract representation • Editors + Bi-directional translators • Generator(s) • Change of focus • From the DSL syntax to the abstract representation
Summary • DSL is likely to be more productive than a GPL • wrt to its domain • Developer can reduce development time • If they have a good set of DSLs • DSL oriented development • User can customize the program w/o recompiling • A DSL for the user may ends up being used by the programmer