
A Theory of Substructural Types and Control Jesse A. Tov Riccardo Pucella Northeastern University, Boston, Massachusetts, USA {tov,riccardo}@ccs.neu.edu Abstract cause the method raises an exception but does not return the Exceptions are invaluable for structured error handling in successfully allocated reference, there is no way for recovery high-level languages, but they are at odds with linear types. code that catches the exception to free the reference. More generally, control effects may delete or duplicate por- In short, exceptions and linear types refuse to get along, tions of the stack, which, if we are not careful, can invalidate because linear types make promises that exceptions do not all substructural usage guarantees for values on the stack. let them keep. We have developed a type-and-effect system that tracks con- With affine rather than linear types, however, divRef is trol effects and ensures that values on the stack are never not a problem, because such a type system does not require wrongly duplicated or dropped. We present the system first that references be freed explicitly. In a language with affine with abstract control effects and prove its soundness. We types, implicitly dropping a value is just fine—presumably then give examples of three instantiations with particular there is a garbage collector—and only duplication is forbid- control effects, including exceptions and delimited contin- den. Consider, however, adding delimited continuation oper- uations, and show that they meet the soundness criteria for ators such as shift and reset to a language with affine types. specific control effects. Assuming a method unref that dereferences and deallocates a reference, we might attempt to define a method squareRef Categories and Subject Descriptors D.3.3 [Programming that takes a reference to an integer, frees it, and returns its Languages]: Language Constructs and Features contents, squared: General Terms Languages def twiceTo(x: Int) = shift { (k: Int ) Int) ) k(k(x)) } 1. Substructural Types and Control def squareRef (r: Ref[Int]) = Consider, for example, a language like Scala (Odersky and reset { twiceTo(1) × r.unref () } Zenger 2005) with mutable references and arithmetic. Here Method twiceTo uses shift to capture its continuation up to is a method that takes two integers and divides each by the the nearest enclosing reset, and it then applies the captured other, returning a pair of references to their quotients: continuation k twice to the parameter x. Method squareRef def divRef (z 1: Int, z 2: Int) = provides the context for twiceTo to capture, which is to free (new Ref(z 1 = z 2), new Ref(z 2 = z 1)) r and multiply by its contents: Suppose that references in this language are linear, mean- [] × r.unref () . ing that they cannot be duplicated, and must be explicitly deallocated rather than implicitly dropped. In such a lan- Since twiceTo uses its continuation twice, the second use of guage, divRef has a memory leak. Most uses of divRef the continuation will access a dangling pointer that the first are harmless, but consider the expression divRef (0, 5). The use freed. method will raise a division-by-zero exception, but (assum- Typically, an affine type system works by imposing two ing one reasonable evaluation order) only after it has allo- syntactic requirements: a variable of affine type, such as cated a reference to hold the result of the first division. Be- r, cannot appear twice in its scope (up to branching), and a function that closes over an affine variable must itself have an affine type. The squareRef example violates neither dictum. In the presence of delimited continuations, we need Permission to make digital or hard copies of all or part of this work for personal or to add a third rule: that a captured continuation that contains 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 an affine value must not duplicated. A simple approximation on the first page. To copy otherwise, to republish, to post on servers or to redistribute of this rule is to give all captured continuations an affine to lists, requires prior specific permission and/or a fee. OOPSLA’11, October 22–27, 2011, Portland, Oregon, USA. (or in a linear system, linear) type. Such a rule would per- Copyright c 2011 ACM 978-1-4503-0940-0/11/10. $10.00 mit some limited uses of delimited continuations, such as coroutines, but we will show that this simple rule is overly about how continuations will be used in a non-substructural restrictive. source language, whereas we want to reason about contin- uations in order to safely use substructural types. Thielecke Our solution. The memory leak and dangling pointer in has linear types only in the object language of his translation, the above examples can be fixed by small changes to the whereas we are interested in linear (and other substructural) code. For divRef , it suffices to ensure that both divisions types in the source language. happen before both allocations: Other recent work relates substructural logics and control. def divRef (z 1: Int, z 2: Int) = { Kiselyov and Shan(2007) use a substructural logic to al- val z 12 = z 1 = z 2 low the “dynamic” control operator shift0 to modify answer val z 21 = z 2 = z 1 types in a typed setting. Unlike this work, their terms are (new Ref(z 12), new Ref(z 21)) structures in substructural logic, not their types. Mazurak } and Zdancewic’s Lolliproc (2010) relates double negation elimination in classical linear logic to delimited control. For squareRef , we need the dereferencing to happen once, We draw significantly on other work on control operators, outside the reset delimiter: effect systems, and substructural types as well. def squareRef (r: Ref[Int]) = { val z = r.unref () Control operators. The literature contains a large vocabu- reset { twiceTo(1) × z } lary of control operators, extending back to ISWIM’s J opera- } tor (Landin 1965), Reynolds’s escape (1972), and Scheme’s call/cc (Clinger 1985). However, for integration in a lan- Unfortunately, the conservative approximation suggested guage with substructural types, control operators with delim- above, that all continuations be treated linearly, would still ited extent, originating with Felleisen’s F (1988), are most disallow these repaired examples. We have designed a type- appropriate, because without some way to mask out control and-effect system (Lucassen and Gifford 1988) that permits effects, any use of control pollutes the entire program and these two repaired versions of the methods while forbidding severely limits the utility of substructural types. the original, erroneous versions. The key idea is to assign to As examples of control features to add to our calculus, we each expression a control effect that reflects whether it may consider the delimited continuation operators shift and reset duplicate or drop its continuation, and to prohibit using an (Danvy and Filinski 1989) and structured exception handling expression in a context that cannot be treated as the control (Goodenough 1975). Both shift/reset and structured excep- effect allows. In this paper, we tions have been combined with type-and-effect systems to • exhibit a generic type system for substructural types and make them more amenable to static reasoning. control defined in terms of an unspecified, abstract con- trol effect (§4); Type-and-effect systems for control. Java (Gosling et al. 1996) has checked exceptions, an effect system for tracking • give soundness criteria for the abstract control effect and the exceptions that a method may raise. Our version of prove type safety for the generic system, relying on the exception effects is similar to Java’s, except that we offer ef- soundness of the abstract control effect (§5); and fect polymorphism, which makes higher-order programming • demonstrate three concrete instantiations of control ef- with checked exceptions more convenient. Our type system fects and prove that they meet the soundness criteria (§6). for exceptions appears in §6.3. Because Danvy and Filinski’s shift (1989) captures a de- The generic type-and-effect system in §4 is defined as limited continuation up to the nearest reset delimiter, typing an extension to λURAL (Ahmed et al. 2005), a substructural shift and reset requires some nonlocal means of communi- λ calculus, which we review in §3, after discussing related cating types between delimiters and control operators. They work in §2. realize this communication with a type-and-effect system, which allows shift to capture and compose continuations of 2. Related Work and Comparison varying types. Asai and Kameyama(2007) extend Danvy This work is not the first to relate substructural types to con- and Filinski’s (monomorphic) type system with polymor- trol operators and control effects. Thielecke(2003) shows phism, which includes polymorphism of answer types. We how to use a type-and-effect system to reason about how give two substructural type systems with shift and reset. expressions treat their continuations. In particular, he gives Section 6.1 presents a simpler version that severely limits the a continuation-passing style transform where continuations answer types of continuations that may be captured. Then, that will be used linearly are given a linear type. Thielecke in §6.2, we combine the simpler system with a polymor- notes that many useful applications of continuations treat phic version of Danvy and Filinski’s, similar to Asai and them linearly. However, his goals are different than ours. Kameyama’s, to allow answer-type modification and poly- He uses substructural types in his object language to reason morphism in a substructural setting. Substructural type systems. Researchers have proposed a v ::= x j λx.e j Λ:e j hij inl v j inr v (values) plethora of substructural type systems.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages17 Page
-
File Size-