Links: Web Programming Without Tiers? Ezra Cooper, Sam Lindley, Philip Wadler, and Jeremy Yallop University of Edinburgh Abstract. Links is a programming language for web applications that generates code for all three tiers of a web application from a single source, compiling into JavaScript to run on the client and into SQL to run on the database. Links supports rich clients running in what has been dubbed ‘Ajax’ style, and supports concurrent processes with statically-typed message passing. Links is scalable in the sense that session state is preserved in the client rather than the server, in contrast to other approaches such as Java Servlets or PLT Scheme. Client-side concurrency in JavaScript and transfer of computation between client and server are both supported by translation into continuation-passing style. 1 Introduction A typical web system is organized in three tiers, each running on a separate computer (see Figure 1). Logic on the middle-tier server generates pages to send to a front-end browser and queries to send to a back-end database. The programmer must master a myriad of languages: the logic is written in a mixture of Java, Perl, PHP, and Python; the pages described in HTML, XML, and JavaScript; and the queries are written in SQL or XQuery. There is no easy way to link these — to be sure that a form in HTML or a query in SQL produces data of a type that the logic in Java expects. This is called the impedance mismatch problem. Links eliminates impedance mismatch by providing a single language for all three tiers. In the current version, Links translates into JavaScript to run on the browser and SQL to run on the database. The server component is written in O’Caml; it consists of a static analysis phase (including Hindley-Milner typechecking), a translator to JavaScript and SQL, and an interpreter for the Links code that remains on the server. Increasingly, web applications designers are migrating work into the browser. “Rich client” systems, such as Google Mail and Google Maps, use a new style of interaction dubbed “Ajax” [11]. Client-side Links compiles into JavaScript, a functional language widely available on most browsers. JavaScript is notoriously variable across platforms, so we have designed the compiler to target a common subset that is widely available. It would be easy to extend Links to support additional target languages, such as Flash or Java. However, we expect the popularity of Ajax will mean that standard and reliable versions of JavaScript will become available over the next few years. Links is a strict, typed, functional language. It incorporates ideas proven in other functional languages, including: – database query optimization, as found in Kleisli and elsewhere, ? Submitted to FMCO ‘06 query request Browser (HTML, XML, JavaScript) Server (Java, Perl, PHP, Python, Ruby) response Database (SQL, XQuery) result Fig. 1. Three-tier model – continuations for web interaction, as found in PLT Scheme and elsewhere, and – concurrency with message passing, as found in Erlang and elsewhere, All three of these features work better with immutable values rather than mutable objects. In Links, side effects play a limited (though important) role, being used for updates to the database and display, and communication between concurrent processes. Types ensure consistency between forms in the browser, logic in the server, and queries on the database; and between the sender and receiver of a message in a concurrent program. Links programs are scalable in the sense that session state is preserved in the client rather than the server. Many commercial web tools (like J2EE) and most research web tools (including current releases of PLT Scheme [15] and Mozart QHTML [9]) are not scalable in this sense. In Links, all server state is serialized and passed to the client, then restored to the server when required. This resumption passing style extends the continuation passing style commonly used in PLT Scheme and elsewhere. Links functions are labelled as to whether they are intended to execute on the client or the server; functions running on the client may invoke those on the server, and vice-versa. Database programming. Queries are written in the Links notation and compiled into SQL, a technique pioneered by Kleisli [7, 35] and now used in LINQ [18]. Web interaction. The notion that a programming language could provide support for web interaction first appears in the programming language MAWL [1]. The notion of continuation from functional programming has been particularly fruitful, being applied by a number of researchers to improve interaction with a web client, including Quiennec [25], Graham [13] (in a commercial system sold to Yahoo and widely used for building web stores), Felleisen and others [14, 15], and Thiemann [31]. Concurrency. Links supports concurrent programming in the client, using “share nothing” concurrency where the only way processes can exchange data is by message passing, as pioneered in Erlang [2] and Mozart [32]. XML programming. Links provides convenient syntax for constructing XML data, similar to that provided by XQuery [36]. The current version does not support regular expression types, as found in XDuce and other languages, but we may add them in a future version. Regular expression types were given a low priority, because they are already well understood from previous research [19]. Other languages. Other languages for web programming include Xtatic [16], Scala [22], Mozart [9], SML.NET [5], F] [30], Cω (based on Polyphonic C] [4] and Xen [6]), HOP [29], Ocsigen [3]. These languages have many overlaps with Links, as they are also inspired by the functional programming community. However, none of these languages shares Links’ objective of generating code for all three tiers of a web application from a single source — scripts for the front-end client, logic for the middle-tier server, and queries for the back-end database. We expect that providing a single, unified language as an alternative to the current multiplicity of languages will be a principal attraction of Links. This paper. We introduce Links by describing three examples in Section 2. Section 3 sketches our implementation of concurrency and client-server interaction. Section 4 gives an SQL-compilable subset of Links and details how it is compiled into SQL, while Section 5 describes typing for processes. Section 6 discusses some shortcomings of the current implementation and Section 7 concludes. 2 Links by example This section introduces Links by a series of examples. The reader is encouraged to try these examples online at http://groups.inf.ed.ac.uk/links/examples/ We begin with a dictionary-suggest example to introduce the basic functionality of Links, and then present two further examples that demonstrate additional capabilities: a draggable list, and a progress bar. 2.1 Dictionary suggest The dictionary suggest application presents a text box, into which the user may type a word. As the user types, the application displays a list of words that could complete the one being typed. A dictionary database is searched, and the first ten words beginning with the same prefix as the typed word are presented (see Figure 2). In addition, the user can add, update and delete definitions. To add a new definition the user fills in and submits the form at the bottom of the page by clicking ‘Add’. To update an existing definition the user clicks on one of the suggestions, which replaces the suggestion with a form containing the existing definition, and then edits and submits the form by clicking ‘Update’. This form also includes buttons for cancelling the update (which restores the original suggestion) and deleting the definition. Fig. 2. Dictionary suggest This application is of interest because it must perform a database lookup and update the display at every keystroke. Applications such as Google Suggest [17] have a similar structure. The Links version is based on an ASP.NET version of the same application, available online [21], using the same dictionary and formatting. It extends the ASP.NET version by allowing the definitions to be added, updated and deleted. The dictionary contains 99,320 entries. Links is acceptably fast for this application, and response times for the Links and ASP.NET versions appear identical. (However, we have only tested with a lightly loaded server.) The code for the application is shown in Figures 3–5; following is a short walkthrough of the code. On each keystroke, a Suggest message containing the current contents of the text field is sent to the handler process. The handler process passes the text content to the function suggest. This function calls completions on the server to find the first ten words with the given prefix, and format on the client to format the list returned. Doing the server interaction in a separate handler process allows the user interaction to remain responsive, even while looking up suggestions. var defsTable = table "definitions" with (id:String, word:String, meaning:String) where id readonly from database "dictionary"; fun newDef(def) server { insert defsTable values [def] } fun updateDef(def) server { update (var d <-- defsTable) where (d.id == def.id) set (word=def.word, meaning=def.meaning) } fun deleteDef(id) server { delete (var def <-- defsTable) where (def.id == id) } fun completions(s) server { if (s == "") [] else { take(10, for (var def <-- defsTable) where (def.word ˜ /s.*/) orderby (def.word) [def]) } } fun suggest(s) client { replaceChildren(format(completions(s)), getNodeById("suggestions")) } fun editDef(def) client { redraw(
Word:
Meaning:
, def.id) } Fig. 3. Dictionary suggest in Links (1) fun redraw(xml, defId) client { replaceChildren(xml, getNodeById("def:"++defId)) } fun formatDef(def) client { {stringToXml(def.word)} {stringToXml(def.meaning)}
} fun format(defs) client { <#>

Click a definition to edit it

for (var def <- defs) {formatDef(def)} } fun addForm(handler) client {
Word:
Meaning: