Contracts Be Misunderstood (Functional Pearl)
Total Page:16
File Type:pdf, Size:1020Kb
Oh Lord, Please Don’t Let Contracts Be Misunderstood (Functional Pearl) Christos Dimoulas, Max S. New, Robert Bruce Findler, Matthias Felleisen PLT, USA {chrdimo,maxsnew,robby,matthias}@racket-lang.org Abstract gramming language to not only express logical assertions about Contracts feel misunderstood, especially those with a higher-order their functions but also construct new forms of contracts with soul. While software engineers appreciate contracts as tools for ar- user-defined combinators. Especially in the context of languages ticulating the interface between components, functional program- that shout “domain specific languages” from every roof top—say mers desperately search for their types and meaning, completely Racket—researchers and developers ought to be able to eliminate the problems that plague sophisticated practical applications of forgetting about their pragmatics. 1 This gem presents a novel analysis of contract systems. Applied conventional contract systems. If they put their mind to it, they to the higher-order kind, this analysis reveals their large and clearly could construct linguistic mechanisms that raised the level of ex- unappreciated software engineering potential. Three sample appli- pressiveness and allowed programmers to articulate an unprece- cations illustrate where this kind of exploration may lead. dented detail of precision for a relatively low cost in terms of code. This gem demonstrates how this alternative mind set about con- Categories and Subject Descriptors D.3.3 [Programming Lan- tracts opens new possibilities. It starts with a novel conceptual guages]: Language Constructs and Features analysis of contracts, re-imagining them as an interlocking sys- tem of interposition points, linguistic constructs for contract attach- Keywords Contracts, Specifications, Language design ment, and DSLs for assembling logical assertions from rather sim- ple building blocks (section 2). This abstract analysis is illustrated 1. Contracts, “always left out, never fit in” with three distinct examples of formulating contracts for libraries Design by Contract [44] is a beautiful idea. Programmers articu- and components (section 3). These examples seemingly expand the late behavioral contracts and then the methods design themselves. convex hull of what behavioral software contracts can talk about, Implicitly, Meyer claims that this idea scales from small pieces of though they really just demonstrate untapped potential. Equipped code to large software systems. with these examples, the gem finally (section 4) describes the re- Beugnard et al. [6] confirm this claim with their survey on lationship between contracts and type systems, on one hand, and the lasting impact of contracts in their study of component-based run-time verification on the other. In short, the three of them form software, software adaptation, service oriented architectures, real- a triangle of complementary techniques for helping programmers time and high-performance computing. Contracts have also become with the difficult task of specifying interfaces. instrumental in the design of web-based systems to embedded Racket [27] is our language of choice to explain these ideas. It software. In these settings, contracts express and enforce a wide advertises itself as a tool for making DSLs, and it has been used range of component specifications; from basic null-pointer checks extensively to study contracts. Specifically, Racket comes with a to coordination protocols and quality of service statements. Sadly, triple of superlatives: our father’s parentheses, elegant weapons these achievements get only minimal support from mainstream for a more civilized way of delivering gems; the world’s most so- programming languages; most provide little more than constructs phisticated higher-order contract system [27, §8], and the galaxy’s for adding pre-conditions or post-conditions. To compensate for the best mechanism for formulating DSLs [27, §12]. None of the ideas lack of support from these conventional contract systems, software are Racket-specific, though, and with a sufficient amount of extra- engineers employ a mixture of ad hoc solutions, invent contract ordinary labor, Haskellians and Camelists can articulate the same design patterns, and rely on half-baked IDE support. ideas in the context of their villages. The introduction of contracts into higher-order functional lan- guages [22] offers a solution to these linguistic problems. In a higher-order world, contracts naturally become first-class citi- 2. “You hold the answers deep within your mind” zens, too. As a result, functional programmers may use their pro- Programming language research has struggled with the concept of “meaning” for nearly five decades. Back in 1968, James Morris [47, p. 9] re-phrased the philosopher C. W. Morris to define this key concept via a trichotomy as follows: 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 made or distributed for profit or commercial advantage and that copies bear this notice and the full citation 1. Syntax delineates the legal forms, or utterances, of a on the first page. Copyrights for components of this work owned by others than ACM language. must be honored. Abstracting with credit is permitted. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. Request permissions from [email protected]. 1 After the introduction of higher-order contracts, many researchers— ,. including three of the authors—spent valuable time on exploring their se- Copyright © ACM [to be supplied]. $15.00. mantics and their shallow use in the context of gradual typing systems. The http://dx.doi.org/10.1145/ title refers to vast number of these efforts. 2. Semantics treats with the relation between the forms, or values can implement interposition for an expressive set of con- expressions, in the language and the objects they denote. tracts, they are inadequate for others. Consider function contracts 3. Pragmatics treats with the relation between a language that describe temporal protocols. Realizing such a contract relies on and its users (human or mechanical). detecting calls to captured functions during the extent of a call to a closure. Such contracts require an interposition layer that intercepts We argue that from a strictly operational point of view, extensional events as well as intensional ones. Current approaches semantics are unnecessary. To specify a language, we need to obtain these intensional events fall back on aspect-oriented pro- only give its syntax and pragmatics. gramming [51] or code re-writing techniques [35]. Strangely enough, Morris then jumps to the conclusion that “[the] 2.2 The Language of Contracts, the Single pragmatics are most easily specified by how a machine ... will react when presented with a legal form of the language,” completely Eiffel-inspired contract systems allow programmers to articulate ignoring how a human relates to such legal forms. contracts with the constructs of the underlying programming lan- Ever since, efforts to give meaning mostly fall into one of two guage. Indeed, in a simplistic contract system, contracts are merely categories: denotational or operational. In the context of contracts, Boolean expressions over function (method) parameters, local vari- the first draws inspiration from type theory and deals well with ables (fields), and function results. Some contract systems inject @ type-like contracts [7, 23, 31]. The second category, due to Find- and D quantifiers, though because their universes are finite, pro- ler and Felleisen [22], opts for an operational method that speci- grammers consider them alternative names for definable functions. fies how checking contracts involves decomposing a contract into At first glance, Racket’s contract system extends this vocabulary its “atomic” constituents, which can be checked against flat val- with notations that mirror its nature as a higher-order functional ues. Both approaches have significant limitations. The first fails language. For example, to describe the behavior of contract systems with sufficient pre- (-> natural-number/c prime?) cision [13] or to scale to dependent higher-order contracts [20, 23]. The second covers the entire range of contracts but obscures the may specify a contract for a function that maps natural numbers actual workings of the contract system to such an extent that pro- to prime numbers. Restricting the domain even further can be grammers fail to perceive the full expressive power of contracts. accomplished with the and/c combinator: This section instead presents a conceptual analysis of contracts, (->(and/c natural-number/c(between/c0 10)) pulling together various strands of research on Racket’s contract (listof prime?)) system. From this perspective, a contract system consists of three parts: an interposition layer; a contract attachment mechanism; and The range of this function contract says that a list of prime num- a suite of contract combinators. The first controls which aspects of bers is expected. A programmer can specify a dependency among a program’s execution a contract system may monitor. The second several parameters and the result with the ->i notation. Here is an specifies the means for associating a contract with (the result of) an illustrative example: expression and its context. The value of the expression is dubbed (->i([s string?] the carrier of a contract, while the context