Type Soundness for Dependent Object Types (DOT)

Type Soundness for Dependent Object Types (DOT)

Type Soundness for Dependent Object Types (DOT) Tiark Rompf ∗ Nada Amin† rtifact A Comple * t * te ∗ * n * A te {firstname}@purdue.edu is W E Purdue University, USA: s A e n C l l L o D C S o † * * c P u e m s EPFL, Switzerland: {first.last}@epfl.ch E u O e e n v R t e O o d t a y * s E a * l u d a e t Abstract the DOT (Dependent Object Types) [4] family was finally presented in 2014 [5]. Scala’s type system unifies aspects of ML modules, object- The calculus proved sound by Amin et al. [5] is µDOT, a oriented, and functional programming. The Dependent Ob- core calculus that distills the essence of Scala’s objects that ject Types (DOT) family of calculi has been proposed as a may contain type members in addition to methods and fields, new theoretic foundation for Scala and similar expressive along with path-dependent types, which are used to access languages. Unfortunately, type soundness has only been es- such type members. µDOT models just these two features– tablished for restricted subsets of DOT. In fact, it has been records with type members and type selections on variables– shown that important Scala features such as type refinement and nothing else. This simple system already captures some or a subtyping relation with lattice structure break at least essential programming patterns, and it has a clean and in- one key metatheoretic property such as environment narrow- tuitive theory. In particular, it satisfies the intuitive and mu- ing or invertible subtyping transitivity, which are usually re- tually dependent properties of environment narrowing and quired for a type soundness proof. subtyping transitivity, which are usually key requirements The main contribution of this paper is to demonstrate for a soundness proof. how, perhaps surprisingly, even though these properties are Alas, Amin et al. also showed that adding other important lost in their full generality, a rich DOT calculus that includes Scala features such as type refinement, mixin composition, recursive type refinement and a subtyping lattice with in- or just a bottom type breaks at least one of these properties, tersection types can still be proved sound. The key insight which makes a soundness proof much harder to come by. is that subtyping transitivity only needs to be invertible in The main contribution of this paper is to demonstrate code paths executed at runtime, with contexts consisting en- how, perhaps surprisingly, even though these properties are tirely of valid runtime objects, whereas inconsistent subtyp- lost in their full generality, a richer DOT calculus that in- ing contexts can be permitted for code that is never executed. cludes both recursive type refinement and a subtyping lat- Categories and Subject Descriptors D.3.3 [Programming tice with full intersection and union types can still be proved Languages]: Language Constructs and Features sound. The key insight is that proper subtyping transitivity Keywords dependent object types, DOT, Scala, soundness only needs to hold for types assigned to runtime objects, but not for arbitrary code that is never executed. 1. Introduction The paper is structured around the main contributions as Modern expressive programming languages such as Scala follows: integrate and generalize concepts from functional program- ming, object oriented programming and ML-style module • We present the first sound calculus of the DOT family systems [32]. While most of these features are understood that includes recursive type refinement and a subtyping on a theoretical level in isolation, their combination is not, lattice with intersection and union types: first informally and the gap between formal type theoretic models and what with examples (Section 2), then formally (Section 3). is implemented in realistic languages is large. • We discuss the key properties that make a soundness In the case of Scala, developing a sound formal model proof difficult (Section 4). that captures a relevant subset of its type system has been • We present our soundness result. First, we give a small- an elusive quest for more than a decade. After many false step operational semantics (Section 5). Then we explain starts, the first mechanized soundness proof for a calculus of the proof strategy and key lemmas in details (Section 6). • We offer some perspective on how foundational type- theoretic work influences practice (Section 7). This is the author’s version of the work. It is posted here for your personal use. Not for redistribution. The definitive version was published in the following publication: We discuss related work in Section 8 and offer conclud- OOPSLA’16, November 2–4, 2016, Amsterdam, Netherlands ing remarks in Section 9. Our mechanized Coq proofs are ACM. 978-1-4503-4444-9/16/11... available from http://oopsla16.namin.net. http://dx.doi.org/10.1145/2983990.2984008 624 2. Types in Scala and DOT The actual List type is defined inside a container listModule, which we can think of as a first-class module. In an ex- Scala is a large language that combines features from func- tended DOT calculus error may signify an ‘acceptable’ run- tional programming, object-oriented programming and mod- time error or exception that aborts the current execution and ule systems. Scala unifies many of these features (e.g. ob- transfers control to an exception handler. In the case that we jects, functions, and modules) [32] but still contains a large study, without such facilities, we can model the abortive be- set of distinct kinds of types. These can be broadly classified havior of error as a non-terminating function, for example [28] into modular types: def error(): Bot = error(). named type: scala.collection.BitSet compound type: Channel with Logged refined type: Channel { def close(): Unit } And functional types : Nominality through Ascription In most other settings parameterized type: List[String] (e.g. object-oriented subclassing, ML module sealing), nom- existential type: List[T] forSome { type T } inality is enforced when objects are declared or constructed. higher-kinded type: List Here we can just assign a more abstract type to our list mod- While this variety of types enables programming styles ule: appealing to programmers with different backgrounds (Java, type ListAPI = { m => ML, Haskell, ...), not all of them are essential. Further uni- type List <: { this => fication and an economy of concepts can be achieved by re- type Elem def head(): this.Elem ducing functional to modular types as follows: def tail(): m.List & { type Elem <: this.Elem } ❀ class List[Elem] {} class List { type Elem } } ❀ List[String] List { type Elem = String } def nil(): List & { type Elem = Bot } ❀ List[T] forSome { type T } List def cons[T]: T => ❀ List List m.List & { type Elem <: T } => This unification is the main thrust of the calculi of the m.List & { type Elem <: T } DOT family. A further thrust is to replace Scala’s compound } types A with B with proper intersection types A&B. It is Types List and Elem are abstract, and thus exhibit nominal worth noting that the correspondence between higher-kinded as opposed to structural behavior. Since modules are just ob- types and existential types suggested above is not exact, in jects, it is perfectly possible to pick different implementa- particular with respect to well-kindedness constraints and tions of an abstract type based on runtime parameters. partial application to type arguments. Before presenting our val mapImpl = if (size < 100) ListMap else HashMap DOT variant in a formal setting in Section 3, we introduce the main ideas with some high-level programming examples. Objects and First Class Modules In Scala and in DOT, ev- Polymorphic Methods In the code above, we have still ery piece of data is conceptually an object and every opera- used the functional notation cons[T](...) for parametric tion a method call. This is in contrast to functional languages methods. We can desugar the type parameter T into a proper in the ML family that are stratified into a core language and a method parameter x with a modular type, and at the same module system. Below is an implementation of a functional time desugar the multi-argument function into nested anony- list data structure: mous functions: val listModule = new { m => def cons(x: { type A }) = ((hd: x.A) => ... ) type List = { this => References to T are replaced by a path-dependent type x.A. type Elem We can further desugar the anonymous functions into objects def head(): this.Elem def tail(): m.List & { type Elem <: this.Elem } with a single apply method: } def cons(x: { type A }) = new { def nil() = new { this => def apply(hd: x.A) = new { type Elem = Bot def apply(tl: m.List & { type Elem <: x.A }) = def head() = error() new { this => def tail() = error() type Elem = x.A } def head() = hd def cons[T](hd: T)(tl: m.List & { type Elem <: T }) = def tail() = tl new { this => }}} type Elem = T More generally, with these desugarings, we can encode def head() = hd the polymorphic λ-calculus System F [20, 35] and its exten- def tail() = tl sion with subtyping, System F<: [9], by defining a pointwise }} mapping over types and terms: 625 Intersection and Union Types At the end of the day, we X ❀ x.A want only one centralized configuration for our system, and we can create one by assigning an intersection type: ∀(X <: S)T ❀ { def apply(x: { type A <: S }): T } val globalConf: DBConfig & AuthConfig = new { Λ(X <: S)t ❀ new { def apply(x: { type A <: S }) = t } def getDB = "myDB" t[U] ❀ t.apply({ type A = U }) def getAuth = "myAuth" } Since globalConf corresponds to both DBConfig and AuthConfig, Apart from the translation of type variables into term we can use it to initialize both services: variables with type members, another difference is that F<: dbs.init(globalConf) supports only upper bounded type variables, while Scala and auths.init(globalConf) DOT allow both lower and upper bounds.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    18 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us