Silverchain: a Fluent API Generator
Total Page:16
File Type:pdf, Size:1020Kb
Silverchain: A Fluent API Generator Tomoki Nakamaru Kazuhiro Ichikawa The University of Tokyo The University of Tokyo Japan Japan [email protected] [email protected] Tetsuro Yamazaki Shigeru Chiba The University of Tokyo The University of Tokyo Japan Japan [email protected] [email protected] Abstract fluent APIs such as Hamcrest15 [ ] and jMock [21]. Method This paper presents a tool named Silverchain, which gener- chaining is a coding style that concatenates consecutive ates class definitions for a fluent API from the grammar of method calls together like a chain. By method chaining, pro- the API. A fluent API is an API that is used by method chain- grammers can group semantically related method calls into ing and its grammar is a BNF-like set of rules that defines a single expression and keep code easy to understand. Fluent method chains accepted in type checking. Fluent APIs gen- APIs are a popular way of designing embedded domain- erated by Silverchain provide two styles of APIs: One is for specific languages (EDSLs), a form of DSLs that is imple- building a chain by concatenating all method calls in series. mented as a library in a general-purpose host language [17]. The other is for building a chain from partial chains by pass- Using a fluent EDSL, DSL sentences can be emulated well ing child chains to method calls in the parent chain as their without any change of the host language. For instance, Java arguments. To generate such a fluent API, Silverchain first programmers can compose an SQL query with jOOQ [12] as translates given grammar into a set of deterministic push- follows: down automata without ϵ-transitions, then encodes these //SELECT*FROM book //WHERE book.published_in= 2016; automata into class definitions. Each constructed automata String query = create.select() corresponds to a nonterminal in given grammar and recog- .from(BOOK) .where(BOOK.PUBLISHED_IN.eq(2016)).getSQL(); nizes symbol sequences produced from its corresponding nonterminal. Fluent APIs usually support subchaining style, which is a style of method chaining that passes a chain to a method call CCS Concepts • Software and its engineering → Do- in another chain as its argument. In the case of the example main specific languages; Source code generation; above, subchaining style is used in the where clause. This Keywords Fluent API, Embedded DSL feature improves the usability of fluent APIs in that program- mers can build an entire chain from semantically grouped ACM Reference Format: Tomoki Nakamaru, Kazuhiro Ichikawa, Tetsuro Yamazaki, and Shigeru partial chains. Note that subchaining style is effective for a Chiba. 2017. Silverchain: A Fluent API Generator. In Proceedings long or complex chain but not for a small or simple chain. of 16th ACM SIGPLAN International Conference on Generative Pro- Non-subchaining style, a style that concatenates all method gramming: Concepts and Experiences (GPCE’17). ACM, New York, calls in series, is useful when building a small or simple chain. NY, USA, 13 pages. https://doi.org/10.1145/3136040.3136041 To improve the usability further, fluent APIs are frequently designed to be type-safe by setting the return type of each 1 Introduction method based on which methods can be written next [2, 10]. A fluent API [10] is an API that is used by method chaining The users of a type-safe fluent API can find misuse easily and a number of well-known class libraries provide their from thrown type errors and autocompletion can provide necessary and sufficient candidate methods to the users. Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not Creating a well-designed fluent API, however, is not as made or distributed for profit or commercial advantage and that copies bear easy as using it. To make a fluent API type-safe, API devel- this notice and the full citation on the first page. Copyrights for components opers need to define a lot of classes and choose the return of this work owned by others than ACM must be honored. Abstracting with type of each method carefully. Further, each class definition credit is permitted. To copy otherwise, or republish, to post on servers or to gets complicated when making fluent APIs support both redistribute to lists, requires prior specific permission and/or a fee. Request permissions from [email protected]. subchaining and non-subchaining style. In fact, manually GPCE’17, October 23–24, 2017, Vancouver, Canada written fluent APIs often fail to follow their expected rules © 2017 Association for Computing Machinery. perfectly. The users of such incomplete APIs accidentally ACM ISBN 978-1-4503-5524-7/17/10...$15.00 https://doi.org/10.1145/3136040.3136041 199 GPCE’17, October 23–24, 2017, Vancouver, Canada T. Nakamaru, K. Ichikawa, T. Yamazaki, and S. Chiba build a chain causing runtime errors, and autocompletion With a fluent API, DSL sentences are embedded without any provides unnecessary or insufficient candidates to the users. change of the host language while those embedded sentences In this paper, we present a tool named Silverchain for gen- maintain domain-specific syntax. When using a non-fluent erating type-safe fluent APIs that support both subchaining API, the document is emulated in a different way as follows: and non-subchaining style. The input to Silverchain is the IDoc idoc = new IDoc (); grammar of a target fluent API, a BNF-like set of rules that idoc.addItem(new Item ( " Item 1 " )); Item item2 = new Item ( " Item 2 " ); defines method chains accepted in type checking. From given item2.addItem(new Item ( " Item 2 . 1 " )); grammar, Silverchain first constructs a set of deterministic item2.addItem(new Item ( " Item 2 . 2 " )); idoc.addItem(item2); pushdown automata without ϵ-transitions (called real-time String tex = idoc.toTeX(); deterministic pushdown automaton, or RDPDA for short), Without method chaining, code tends to contain meaning- each of which recognizes symbol sequences produced from less intermediate variables and does not resemble original its corresponding nonterminal in the grammar. These con- DSL sentences. String encoding and syntax extension are also structed RDPDAs are then encoded into class definitions for techniques to embed DSL sentences into Java source code. By the target fluent API. Silverchain can generate a fluent API string encoding, DSL sentences are directly written as string for any context-free grammar (CFG) but cannot generate literals in Java. Those sentences maintain domain-specific an API that fully supports non-subchaining style for some syntax but are often unreadable especially when they are kinds of grammars. This limitation is due to our construction long or contain escape sequences. Furthermore, no syntax method of RDPDAs. Silverchain differs from other generators checking is applied to DSL sentences at compile-time. By (or generating algorithms) in that generated APIs support extending Java syntax, programmers can compose a DSL subchaining and non-subchaining styles. We describe those sentence in Java as it is but introducing a syntax extension other generators later in Section 5. mechanism is still a research topic [9, 19]. Fluent APIs can be activated easily by importing them since they are just 2 Motivation libraries. As a motivating example, consider creating a Java fluent From the viewpoint of usability, it is essential to support API for IDoc, a small DSL for writing itemized documents. both subchaining and non-subchaining style in one fluent The following code shows an example use of IDoc and its API. Without subchaining, the example document is emu- lated as follows: translation into TEX: String tex = idoc() begin . begin () " Item 1 " . text ( " Item 1 " ) " Item 2 " . text ( " Item 2 " ) begin . begin ()// Nesting structure is flattened. " Item 2 . 1 " . text ( " Item 2 . 1 " ) " Item 2 . 2 " . text ( " Item 2 . 2 " ) end .end () end .end().toTeX(); // Translation to TeX \ begin { itemize }% Just"begin" in IDoc The readability gets worse as the length or the complexity \item Item 1 of a chain increases if a fluent API does not support sub- \item Item 2% Quoted string in IDoc \ begin { itemize } chaining style. The readability gets better by indentation \item Item 2.1 that reflects original nesting structures of the sentence, but \item Item 2.2 \end{ itemize }% Just"end" in IDoc such indentation is not naturally obtained with support from \end{ itemize } an integrated development environment (IDE). Subchain- In IDoc, itemized documents can be written more simply ing style is also effective when changing a part of a chain since IDoc is specialized to itemized documents. dynamically as follows: Using a Java fluent API for IDoc, programmers can com- List list1 = begin() ... .end(); List list2 = begin() ... .end(); pose an itemized document in Java as if they write it in IDoc. String tex1 = idoc() For instance, the IDoc sentence above is emulated in Java by . begin () . text ( " Item " ) method chaining as follows: .list(bool? list1 : list2) .end().toTeX(); String tex = idoc() . begin () // If only non-subchaining style is supported. text ( " Item 1 " ) IncompChain1 c1 = idoc().begin().text( " Item " ); . text ( ) " Item 2 " IncompChain2 c2; .list(begin() i f ( bool ) { . text ( ) " Item 2 . 1 " c2 = c1.begin() ... .end();// list1 . text ( " Item 2 . 2 " ) } e l s e { .end ()) c2 = c1.begin() ... .end();// list2 .end().toTeX(); } 200 Silverchain: A Fluent API Generator GPCE’17, October 23–24, 2017, Vancouver, Canada String tex2 = c2.end().toTeX(); 1 idoc -> list* ; 2 list -> " b e g i n " item + " end " ; When subchaining style is supported, the users can build a 3 item -> text list? ; 4 chain by combining the base chain and semantically grouped 5 START = idoc ; subchains according to satisfied conditions.