Proceedings Chapter

Featherweight Swift: A Core Calculus for Swift's Type System

RACORDON, Dimitri, BUCHS, Didier

Abstract

Swift is a modern general-purpose , designed to be a replacement for -based languages. Although primarily directed at development of applications for Apple’s operating systems, Swift’s adoption has been growing steadily in other domains, ranging from server-side services to machine learning. This success can be partly attributed to a rich type system that enables the design of safe, fast, and expressive programming interfaces. Unfortunately, this richness comes at the cost of complexity, setting a high entry barrier to exploit Swift’s full potential. Furthermore, existing documentation typically only relies on examples, leaving new users with little help to build a deeper under- standing of the underlying rules and mechanisms. This paper aims to tackle this issue by laying out the foundations for a formal framework to reason about Swift’s type system. We introduce Featherweight Swift, a minimal language stripped of all features not essential to describe its typing rules. Featherweight Swift features classes and protocol inheritance, supports retroactive modeling, and emulates Swift’s [...]

Reference

RACORDON, Dimitri, BUCHS, Didier. Featherweight Swift: A Core Calculus for Swift’s Type System. In: Proceedings of the 13th ACM SIGPLAN International Conference on Software Language En- gineering (SLE ’20). 2020.

Available at: http://archive-ouverte.unige.ch/unige:144345

Disclaimer: layout of this document may differ from the published version.

1 / 1 Featherweight Swift: A Core Calculus for Swift’s Type System

Dimitri Racordon Didier Buchs University of Geneva University of Geneva Department of Department of Computer Science Switzerland Switzerland [email protected] [email protected]

Abstract ACM Reference Format: Swift is a modern general-purpose programming language, Dimitri Racordon and Didier Buchs. 2020. Featherweight Swift: A designed to be a replacement for C-based languages. Al- Core Calculus for Swift’s Type System. In Proceedings of the 13th ACM SIGPLAN International Conference on Software Language En- though primarily directed at development of applications gineering (SLE ’20), November 16–17, 2020, Virtual, USA. ACM, New for Apple’s operating systems, Swift’s adoption has been York, NY, USA, 15 pages. https://doi.org/10.1145/3426425.3426939 growing steadily in other domains, ranging from server-side services to machine learning. This success can be partly at- tributed to a rich type system that enables the design of safe, 1 Introduction fast, and expressive programming interfaces. Unfortunately, Swift is a modern general-purpose programming language, this richness comes at the cost of complexity, setting a high developed by Apple to be a successor to C-based languages. entry barrier to exploit Swift’s full potential. Furthermore, Often introduced in the context of mobile and desktop appli- existing documentation typically only relies on examples, cations, Swift’s adoption in other domains has been growing leaving new users with little help to build a deeper under- steadily since its open-source release in 2014, notably in the standing of the underlying rules and mechanisms. context of server-side and machine learning development. This paper aims to tackle this issue by laying out the foun- This success can be explained on one front by the language’s dations for a formal framework to reason about Swift’s type efficient memory model and seamless integration intothe system. We introduce Featherweight Swift, a minimal lan- C ecosystem, and on another by its powerful type system. guage stripped of all features not essential to describe its Swift enables the design of safe, fast and expressive pro- typing rules. Featherweight Swift features classes and proto- gramming interfaces by leveraging advanced features such col inheritance, supports retroactive modeling, and emulates as bounded polymorphism [11], existential types [31], and Swift’s overriding mechanisms. Yet its formalization fits on traits [19]. The latter in particular enables a discipline called a few pages. We present Featherweight Swift’s syntax and Protocol-Oriented Programming (POP). POP is a type-driven semantics. We then elaborate on the usability of our frame- paradigm that advocates for the use of protocols over con- work to reason about Swift’s features, future extensions, crete types. Protocols in Swift are similar to interfaces in and implementation by discussing a bug in Swift’s compiler, Java, abstract classes and concepts in C++, or traits in Scala. discovered throughout the design of our calculus. The central idea is to reason about type requirements (i.e., what types should be able to do) rather than properties of CCS Concepts: • Software and its engineering → Seman- a specific implementation. Sorting algorithms are a good tics; • Theory of computation → Operational semantics. canonical use case for such an approach. Although they are Keywords: protocol oriented programming, language se- often defined over numerical values, most sorting algorithms mantics, language calculus, type systems, swift are in fact agnostic of the type of the values being sorted, as long as it defines a total order relation. Following that Permission to make digital or hard copies of all or part of this work for observation, a protocol-oriented approach consists of first personal or classroom use is granted without fee provided that copies capturing this requirement in a protocol, and then writing are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights an algorithm that would rely on some existential type satis- for components of this work owned by others than the author(s) must fying this protocol, while remaining otherwise completely be honored. Abstracting with credit is permitted. To copy otherwise, or agnostic of any other implementation detail. republish, to post on servers or to redistribute to lists, requires prior specific Unfortunately, Swift’s type system comes at the cost of permission and/or a fee. Request permissions from [email protected]. complexity. While object-orientation is generally well known SLE ’20, November 16–17, 2020, Virtual, USA and understood by most developers, knowledge on POP pat- © 2020 Copyright held by the owner/author(s). Publication rights licensed to ACM. terns and related concepts is not nearly as widespread. As ACM ISBN 978-1-4503-8176-5/20/11...$15.00 a result, exploiting the language’s full potential requires a https://doi.org/10.1145/3426425.3426939 high-level of expertise and experience. Furthermore, existing SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs documentation focuses on examples and does not provide 1 protocol Serializable { a comprehensive overview of the type system’s rules and 2 func serialize() -> String mechanisms. This impedes new users, specifically students, 3 } to build a deeper understanding. The lack of a formal defini- The above protocol describes a type with a single method tion of the language’s semantics also precludes one’s ability serialize. The method takes no argument and is expected to reason about its design and implementation, in particular to return a serialized representation of its receiver (i.e., the to foresee interactions between different features. object on which it is called), as a character string. We propose to address these issues by the means of a for- There are two ways to indicate that a type conforms to mal framework describing Swift’s type system. We introduce a particular protocol. The first and most straightforward is Featherweight Swift (FS), a core calculus inspired by Feather- to specify the conformance directly within the type’s dec- weight Java (FJ) [23]. FS captures the fundamental concepts laration and to provide an implementation for all of the of Swift’s type system and discards all features that are not protocol’s requirements: essential to the description of its typing rules. It features class and protocol inheritance, supports retroactive modeling, and 1 class Customer: Serializable { emulates Swift’s overriding mechanism, but leaves out local 2 let id: String and global variables, exceptions, concurrency, and even as- 3 let name: String signment. This results in a functional subset whose complete 4 init(id: String, name: String) { formalization fits on a few pages. While our approach elides 5 self.id = id; self.name = name many peculiarities, such as the difference between value and 6 } reference semantics [35], the bareness of the language ex- 7 func serialize() -> String { poses Swift’s method lookup mechanism and type coercion 8 "(id:\(self.id), name:\(self.name))" rules clearly and concisely. As a result, FS helps language 9 } users and designers alike to generalize assumptions and test 10 } them against the compiler’s implementation. Here, the class Customer is declared conforming to the pro- We present Featherweight Swift’s syntax, type system, and tocol Serializable. The conformance is valid because the operational semantics. Although we do not provide a full class has a method that satisfies the protocol’s requirement. type soundness proof, we present the key properties related An alternative approach, called retroactive modeling [41], to the method lookup mechanism. We then illustrate the consists of extending an existing concrete type to specify framework’s usability to reason about Swift by discussing additional conformances and provide it with the associated one of the bugs we found in Apple’s compiler implementa- implementations. For example, one can specify that Swift’s tion, discovered throughout FS’s formalization. The bug has integers conform to the Serializable protocol: been reported and fixed in Swift 5.2. 1 extension Int: Serializable { 2 func serialize() -> String {"i(\(self))"} 2 Swift’s Type System in a Nutshell 3 } This section briefly introduces Swift’s type system, with a To preserve subtyping, retroactive modeling can only add particular focus on its support for protocols. It is worth not- constructs to a type and may not modify nor remove any ing that POP solves similar problems as Object-Oriented of its pre-existing characteristics. Simply put, an extension Programming (OOP) [2]. However, it aims to avoid common cannot alter any method or property from a type, nor can it pitfalls of class inheritance, such as the fragile base class subtract any protocol from its conformance set. problem [38], by advocating for composition over inheri- A protocol can refine (i.e., inherit from) one or several tance to keep class hierarchies as flat as possible. It also other protocols to represent an aggregate of requirements. differs from mixin-based inheritance [9], a technique that For instance, we can compose a protocol Doc, describing the consists of composing classes through multiple inheritance, requirements for types representing a document of some specifically because it does not rely on inheritance as acom- sort, with Serializable to represent persistent documents: position mechanism. Nonetheless, POP does not intend to 1 protocol Doc { replace object-orientation. Rather, it introduces features that 2 func title() -> String can be used to refine essential object-oriented aspects, such 3 } as encapsulation, polymorphism, and separation of concerns. 4 protocol PersistentDoc: Serializable, Doc { In Swift, a protocol represents a collection of requirements 5 func save(filename: String) to satisfy. These requirements are specified in the form of 6 } methods to implement or properties (a.k.a. fields in Java) to expose. For instance, one could define a protocol that Protocols may also appear in signatures to express the con- expresses the requirements of serializable types: straints of some concrete existential type [31] satisfying their Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA requirements. Anonymous compositions can be created lo- 1 protocol Equatable { cally when composition through inheritance does not result 2 func equals(other: Self) -> Bool in a reusable abstraction: 3 } 4 extension Equatable { 1 let doc: Serializable & Doc 5 func notEquals(other: Self) -> Bool { Unlike Java interfaces, protocols may refer to the concrete 6 !self.equals(other: other) type that conforms to them. For instance, consider a protocol 7 } Orderable describing types with a total order: 8 } 1 protocol Orderable { Conforming types may still override default implementa- 2 func lesser(other: Self) -> Bool tions, typically to provide optimized alternatives that can 3 } rely on the properties of the conforming type. Otherwise, This protocol requires a single method lesser, that should they will inherit all default implementations. One problem re- return whether another instance is smaller than the receiver1. lated to this feature occurs when two distinct protocols have Notice the use of the type Self (a.k.a. MyType in related liter- implementations for the same method requirement. This in- ature [10]), that serves as a placeholder for the conforming troduces an ambiguity for conforming types, which must type. This allows a protocol to specify methods that are not specify which implementation should be inherited. There compatible with other types conforming to the same proto- exists a handful of techniques to handle these cases [33]. col, which contributes to a stronger type safety. Indeed, the However, in Swift, conflicts can only be resolved by overrid- use of Self guarantees that two values of non-related types ing the default implementation in the conforming type, as (e.g., a number and a string) cannot be compared, even if both of this writing. Consider the following example: types conform to the protocol Orderable. In other words, if 1 protocol Dumpable { a type T conforms to the protocol Orderable, then it should 2 func dump() contain a method lesser with the type T → Bool. Conse- 3 } quently, the method will not accept a value of type U, even 4 extension Dumpable { if U also conforms to Orderable. This solves a common pit- 5 func dump() { print("Some Dumpable val.") } fall referred to as the binary method problem [10]. However, 6 } protocols with self requirements (i.e., defining a method or 7 property requirement annotated with Self) cannot be used 8 protocol Doc { to type an expression in a protocol composition. The reason 9 func title() -> String for this limitation is linked to the type safety guarantee we 10 } have just discussed. Should it be possible to type a variable x 11 extension Doc { with the protocol Orderable, then there would be no way to 12 func dump() { print(self.title()) } type-check a call to the method x.lesser statically. There 13 } are workarounds, like explicit parameterisation (e.g., Haskell 14 type classes and C++ concepts), multiple dispatch [13] or 15 class DummyDoc: Dumpable, Doc { type erasure [14], but an extensive discussion about such 16 func title() -> String {"A document"} techniques is beyond the scope of this paper. 17 func dump() { print("Some DummyDoc val.") } Swift supports protocol extensions as well. While such 18 } extensions cannot add additional conformances to a protocol, 19 they can be used to provide additional methods and/or de- 20 DummyDoc().dump() fault implementations for a protocol’s method and property 21 // Prints"Some DummyDoc val." requirements. The reader will remark that this feature is akin to the concept of partially implemented traits in languages The class DummyDoc conforms to Dumpable and Doc, and ob- such as Scala or Rust. For example, one can define a protocol tains two default implementations for dump, defined at line for equatable types which, similarly to Orderable, defines 5 and 12 respectively. Hence, it must solve the conflict by method requirements to check for equality between two in- overriding the method, which is done at line 17. stances2. Based on this description, a default implementation Notice that protocol extensions can provide implemen- of a method notEquals is obvious, and can be provided in a tations even when they are not defined as requirements. protocol extension. This is the case in the above example. The method dump is provided by an extension at line 12 even if the protocol 1 Note that the requirement is purely syntactical and does not prescribe Doc does not require it. This results in a subtle difference in anything about the method’s semantics. 2The reader proficient in Swift will notice that this definition of the lookup mechanism, reminiscent of non-virtual methods Equatable differs from Swift’s built-in protocol. This choice is delib- in C++ [4], that allows the compiler to dispatch methods erate and made to brush over the notion of static function requirements. statically. Hence, if the dump is called on an existential type SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs

satisfying Doc only, the implementation declared at line 12 most common features, FS drops non-member functions and will be called even if it is reimplemented in the concrete type. properties (i.e., functions and variables declared outside of This behavior is specific to protocol extensions and cannot a class), computed properties, exceptions, concurrency, and be reproduced with concrete types. It is not formalized in FS. side effects. All properties are considered to be let (a.k.a. constant) bindings, assigned only once in their class’ ini- 3 Featherweight Swift tializer, and method arguments cannot be reassigned. We Featherweight Swift is a strict functional subset of Swift, also elide the difference between value and reference types, which focuses on the latter’s essential features to describe whose respective observable behaviors are indistinguishable its type system. A program is described by a set of classes, in the absence of side effects. Despite all these omissions, protocols and extensions, and a single expression. The latter FS remains expressive enough to be Turing complete (one represents the behavior of the entire program. can encode the 휆-calculus in FS). Note that FS does not fea- ture generic types. While these account for a significant part of Swift’s type system, we prefer to focus solely on class 1 protocol Thing { inheritance and protocol conformance. 2 func duplicated() -> Pair Figure1 illustrates an example of a FS program. It starts 3 } with the declaration of a protocol Thing, which contains a 4 single requirement for a method duplicated. It is extended 5 extension Thing { at line 5 to provide a default implementation for its unique 6 func duplicated() -> Pair { requirement, which consists of initializing a new instance of 7 Pair(fst: self, snd: self) the class Pair using the method receiver for both elements. 8 } The program declares four classes, A, B, C and Pair at lines 9 } 11, 13, 17 and 21 respectively. A and B inherit from a built-in 10 root class Object and conform to the protocol Thing, but 11 class A: Object, Thing {} B additionally declares a property foo, which is inherited 12 by the class C. Pair declares two properties fst and snd, 13 class B: Object, Thing { along with a method withFst that returns a copy of itself 14 let foo: A in which the first element is substituted with the method’s 15 } argument. The use of these types is finally illustrated by the 16 expression at line 29, which initializes a pair, duplicates its 17 class C: B { second element to produce another pair, and substitutes its 18 let bar: A first element with an instance of the class C. 19 } 20 3.1 Formal Syntax 21 class Pair: Object { Let 퐶 denote a syntactic category, we write 퐶# for a possibly 22 let fst: protocol empty set of syntactic constructions that are generated by 퐶. 23 let snd: protocol Similarly, let 푆 be a set, we write 푆# ⊆ P(푆). 24 func withFst(v: protocol) -> Pair { 25 Pair(fst: v, snd: self.snd) Definition 3.1 (Featherweight Swift’s syntax). Let 퐼푝 de- 26 } note the set of protocol identifiers, 퐼푐 denote the set of class 27 } identifiers and 퐼푥 denote the set of variable, property, and 28 method identifiers. Let the metasyntactic variable 푝 range 29 Pair(fst: A(), snd: B(foo: A())) over 퐼푝 . Let 푐 and 푑 range over 퐼푐 , and 푥 range over 퐼푥 . FS’s 30 .snd syntax is described as follows: 31 .duplicated() Prog. Π F Pd# Cd# Xd# 푒 32 .withFst(C(foo: A(), bar: A())) 푝 퐼 # # Prot. Pd F protocol : 푝 { Rd } 33 // Evaluates to"Pair( 푐 푑, 퐼 # # # Class Cd F class : 푝 { Vd Md } 34 // fst:C(foo:A(), bar:A()), Ext. Xd F extension 푝 { Md# } 35 // snd:B(foo:A()))" 푐 퐼 # # | extension : 푝 { Md } Prop. Vd F let 푥 : 휏 Figure 1. A typical Featherweight Swift program Meth. Md F func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏 { 푒 } Req. Rd F func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏 From Swift, FS keeps protocols, extensions and classes, Expr. 푒 F 푥 | 푒.푥 | 푒 as 휏 | 푒 as! 휏 and its type system supports protocol conformance, protocol | 푒(푒1, . . . , 푒푛) | 푐(푥1 : 푒1, . . . , 푥푛 : 푒푛) 휏 푐 퐼 # 휏 휏 composition, and class inheritance. However, among Swift’s Type F | protocol⟨ 푝 ⟩ | → | Self Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA

FS’s syntax is defined to be as close as possible to that of omit static and class methods, as well as non-member func- Swift. In fact, FS programs can almost be copy-pasted into tions (i.e., functions declared outside of a class). Methods are a Swift compiler and have the same semantics. We assume first-class citizen in FS. Therefore, they must be treated as that a program does not contain duplicate type declarations. standard expressions (e.g., as arguments or return values), Similarly, we assume that classes do not contain duplicate and an application of the form 푒(푒1, . . . , 푒푛) may feature any property or method declarations and that methods do not kind of expression for 푒. An application whose receiver is a feature duplicate parameters. class identifier (i.e., 푐(푥1 : 푒1, . . . , 푥푛 : 푒푛)) denotes a call to A protocol declaration protocol 푝 : 푃 { 푅 } declares a the latter’s implicit initializer. In Swift, while all initializer protocol 푝 that refines each of the protocols in 푃. The decla- and method parameters are positional, they must also be ration’s body is a set of method requirements (i.e., methods named at the call site by default, unless defined otherwise that conforming types should implement), which are de- explicitly. However, as of this writing, parameter names are clared the just as regular methods, except that they do not actually not part of a method’s type. This means that a func- have a body. For simplicity, we omit property requirements. tion assigned to a variable, or passed as a parameter, cannot These would require the addition of computed properties be called with named parameters. We adopt a more consis- (i.e., properties whose values are the result of a method call), tent approach in FS. In order to avoid determining an order whose typing mechanism overlaps with regular methods. on property declarations and inheritance thereof, we always A class declaration class 푐 : 푑, 푃 { 푉 푀 } introduces a require parameters to be named in calls to a class’ implicit class named 푐 that inherits from a base class 푑, and conforms memberwise initializer. On the other hand, parameters to to each of the protocols in 푃. All class declarations define a method calls are kept positional only. supertype, for the sake of syntactic regularity. Consequently, We distinguish two sorts of cast expressions: 푒 as 휏 is classes that in standard Swift do not inherit from any base called a guaranteed cast and 푒 as! 휏 is called a forced cast. FS’s class are declared inheriting from a root class Object in FS3. typing rules ensure that a guaranteed cast cannot trigger an The body of a class declaration consists of a set of property error at runtime, whereas such an assumption is not verified declarations and a set of method declarations. Since the lan- statically for forced casts. We elide Swift’s safe casts (i.e., guage is free of side effects, all properties can be treated expressions of the form 푒 as? 휏 in Swift), as they involve as let (a.k.a. constant) bindings. In other words, all prop- generic option types (a.k.a. the maybe monad [32]), which erty declarations are of the form let 푥 : 휏, where 푥 is the are not supported in FS. name of the property being declared and 휏 is its type, and An expression can be typed by a class, a protocol compo- we omit default values. FS does not support overloading, sition (i.e., a set of protocols), a function type, or the special including for initializers. Thus, all classes necessarily have a type variable Self. The reader proficient in Swift will remark single memberwise initializer (i.e., an initializer that accepts the use of a legacy syntax for protocol composition, which an argument for each of the class’ properties), which we consists of a set of protocol identifiers enclosed in angle keep implicit for conciseness. Unlike in Swift, nested classes brackets and prefixed by the keyword protocol. While no (a.k.a. inner classes in Java) are prohibited. While such a fea- longer supported, this syntax lets us express the empty com- ture can serve to declutter the global namespace, it does not position protocol<> which corresponds to Swift’s built-in contribute to expressiveness. Furthermore, we also omit cus- Any type (i.e., an existential type without any requirement). tom deinitializer (a.k.a. destructors), as those cannot affect a A method or property may refer to the type in which it is program’s behavior in the absence of side effects. declared, allowing the declaration of self-referencing types. An extension declaration of the form extension 푝 { 푀 } In protocol declarations and extensions, the special type vari- is called a protocol extension. It provides a protocol 푝 with able Self designates the concrete conforming type. In class method implementations for its conforming types. Similarily, declarations and extensions, Self designates any derived an extension of the form extension 푐 : 푃 { 푀 } is called type that can inherit from the class: a class extension. It can provide a class 푐 with additional protocol conformances and method implementations. 1 class Parent: Object { A method declaration func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏 { 푒 } 2 func identity() -> Self { self } declares a method 푥 that accepts 푛 parameters and always 3 } returns a value, computed by evaluating the expression 푒 cor- 4 class Child: Parent {} responding to the method’s body. A method’s body can refer to a special variable self ∈ 퐼푥 that identifies the method’s The type of the method identity depends on that of the receiver and allows recursion. It is treated as a regular vari- receiver. If the method is called on an object of type Parent, able rather than a keyword, so that no additional typing or then the result will be an instance of Parent. On the other evaluation rule is required to describe property accesses. We hand, if it is called on an object of type Child, then the result will be an instance of Child. We elaborate further on the 3Such a root class does not exist in actual Swift, but can be easily reproduced. reasons for this subtlety later. SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs

3.2 Typing Semantics Example 3.5 (Protocol inheritance). Let 휋 be a program We now describe FS’s typing semantics. We start by in- defined as follows: troducing some notation to help formalizing predicates on 1 protocol P {} declarations more concisely. Let 휋 ∈ Π be a program, we 2 protocol Q: P {} write 휋 ⊢ protocol 푝 : 푃 { 푅 } to denote that the proto- 3 protocol R {} col 푝’s declaration is part of the program 휋. Similarly, we 4 class C: Object, Q {} write 휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } for class declarations, 5 class D: C, R {} 휋 ⊢ extension 푝 { 푀 } for protocol extensions and 휋 ⊢ 6 D() extension 푐 푃 { 푀 } : for class extensions. We use letters dec- From 휋, we can deduce that 휋 ⊢ Q ⊑ P and 휋 ⊢ D ⊑ P. orated with a tilde symbol (i.e., ∼) to denote declarations. Let 휏 푑ebe a protocol, class, property, method or method require- Definition 3.6 (Conformance set). Let be a protocol or class in a program 휋. We write conf (휏, 휋) for the set of pro- ment declaration, we write 푑.ename for its name and 푑.etype 푚 푚 푥 휏 휎 푒 tocols to which 휏 conforms in 휋. More formally: for its type. For example, let e = func ( : ) → { }, 푚. 푚 푚. 휏 휎 휏, 휋 푝 퐼 휋 휏 푝 e name = and e type = → . conf ( ) = { ∈ 푝 | ⊢ ⊑ } 푚 푚 휋 Definition 3.2 (Signature equivalence). Let e1 and e2 be Example 3.7 (Conformance set). Let be the program il- two method or method requirement declarations. We say lustrated in Example 3.5. program defined as follows: From 푚 푚 휋 ( , 휋) = { , , } that they are signature-equivalent, written e1 ≈ e2, if their , we can deduce that conf D P Q R . names and type signatures are identical. More formally: Both the subtyping and the conformance relations allow us 푚 푚 푚 . 푚 . 푚 . 푚 . e1 ≈ e2 ⇐⇒ e1 name = e2 name ∧ e1 type = e2 type to define polymorphic substitutability, which is referred toas type coercion in Swift. This is a purely syntactical application 푐 푑 Definition 3.3 (Class inheritance). Let and denote two of Liskov’s substitution principle [29]. classes in a program 휋, we write 휋 ⊢ 푐 ≤ 푑 if 푐 inherits from 푑 in 휋. Class inheritance is the reflexive and transitive Definition 3.8 (Coercion). Let 휏 and 휎 be two types in a closure of the immediate subclass relation specified in class program 휋. We write 휋 ⊢ 휏 ⊴ 휎 if 휏 can be coerced into 휎 in declarations. In formal terms, let 푐, 푑 and 푒 be class identifiers, 휋. In more formal terms, let 휏 and 휎 denote two types and ≤ is the minimal relation such that: let 푐 be a class identifier, coercion is defined as the minimal relation such that: 휋 ⊢ 푐 ≤ 푑 휋 ⊢ 푑 ≤ 푒 ∀푖, 휋 ⊢ 휎푖 ⊴ 휏푖 휋 ⊢ 휏푟 ⊴ 휎푟 휋 ⊢ 푐 ≤ 푐 휋 ⊢ 푐 ≤ 푒 휋 ⊢ 휏 ⊴ 휏 휋 ⊢ 휏1, . . . , 휏푛 → 휏푟 ⊴ 휎1, . . . , 휎푛 → 휎푟 휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } 휋 ⊢ 휏 ≤ 휎 ∀푝 ∈ 푃, 푐 ⊑ 푝 휋 ⊢ 푐 ≤ 푑 휋 ⊢ 휏 ⊴ 휎 휋 ⊢ 푐 ⊴ protocol⟨푃⟩ Definition 3.4 (Protocol conformance). Let 푝 and 푞 denote two protocols in a program 휋, we write 휋 ⊢ 푝 ⊑ 푞 if 푝 ∀푝 ∈ 푃, ∃푞 ∈ 푄, 휋 ⊢ 푝 ⊑ 푞 conforms to (i.e., inherits from) 푞 in 휋. Similarly, let 푐 denote 휋 ⊢ protocol⟨푃⟩ ⊴ protocol⟨푄⟩ a class, we write 휋 ⊢ 푐 ⊑ 푞 if 푐 conforms to 푞 in 휋. Protocol conformance (i.e., ⊑) is the reflexive and transitive closure Example 3.9 (Coercion). Let 휋 be the program illustrated of the immediate conformance relations declared in protocol in Example 3.5. program defined as follows: From 휋, we can and class declarations, as well as class extensions. In formal deduce that the following relations hold: terms, let 푝, 푞 and 푟 be protocol identifiers, and 푐 and 푑 be 휋 ⊢ (C, C → D) ⊴ (D, C → C) 휋 ⊢ C ⊴ protocol⟨⟩ class identifiers, ⊑ is the minimal relation such that: 휋 ⊢ protocol⟨Q, R⟩ ⊴ protocol⟨P, R⟩ 휋 ⊢ protocol 푝 : 푄 { 푅 } 푞 ∈ 푄 휋 ⊢ 푝 ⊑ 푝 휋 ⊢ 푝 ⊑ 푞 3.2.1 Name Lookup. We define a function props that ac- cepts a class and returns the set of properties available in 휋 ⊢ 푝 ⊑ 푞 휋 ⊢ 푞 ⊑ 푟 휋 ⊢ 푐 ≤ 푑 휋 ⊢ 푑 ⊑ 푝 that class. Note that props does not need to check extensions nor conformed protocol, as these may only define additional 휋 푝 푟 휋 푐 푝 ⊢ ⊑ ⊢ ⊑ methods in FS.

휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } 휋 ⊢ extension 푐 : 푃 { 푀 } props(Object, 휋) = ∅ 푞 ∈ 푃 푞 ∈ 푃 휋 푐 푑, 푃 푉 푀 푑, 휋 푉 ′ 휋 ⊢ 푐 ⊑ 푞 휋 ⊢ 푐 ⊑ 푞 ⊢ class : { } props( ) = props(푐, 휋) = 푉 ∪ 푉 ′ Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA

We define a function lookup푣 that returns the set of the prop- 1 protocol P{ erty declarations with the given name in the given class: 2 func ham() -> B 푣 ∈ (푥, 푐, 휋) ⇐⇒ 푣 ∈ (푐, 휋) ∧ 푣. 푥 3 } e lookup푣 e props ename = 4 extension P{ Example 3.10 (Property lookup). Let 휋 be a program de- 5 func foo() -> A { A() } fined as follows: 6 } 1 class C: Object {} 7 2 class D: C { let foo: C } 8 protocol Q {} 3 class E: D { let bar: D } 9 extension Q{ 4 E(foo: C(), bar: D(foo: C())) 10 func foo() -> A { B() } We can deduce that props(E, 휋) contains let foo : C and 11 } let bar : D. It follows that lookup(foo, D, 휋) = {let foo : C}. 12 13 protocol R: P, Q {} Both class inheritance and protocol conformance con- 14 extension R{ tribute to FS’s method lookup mechanism. The methods 15 func foo() -> A { C1() } that are associated with a class can be defined in the class’ 16 } declaration itself, in the declaration of another class from 17 which it inherits, in extensions of the class, or even in exten- 18 class A: Object { sions of the protocols to which the class conforms. While FS 19 func bar() -> A { A() } does not support method overloading, it allows overriding. 20 } A method declared in a class can be overridden in any of its 21 derived classes. Furthermore, methods required in a protocol 22 class B: A, P { de- and implemented in an extension are meant to define a 23 func ham() -> B { B() } fault behavior for all conforming types, and may therefore be 24 } overridden as well. Method lookup is thus performed along 25 two dimensions. The first and most straightforward relates 26 class C1: B, Q { to the class hierarchy. A method’s declaration is searched 27 func foo() -> A { C1() } starting from the most derived class and climbing up through 28 func bar() -> A { C1() } each superclass. Note that methods in class extensions are 29 } interpreted as being part of the class declaration and be- 30 long to the class hierarchy. The second dimension relates to 31 class C2: B, Q, R {} protocol conformance. If a method’s declaration cannot be 32 extension C2 { found within the class hierarchy, it is searched within the 33 func qux() -> A { C2() } extensions of the protocol to which the class conforms. 34 } Figure2 illustrates different scenarios of method inheri- tance and overriding. The protocols P, Q and R are all associ- Figure 2. Examples of method overriding ated with a single default implementation for a method foo, defined in protocol extensions at line 5, 10 and 15, respec- tively. The protocol P additionally requires that conforming types implement a method ham, as indicated by the method that the method foo must be overridden. The choice of its requirement declared at line 2. Note also that the protocol R implementation would be ambiguous otherwise, as class C1 inherits from both the protocols P and Q. The class A has only inherits the default implementations of both the protocols P one method, bar, defined directly in the class’ declaration, and Q. This is not the case for the class C2. The class conforms at line 19. This method is inherited by the class B through to the protocol R and thus inherits the latter’s default im- the traditional class inheritance mechanism. In addition, the plementation, declared at line 15. The latter overrides those class B has a method ham, declared at line 23, which satisfies associated with the protocols P and Q, since R refines both of the method requirement of the protocol P, whose confor- them. The class C2 also declares the method qux, but in an mance is declared at line 22. By the same conformance, the extension at line 33, rather than directly in its declaration. class also inherits the default implementation for the method Let 푀, 푁 ∈ P(Md) ∪ P(Rd) be two sets of method and foo, declared at line 5. The class C1 has three methods foo, method requirement declarations. We write 푁 ≫ 푀 the bar and ham. However, the two former are overridden in union of 푀 with 푁 subtracted by the declarations in 푀 that 4 the class’ declaration, at line 27 and 28, respectively . Note have a signature-equivalent declaration in 푁 . More formally: 4Swift demands that overridden methods be explicitly prefixed with the 푁 푀 푚 푀 푛 푁,푚 푛 푁 keyword override. We omit this requirement for the sake of conciseness. ≫ = {e ∈ | še ∈ e ≈ e} ∪ SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs

We define a function xmeths that accepts a protocol or class Finally, we write cmeths(푐, 휋) for the set that also gathers and gathers all methods declarations from its extensions. the implementations associated with conformed protocols: 휋 For instance, let be the program shown in Figure2, then CS = conf (푐, 휋) xmeths(R, 휋) = {func foo() → A { C1() }}. More formally, Ø 푀 = xmeths(푞, 휋) 푀 = cmeths (푐, 휋) ≫ 푀 let 휏 denote a protocol or a class in a program 휋, xmeths(휏, 휋) 푋 1 푋 푞∈CS is the minimal set such that: 푀 ′ 푚 푐 푚 푀 = {e[Self ↦→ ] | e ∈ } 휋 휏 푀 휋 휏 푃 푀 ⊢ extension { } ⊢ extension : { } cmeths(푐, 휋) = 푀 ′ 푀 휏, 휋 푀 휏, 휋 ⊆ xmeths( ) ⊆ xmeths( ) Recall that methods defined in the class hierarchy take prece- We then define a function pmeths that accepts a protocol and dence over method requirements and default implementa- gathers all method requirements and default implementa- tions, even if the conformance is not defined on a super- 푚 tions that are either associated directly with this protocol, class. More formally, if a declaration e푐 appears in a class 푐 푑 휋 푐 푑 or inherited from another protocol higher in its hierarchy. or any superclass such that ⊢ ≤ , and a protocol 푞 푐, 휋 For instance, let 휋 be the program shown in Figure2, then ∈ conf ( ) defines a requirement or default implementa- 푚 푚 푚 푚 푐, 휋 pmeths(R, 휋) = {func foo() → A { C1() }, func ham() → tion e푞, then e푐 ≈ e푞 =⇒ e푞 ∉ cmeths( ). Moreover, B}. More formally, let 푝 denote a protocol in a program 휋, notice that cmeths substitutes references to Self by the class pmeths(푝, 휋) is defined as the set such that: for which it builds the set of methods. For instance, if a class 푐 conforms to a protocol with a default implementation 휋 푝 푄 푅 푀 푝, 휋 ⊢ protocol : { } = xmeths( ) func foo(푥 Self) → Self { 푥 } Ø : , then it will be transformed CS = conf (푝, 휋) − {푝} 푀CS = pmeths(푞, 휋) as func foo(푥 : 푐) → 푐 { 푥 } in cmeths(푐, 휋). We define a func- 푞∈CS tion lookup푐푚 that returns the set of methods and method pmeths(푝, 휋) = (푀 ≫ 푅) ≫ 푀CS requirements with the given name in the given class: (푥, 푐, 휋) = {푚 ∈ (푐, 휋) | 푚. = 푥} Note that pmeths does not apply overriding between proto- lookup푐푚 e cmeths e name cols that do not have a conformance relationship. In other Similarly, we define a function lookup푝푚 that returns the set words, if two protocols 푞 and 푟 belong to the conformance of method requirement and default implementations with set of some protocol 푝 in a program 휋 such that neither the given name in the given protocol: 휋 ⊢ 푞 ⊑ 푟 휋 ⊢ 푟 ⊑ 푞 nor , then all requirements and default lookup (푥, 푝, 휋) = {푚 ∈ pmeths(푝, 휋) | 푚.name = 푥} implementations of 푞 and 푟 are inherited by 푝, even if they 푝푚 e e have the same signature. This is why foo must be overridden Example 3.11 (Method lookup). Let 휋 be the program in , 휋 by the class C1 in the program shown in Figure2. We show Figure2. The set cmeths0 (C2 ) of methods declared within later how FS’s type system checks that ambiguous method C2’s declaration contains only func qux() → A { C2() }. The , 휋 references are rejected in a well-typed program. set cmeths1 (C2 ) that also includes the methods declared Similarly to pmeths, we define a function cmeths that ac- in C2’s class hierarchy additionally contains func ham() → cepts a class and gathers all methods and method require- B{B() } and func bar() → A{A() }. Finally, the set con- ments that are declared directly in the class’ declaration, or taining the four methods available to the class C2 is given its extensions, or inherited from a superclass, or inherited by cmeths(C2, 휋) = {func ham() → B{B() }, func bar() → as a default implementation from a conformed protocol. We A { C2() }, func foo() → A { C1() }, func qux() → A { C2() }} 푐 decompose the lookup process into three steps. First, let be 3.2.2 Type Checking. The typing rules for expressions 휋 푐, 휋 a class in a program , we write cmeths0 ( ) for the set of are presented in Figure3. All rules are described in the form methods declared directly within its declaration and exten- of a typing judgment 휋, Γ ⊢ 푒 : 휏, where 휋 is a program, Γ 휋 sions. For instance, let be the program shown in Figure2, is a mapping from variable identifiers to types, 푒 is an ex- , 휋 cmeths0 (B ) is a singleton containing the method ham’s dec- pression and 휏 is the type of the expression. We draw the laration. More formally, cmeths0 is defined as follows: reader’s attention on a few subtleties. The rules TE-CProp 휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } and TE-CMeth correspond to the typing of a class member selection (i.e., a property or a method). Recall that lookup푣 cmeths0 (푐, 휋) = 푀 ∪ xmeths(푐, 휋) and lookup푐푚 returns sets of declarations. Consequently, the Next, we write cmeths1 (푐, 휋) for the set that also includes rules check that there is at least one candidate. However, it the declarations inherited from superclasses. For instance, does not ensure that this candidate is unique, which could cmeths1 (B, 휋) contains the declarations for ham and bar, in- lead to ambiguous situations. Fortunately, this cannot hap- herited from the class A in the program shown in Figure2. pen in a well-typed program because the typing rule for class declaration (described later) ensures that class mem- 휋 푐 푑, 푃 ... ⊢ class : { } bers are not overloaded. The same assumption does not hold cmeths1 (푐, 휋) = cmeths0 (푐, 휋) ≫ cmeths1 (푑, 휋) for protocol compositions (i.e., a protocol composition can Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA

TE-GCast TE-FCast TE-CProp TE-CMeth TE-Var 휋, Γ ⊢ 푒 : 휎 휋, Γ ⊢ 푒 : 휎 휋, Γ ⊢ 푒 : 푐 휋, Γ ⊢ 푒 : 푐 휏 (푥) 휋 ⊢ 휎 휏 (휏, 휋) 휋 ⊢ 휏 휎 (휏, 휋) 푣 ∈ (푥, 푐, 휋) 푚 ∈ (푥, 푐, 휋) = Γ ⊴ inst ⊴ inst e lookup푣 e lookup푐푚 휋, 푥 휏 휋, 푒 휏 휏 휋, 푒 휏 휏 휋, 푒.푥 푣. 휋, 푒.푥 푚. Γ ⊢ : Γ ⊢ ( as ) : Γ ⊢ ( as! ) : Γ ⊢ : etype Γ ⊢ : e type TE-PMeth 휋, Γ ⊢ 푒 : protocol⟨푃⟩ TE-Call TE-Init 푚 Ø 푥, 푝, 휋 휋, ⊢ 푒 (휏 , . . . , 휏 ) → 휏 (푐, 휋) = {푣 ,..., 푣 } ∀푖, 휋, ⊢ 푒 휎 { } = lookup푝푚 ( ) Γ : 1 푛 props e1 e푛 Γ 푖 : 푖 e 푖, 휋, 푒 휎 푖, 휋 휎 휏 푖, 푣 . 푥 휋 휎 푣 . 푝 ∈푃 ∀ Γ ⊢ 푖 : 푖 ∀ ⊢ 푖 ⊴ 푖 ∀ e푖 name = 푖 ∧ ⊢ 푖 ⊴ e푖 type 휋, 푒.푥 푚. 휋, 푒 푒 , . . . , 푒 휏 휋, 푐 푥 푒 , . . . , 푥 푒 푐 Γ ⊢ : e type Γ ⊢ ( 1 푛) : Γ ⊢ ( 1 : 1 푛 : 푛) :

Figure 3. Featherweight Swift’s expression typing be associated with overloaded symbols). As a result, the rule Definition 3.12 (Protocol conformance checking). Let 푐 be T-PMeth must also check for the candidate’s uniqueness. a class and 푝 a protocol in a program 휋 such that 휋 ⊢ 푐 ⊑ 푝. A cast is statically “guaranteed” (TE-GCast) if the type of We say that푐 satisfies its conformance to 푝, written 휋 ⊢ 푐 |= 푝, the expression to cast can be coerced into the specified type. if it has a single implementation for each of the method On the other hand, a cast whose specified type is a subtype of requirements defined by 푝 and the protocols from which 푝 the expression’s type cannot be type-checked statically, and inherits. More formally, ⊑ is the minimal relation such that: is therefore dubbed “forced” (TE-FCast). Note that casting between completely unrelated types (i.e., a pair 휏, 휎 such that 휋 ⊢ 푐 ⊑ 푝 휋 ⊢ protocol 푝 : 푄 { 푅 } 푟 푅, 푚 푐 ,푚 푟 neither 휋 ⊢ 휏 ≤ 휎 nor 휋 ⊢ 휎 ≤ 휏) necessarily results in a type ∀e ∈ ∃!e ∈ impls( ) e ≈ e error. Recall that protocols with self requirements cannot ∀푞 ∈ conf (푝, 휋) − {푝}, 휋 ⊢ 푐 |= 푞 be used to type an expression, due to the binary method 휋 ⊢ 푐 |= 푝 problem [10]. Hence, casting rules must also ensure whether the specified type is instantiable, which is performed by Type-checking for method declarations is described by checking a predicate inst, formally defined as follows: TD-PMeth and TD-CMeth, which determine whether a dec- laration is valid in the context of the protocol or class, re- 휋 ⊢ protocol 푝, 푄 { 푅 } spectively. Both rules verify that the type of the method’s ∀푞 ∈ 푄, inst(푞, 휋) 휋 ⊢ class 푐 : 푑, 푃 { ... } body is compatible with the method’s signature. This is done 푟 푅, 푟. , 휋 푑, 휋 ∀e ∈ inst(etype ) inst( ) in a fresh typing environment, in which only self and the inst(푝, 휋) inst(푐, 휋) method’s parameters are defined, to prevent methods from capturing any identifiers by closure. Recall that overriding ∀푞 ∈ 푃, inst(푞, 휋) does not apply to protocols’ requirements and default imple- mentations. Nonetheless, FS’s type system requires that all , 휋 , 휋 inst(Object ) inst(protocol⟨P⟩ ) methods with the same name have the same signature, which is checked in rule TD-PMeth. The rule TD-Protocol checks 푖 , . . . , 푛 , 휏 휏 , 휋 ∀ ∈ {0 } 푖 ≠ Self ∧ inst( 푖 ) that the conformance set of a protocol 푝 forms a directed inst(휏1, . . . , 휏푛 → 휏0, 휋) acyclic graph rooted by 푝, to avoid circular inheritance. It also prevents protocol extensions to declare a method implemen- The type-checking rules are presented in Figure4. Typ- tation without a matching requirement, thus disallowing stat- ing a program (TD-Program) consists of type-checking all ically dispatched methods. Class declarations additionally its declarations as well as the expression that represents its require that properties and methods cannot be overloaded. behavior. Type-checking for class declarations guarantees There should be a single implementation of each class mem- that all the requirements from the protocols to which the ber, which is checked in rules TD-CProp and TD-CMeth. This class conforms are actually fulfilled. Notice that protocol con- is not a requirement in TD-PMeth, as a protocol may receive formance is not a structural property. In other words, even multiple default implementations from the protocols that it if a class 푐 has an implementation for all the method require- refines. Consequently, a class that inherits multiple default ments in 푝, 푐 |= 푝 does not hold unless 푝 is explicitly defined implementations (typically obtained via different protocol as a protocol to which 푐 must conform (i.e., 푝 ∈ conf (푐)). We extensions) must override them, so that method calls are write impls(푐) ⊆ cmeths(푐) the set of complete method dec- not ambiguous. For instance, the declaration of the class C1 larations associated with 푐, that is the set of declarations that in Figure2 would no longer be well-typed if line 27 were have a body, and define conformance checking as follows: commented out. SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs

TD-Program TD-Protocol TD-Class 푝 푃, 푃,퐶, 푋, 푒 푝 푝. 푞 푝, 휋 , 푞 푝 푝 푐, 휋 , 휋 푐 푝 ∀e ∈ ( ) ⊢ e : ename š ∈ conf ( ) ⊑ ∀ ∈ conf ( ) ⊢ |= 푐 퐶, 푃,퐶, 푋, 푒 푐 푐. 푚 푝, 휋 , 푟 푅,푚 푟 푣 푐, 휋 , 휋, 푐 푣 푣. ∀e∈ ( ) ⊢ e: ename ∀e ∈ xmeths( ) ∃e ∈ e ≈ e ∀e ∈ props( ) ( ) ⊢ e: etype 푃,퐶, 푋, 푒 , 푒 휏 푚 푝, 휋 , 휋, 푝 푚 푚. 푚 푐, 휋 , 휋, 푐 푚 푚. ( ) ∅ ⊢ : ∀e ∈ pmeths( ) ( ) ⊢ e : e type ∀e ∈ cmeths( ) ( ) ⊢ e : e type ⊢ (푃,퐶, 푋, 푒) : 휏 휋 ⊢ protocol 푝, 푃 { 푅 } : 푝 휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } : 푐

TD-PReq TD-CProp ∀푚 ∈ (푥, 푝, 휋),푚. = 휏 , . . . , 휏 → 휏 푥, 푐, 휋 e lookuppm e type 1 푛 ∥ lookup푣 ( ) ∥= 1 휋, 푝 ⊢ func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏 : 휏1, . . . , 휏푛 → 휏 휋, 푐 ⊢ (let 푥 : 휏) : 휏

TD-PMeth TD-CMeth 휋, [self ↦→ 푝, 푥 ↦→ 휏 , . . . , 푥 ↦→ 휏 ] ⊢ 푒 휎 휋 ⊢ 휎 휏 푥, 푐, 휋 1 1 푛 푛 : ⊴ ∥ lookupcm ( ) ∥= 1 ∀푚 ∈ (푥, 푝, 휋),푚. 휏 , . . . 휏 → 휏 휋, 푐, 푥 휏 , . . . , 푥 휏 푒 휎 휎 휏 e lookuppm e type = 1 푛 [self ↦→ 1 ↦→ 1 푛 ↦→ 푛] ⊢ : ⊴ 휋, 푝 ⊢ func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏 { 푒 } : 휏1, . . . , 휏푛 → 휏 휋, 푐 ⊢ func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏 { 푒 } : 휏1, . . . , 휏푛 → 휏

Figure 4. Featherweight Swift’s declaration typing

3.3 Operational Semantics which happens to be another function call.

As mentioned earlier, thanks to the omission of assignment, Pair(fst: A(), snd: B(foo: A())) . snd FS’s semantics can be defined purely within its syntax. How- . duplicated() . withFst(C(foo: A(), bar: A())) ever, because methods are first-class citizens in FS, we need a way to represent bounded methods (i.e., methods in which The rule E-Call applies again, this time to evaluate the call references to self are bound to a receiver) as first-class to the method duplicated. This triggers the evaluation of terms. This is done by “demoting” a method to a non-member the function’s callee, which is the access class property snd: function in which all occurrences of self are syntactically Pair(fst: A(), snd: B(foo: A())) . snd substituted by the receiver. FS does not support unbounded . duplicated() . withFst(C(foo: A(), bar: A())) methods: an expression of the form 푐.푚 is not well-typed if 푐 ∈ 퐼푐 is a class identifier, as we would be unable to bind oc- The rule E-Prop applies on the property selection, evaluating currences of self to a proper class instance. The set of values Pair(fst: A(), snd: B(foo: A())) with the rule E-Init. V to which a terminating program may evaluate is therefore The term remains unchanged, as it is already in reduced composed of bounded methods and class initializers only. form (i.e., it only features calls to class initializers). Therefore More formally, it is defined inductively as the minimal set E-Prop’s application produces a term B(foo: A()) (i.e., the such that Md ⊆ V and 푐(푥1 : 푣1, . . . , 푥푛 : 푣푛) ∈ V, where second element of the pair), which now acts as the receiver 푐 ∈ 퐼푐 is a class identifier, 푥1, . . . , 푥푛 ∈ 퐼푥 are property names for the call to duplicated: 푣 , . . . , 푣 ∈ V and 1 푛 are values. B(foo: A()) . duplicated() We describe FS’s operational semantics as “big-step” se- . mantics rules, with a judgement of the form 휋 ⊢ 푒 ⇓ 푣, where withFst(C(foo: A(), bar: A())) 휋 ∈ Π is a program, 푒 ∈ 퐸 is an expression and 푣 ∈ V is a This results in the pair Pair(fst: B(foo: A()), snd: B( value. All rules are presented in Figure5. Unbounded meth- foo: A())), allowing the call to withFst to be evaluated: ods are bound upon method selection by the rule E-Meth. It Pair(fst:C(foo: A(), bar: A()), snd:B(foo: A())) results that function calls can remain completely agnostic of this process, and simply substitute function parameters The program successfully terminates with this term, which with their corresponding argument (rule E-Call). cannot be further reduced.

Example 3.13. Consider the expression following expres- The rule E-FCast, which corresponds to the evaluation sion, defined in the context of the program shown in Figure1: of an forced cast, refers to a function typeof to obtain the runtime type of a particular term, formally given as follows: Pair(fst: A(), snd: B(foo: A())) . snd typeof (푐(푥1 : 푣1, . . . , 푥푛 : 푣푛)) = 푐 . duplicated() . withFst(C(foo: A(), bar: A())) typeof (func 푥 (푥1 : 휏1, . . . , 푥푛 : 휏푛) → 휏) = 휏1, . . . , 휏푛 → 휏 The following steps describe the evaluation of this expression. The reader will notice that protocols are completely absent The rule E-Call applies first to evaluate the call to the method from the operational semantics, including the definition of withFst. This triggers the evaluation of the function’s callee, the function typeof . Indeed, while protocols may be use Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA

E-Init E-Prop E-FCast ∀푖, 휋 ⊢ 푒푖 ⇓ 푣푖 휋 ⊢ 푒 ⇓ 푐(. . . , 푥푖 : 푣푖,... ) 휋 ⊢ 푒 ⇓ 푣 휋 ⊢ typeof (푣) ⊴ 휏

휋 ⊢ 푐(푥1 : 푒1, . . . , 푥푛 : 푒푛) ⇓ 푐(푥1 : 푣1, . . . , 푥푛 : 푣푛) 휋 ⊢ 푒.푥푖 ⇓ 푣푖 휋 ⊢ 푒 as! 휏 ⇓ 푣

E-Meth E-Call 휋 푒 푐 푣 ′ ⊢ ⇓ ( ) 휋 ⊢ 푒 ⇓ func 푥 (푥1 : 휏1, . . . 푥푛 : 휏푛) → 휏 { 푒 } E-GCast 푥 푝 휏 푒 푥, 푐, 휋 푖, 휋 푒 푣 휋 푒 ′ 푥 푣 , . . . , 푥 푣 푣 휋 푒 푣 {func ( ) → { }} = lookupcm ( ) ∀ ⊢ 푖 ⇓ 푖 ⊢ [ 1 ↦→ 푖 푛 ↦→ 푛] ⇓ ⊢ ⇓

휋 ⊢ 푒.푥 ⇓ func 푥 (푝) → 휏 { 푒 [self ↦→ 푐(푣)] } 휋 ⊢ 푒(푒1, . . . , 푒푛) ⇓ 푣 휋 ⊢ 푒 as 휏 ⇓ 푣

Figure 5. Featherweight Swift’s operational semantics

to type an expression, runtime values can only be class in- • if 휏 ∈ 퐼푐 denotes a class and 휎 = protocol⟨푃⟩ is an in- stances and bounded methods. stantiable protocol composition for some set of protocols 푃 퐼 Ð 푝, 휋 휏, 휋 ⊆ P( 푝 ), then 푝 ∈푃 pmeths( ) ⊆ cmeths( ); 3.4 Properties • if 휏 = protocol⟨푃⟩ and 휎 = protocol⟨푄⟩ are two This section presents some key properties of FS’s type system. protocol compositions for some sets of protocols 푃, 푄 ⊆ 퐼 Ð 푞, 휋 Ð 푝, 휋 The first relate to overloading and guarantees that classes P( 푝 ), then 푞∈푄 pmeths( ) ⊆ 푝 ∈푃 pmeths( ). do not define overloaded properties and/or methods ina Proof. The proof is by induction on the definition of the well-typed program. The two first lemmas imply that there coercion operator (Definition 3.8). □ is a unique declaration corresponding to a name lookup in the rules TE-CProp and TE-CMeth, which respectively cor- Lemma 3.18. Let 푒 be a well-typed expression such that 휋, Γ ⊢ respond to the resolution of property and method names. 푒 휏 ′ ∀푥 ∈ ( ), ′(푥) 푚 : . Let Γ be typing context such that dom Γ Γ ⊴ The third additionally guarantees that e be a proper method Γ(푥). Then 휋, Γ′ ⊢ 푒 : 휏 ′ and 휏 ′ ⊴ 휏. declaration and not a mere requirement in TE-CMeth. Proof. The proof is by induction over the derivation FS’s Lemma 3.14. Let 푐 denote a class in a well-typed program expression typing (Figure3). □ 휋 ∈ Π, then 푐 does not define any overloaded property.

휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } FS supports recursion through self. As we chose to ex- press its operational semantics with big step inference rules =⇒ ∀푥 ∈ 퐼 , ∥ lookup (푥, 푐, 휋) ∥≤ 1 푥 푣 (in part to sidestep the so-called stupid cast problem [23]), Proof. The proof is straightforward by TD-Class. □ stating type soundness with the usual progress and preser- vation theorems [42] requires to take diverging evaluations Lemma 3.15. Let 푐 denote a class in a well-typed program into account. This disqualifies the classical approach which 휋 ∈ Π, then 푐 does not define any overloaded method. consists of defining a predicate 휋 ⊢ 푒 ⇓ error to character- ize type errors, as it does not allow the distinction between 휋 ⊢ class 푐 : 푑, 푃 { 푉 푀 } well-typed programs that terminate and those that diverge. ⇒ ∀푥 ∈ 퐼 , ∥ (푥, 푐, 휋) ∥≤ = 푥 lookupcm 1 Another strategy is to rely on coinduction to define a relation 휋 ⊢ 푒 ⇓∞ Proof. The proof is straightforward by TD-Class. □ of the form which denotes non-terminating evalu- ations [26]. Although we do not include such definitions, for Lemma 3.16. Let 푐 denote a class in a well-typed program spatial reasons, we state type soundness with this principle. 휋 ∈ Π, then all methods 푚 ∈ cmeths(푐, 휋) have an implemen- e Lemma 3.19 (Preservation). Let 푒 is a well-typed expression tation. such that 휋, ∅ ⊢ 푒 : 휏 and 휋 ⊢ 푒 ⇓ 푣, then 휋, ∅ ⊢ 푣 : 휎 =⇒ 휋 푐 푑, 푃 푉 푀 푚 푐, 휋 ,푚 ⊢ class : { } =⇒ ∀e ∈ cmeths( ) e ∈ Md 휎 ⊴ 휏. Proof. The proof is straightforward by TD-Class. □ Proof. The proof is by induction over the derivation of the relation 휋 ⊢ 푒 ⇓ 푣 (Figure5), using the substitution lemmas. Next, we state the substitution lemmas. □ Lemma 3.17. Let 휏 and 휎 be two types in a well-typed pro- 푒 gram 휋 such that 휋 ⊢ 휏 ⊴ 휎. The set of properties and methods Lemma 3.20 (Progress). Let is a well-typed expression such 휋, ∅ ⊢ 푒 휏 š푣, 휋 ⊢ 푒 ⇓ 푣 휋 ⊢ 푒 ⇓∞ of 휎 is a subset of the set of properties and methods of 휏. that : and , then .

• if 휏 ∈ 퐼푐 and 휎 ∈ 퐼푐 denote classes, then props(휎, 휋) ⊆ Proof (Structure). The proof is by coinduction and case anal- props(휏, 휋) and cmeths(휎, 휋) ⊆ cmeths(휏, 휋); ysis over 푒. □ SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs

Theorem 3.21 (Type Soundness). Let 푒 is a well-typed ex- This program is now well-typed in both Swift and FS but pression such that 휋, ∅ ⊢ 푒 : 휏, then either 휋 ⊢ 푒 ⇓∞ or should fail at runtime with a cast error. At line 12, the method ∃푣, 휋 ⊢ 푒 ⇓ 푣. boxed is invoked with a type () → DerivedList. Hence, Self should refer to DerivedList rather than List. It fol- 4 Reasoning About Swift lows that List(next: self) as! DerivedList must fail, The design of FS allowed us to unveil or rediscover a handful because List is not a subclass of DerivedList. However, as of bugs with the official implementation of Swift’s compiler. of the version 5.1.2, Swift would not detect such a failure and These bugs were discovered on the version 5.1.2. Three of happily cast an instance of List as a DerivedList, thus by- them directly affect the language’s handling of protocol com- passing type safety. Consequently, the program would have position. However, one relates to unbounded methods [37], an undefined behavior upon accessing the property foo on which were supported in an earlier design of FS’s type sys- the value returned from the method call. tem but were eventually dropped for the sake of simplicity, We discovered this bug while stating FS’s progress theo- and another involves generic types [24]. The remainder of rem. In order to review each case of the operational semantics this section focuses on the third one [36]. systematically, we designed a collection of use-cases to test Swift protocols may refer to the variable Self to serve as various derivation scenarios and compare them to actual ex- a placeholder for the types that conform to them. It follows ecutions to validate the result of our semantics. This eventu- that if Self appears in a method requirement, then conform- ally led us to the above program. It turns out that the problem ing types must implement a method that substitutes it with is obvious under FS’s semantics. Since List ⋪ DerivedList, themselves. For instance, consider the following protocol: the rule E-FCast cannot apply and the derivation is stuck at the cast expression. 1 protocol Boxable { 2 func boxed() -> Self 3 } 5 Related Work Boxable defines a single requirement for a method boxed There is a rich literature dedicated to the study of program- that returns instances of the conforming type. Because of ming languages by the means of minimal core calculi, usu- class inheritance, there is one important caveat to consider ally building on top of the 휆-calculus. Unfortunately, in its when conforming to this protocol. Indeed, the following class simplest, purest form, the 휆-calculus is not ideal to reason declaration is not well-typed: about object-oriented abstractions, such as inheritance and

1 class List: Boxable { composition. This has spawned the development of several 2 let next: List? calculi, including highly influential work such as Abadi and 3 func boxed() -> List { List(next: self)} Cardelli’s object calculus [1] and Featherweight Java [23]. 4 } This work borrows heavily from the latter. FJ is a popular lan- guage calculus that aims to provide a sound base for studying While List satisfies Boxable’s requirements, a subclass will extensions to the Java language. Just as FS, it discards most () → not. It will inherit a method boxed with a type List, of Java’s features to focus on a minimal functional subset which does not match its corresponding requirement. The akin to the 휆-calculus. FS differs from FJ in three significant solution is to substitute List with Self so that the method ways. The first obviously relates to protocols, which addan declaration refers to the type of the subclass. Unfortunately, extra dimension to method lookup and type polymorphism. this introduces another problem, as the type of the expression Nonetheless, intuitions about substitution lemmas remain List(next: self) is not compatible with Self. A simple identical. The second difference is that methods in FS are workaround is to force cast the expression: first-class citizens. As such, they may be passed as arguments 1 class List: Boxable { or returned from a function, whereas Featherweight Java 2 let next: List? is a first-order calculus. This slightly complicates the typ- 3 func boxed() -> Self { ing rules and operational semantics related to method calls, 4 List(next: self) as! Self since we cannot assume that 푒 is necessarily an expression 5 } of the form 푒0.푚 in a method call 푒(푒1, . . . , 푒푛). Lastly, FS is 6 } formalized in terms of a “big-step” operational semantics, 7 whereas FJ is formulated using “small-step” semantics. This 8 class DerivedList: List { provides the calculus with a simpler model to express com- 9 let foo: String plex features such as concurrency and exceptions, although 10 } these shortcomings can be tackled by expressing properties 11 on derivation at a meta-level [35]. On the other hand, this 12 print(DerivedList(foo:"bar", next: nil) introduces inconsistencies in the derivation of expressions 13 .boxed().foo) whose evaluation order has to be taken into account. For Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA instance, a special rule has to be defined to state the progress We have discussed how FS served us to reason about theorem with respect to failed cast expressions. Swift’s semantics, which eventually led us to the discovery There exist a number of theoretical work aimed at for- of a few bugs. This convinces us of the necessity to provide malizing protocol-oriented approaches. Traits, from which language users and developers alike with a suitable formal Swift protocols directly derive, are introduced in [39] for framework to generalize assumptions and envision how new an untyped calculus [19]. The first attempt to type-check ideas may interact with existing features. The entry barrier to them statically is proposed in [20]. While their language new, modern programming languages is constantly pushed offers more features than FS, including for instance property higher, as elaborate typing mechanisms make their way into updates (i.e. assignments), composition is only supported mainstream languages. Therefore, it is paramount that these for disjoint traits (i.e. traits without any common methods), be accompanied by rigorous definitions. and support for casting is limited. This latter limitation is This work prompts a number of exciting perspectives for addressed in [40]. Another paper, more closely related to future developments: this work, studies traits as an extension of FJ called Feath- • Generic types contribute significantly to the power of erTrait [28]. While FS only relies on overriding to disam- Swift’s type system, in particular when used in concert biguate overlapping default implementations, FeatherTrait with protocols, and would therefore constitute a wel- also formalizes aliasing and exclusion as composition mech- comed extension of our work. Although the generic anisms [33]. However, traits must be type-checked every extension of FJ [23] is an obvious starting point, one time they are imported into a class, whereas protocol type- challenge is to provide a support for Swift’s bounded checking only occurs once in FS, promoting modularity. This polymorphism [11], whereas most approaches are re- limitation is later addressed in [27] by treating trait compo- stricted to parametric polymorphism. Fortunately, the sitions as interfaces. FS adopts a similar approach, defining more recent formalization of Go [22] provides promis- type coercion over class inheritance and protocol composi- ing insights to tackle this issue. tion. More recent work on calculi with traits focus on state • Another natural extension would relate to the support (e.g. [6, 16]) and behavioral properties (e.g. [3, 17]). of assignments. Once again, a number of extensions The POP discipline can be adopted in a variety of program- to Featherweight Java have already been proposed ming languages, including Scala, that shares a number of (e.g. [8, 30]). Here, the challenge is to properly repro- similarities with Swift with respect to its features and design duce Swift’s distinction between value and reference choices. A formalization of Scala’s type system is presented types [35]. A promising lead in that direction would be in the form of a core calculus, that includes traits [15]. The to adopt a similar approach as Giannini’s pure impera- model features a more complex lookup mechanism than FS tive calculus [21], that proposes to represent aliasing to accommodate the richer, more expressive set of type con- directly at the syntactic level. structions supported by the Scala language. Typescript and • A third axis relates to concurrency. Although Swift’s Go are two modern languages that offer a different take on current concurrency model is based on a traditional POP, using structural typing as a mechanism for retroactive multithreaded approach (for which FJ extensions have modeling. This contrasts with FS, which requires protocol already been proposed [12, 34]), future implementa- conformance to be explicitly stated in type declarations or tions will feature actors on the top of coroutines [25]. extensions thereof. Both TypeScript and Go have been for- Hence, a formal framework to reason about such ap- malized in the form of core language calculi [7, 22]. proaches in the context of Swift’s type system would be of great interest. There exist multiple language 6 Conclusion and Future Directions calculi from which we can draw inspiration in that front [5, 18]. We have presented Featherweight Swift, a core calculus to • Some of the features that we have dismissed can be understand and reason about Swift’s type system. Our ap- easily encoded on top of FS, but a formalization of proach mimics that of Featherweight Java [23]. FS drops these encodings has yet to be provided to validate their all non-essential features and focuses only on the funda- soundness. This would let us study a larger subset of mental concepts that characterize Swift’s type system. Our Swift, for instance, to reason about observers, lazy, and language comes with classes and protocol inheritance, sup- computed properties. ports retroactive modeling, and reproduces Swift’s overrid- ing mechanisms. On the other hand, it discards local and global variables, exceptions, concurrency and assignment. Acknowledgments As a result, its syntax and semantics can be defined concisely, The authors would like to thank the members of the Swift in a style reminiscent of the 휆-calculus, and highlight Swift’s forums community for their precious help in the understand- type coercion and method lookup mechanism clearly and ing of some of the most intricate edge cases of Swift’s type unambiguously. system, and for their feedback on early drafts of this paper. SLE ’20, November 16–17, 2020, Virtual, USA Dimitri Racordon and Didier Buchs

References [15] Vincent Cremet, François Garillot, Sergueï Lenglet, and Martin Oder- [1] Martín Abadi and Luca Cardelli. 1995. A Theory of Primitive Objects: sky. 2006. A Core Calculus for Scala Type Checking. In Mathemat- Second-Order Systems. Science of 25, 2-3 ical Foundations of Computer Science 2006, 31st International Sympo- (1995), 81–116. https://doi.org/10.1016/0167-6423(95)00010-0 sium, MFCS 2006, Stará Lesná, Slovakia, August 28-September 1, 2006, [2] Martín Abadi and Luca Cardelli. 1996. A Theory of Objects. Springer, Proceedings (Lecture Notes in Computer Science, Vol. 4162), Rastislav Berlin. https://doi.org/10.1007/978-1-4419-8598-9 Kralovic and Pawel Urzyczyn (Eds.). Springer, Berlin, 1–23. https: [3] Reza Ahmadi, K. Rustan M. Leino, and Jyrki Nummenmaa. 2015. Au- //doi.org/10.1007/11821069_1 tomatic verification of Dafny programs with traits. In Proceedings of [16] Tom Van Cutsem, Alexandre Bergel, Stéphane Ducasse, and Wolf- the 17th Workshop on Formal Techniques for Java-like Programs, FTfJP gang De Meuter. 2009. Adding State and Visibility Control to Traits 2015, Prague, Czech Republic, July 7, 2015, Rosemary Monahan (Ed.). Using Lexical Nesting. In ECOOP 2009 - Object-Oriented Programming, ACM, New York, 4:1–4:5. https://doi.org/10.1145/2786536.2786542 23rd European Conference, Genoa, Italy, July 6-10, 2009. Proceedings [4] Gerald Aigner and Urs Hölzle. 1996. Eliminating Virtual Function Calls (Lecture Notes in Computer Science, Vol. 5653), Sophia Drossopoulou in C++ Programs. In ECOOP’96 - Object-Oriented Programming, 10th (Ed.). Springer, Berlin, 220–243. https://doi.org/10.1007/978-3-642- European Conference, Linz, Austria, July 8-12, 1996, Proceedings (Lecture 03013-0_11 Notes in Computer Science, Vol. 1098), Pierre Cointe (Ed.). Springer, [17] Ferruccio Damiani, Johan Dovland, Einar Broch Johnsen, and Ina Berlin, 142–166. https://doi.org/10.1007/BFb0053060 Schaefer. 2014. Verifying traits: an incremental proof system for fine- [5] Konrad Anton and Peter Thiemann. 2010. Typing Coroutines. In grained reuse. Formal Asp. Comput. 26, 4 (2014), 761–793. https: Trends in Functional Programming - 11th International Symposium, //doi.org/10.1007/s00165-013-0278-3 TFP 2010, Norman, OK, USA, May 17-19, 2010. Revised Selected Papers [18] Ana Lúcia de Moura and Roberto Ierusalimschy. 2009. Revisiting (Lecture Notes in Computer Science, Vol. 6546), Rex L. Page, Zoltán coroutines. ACM Transactions on Programming Languages and Systems Horváth, and Viktória Zsók (Eds.). Springer, Berlin, 16–30. https: 31, 2 (2009), 6:1–6:31. https://doi.org/10.1145/1462166.1462167 //doi.org/10.1007/978-3-642-22941-1_2 [19] Stéphane Ducasse, Oscar Nierstrasz, Nathanael Schärli, Roel Wuyts, [6] Alexandre Bergel, Stéphane Ducasse, Oscar Nierstrasz, and Roel Wuyts. and Andrew P. Black. 2006. Traits: A mechanism for fine-grained 2008. Stateful traits and their formalization. Computer Languages, reuse. ACM Transactions on Programming Languages and Systems 28, Systems and Structures 34, 2-3 (2008), 83–108. https://doi.org/10.1016/ 2 (2006), 331–388. https://doi.org/10.1145/1119479.1119483 j.cl.2007.05.003 [20] Kathleen Fisher and John Reppy. 2003. Statically Typed Traits. Techni- [7] Gavin M. Bierman, Martín Abadi, and Mads Torgersen. 2014. Under- cal Report. AT&T Labs. standing TypeScript. In ECOOP 2014 - Object-Oriented Programming - [21] Paola Giannini, Marco Servetto, and Elena Zucca. 2018. A Syntactic 28th European Conference, Uppsala, Sweden, July 28 - August 1, 2014. Model of Mutation and Aliasing, In Proceedings of the 12th Workshop Proceedings (Lecture Notes in Computer Science, Vol. 8586), Richard E. on Developments in Computational Models and 9th Workshop on Jones (Ed.). Springer, Berlin, 257–281. https://doi.org/10.1007/978-3- Intersection Types and Related Systems, DCM/ITRS 2018, Oxford, UK, 662-44202-9_11 8th July 2018, Michele Pagani and Sandra Alves (Eds.). Electronic [8] Gavin M. Bierman, Matthew J. Parkinson, and Andrew M. Pitts. 2003. Proceedings in Theoretical Computer Science 293, 39–55. https://doi. MJ: An imperative core calculus for Java and Java with effects. Technical org/10.4204/EPTCS.293.4 Report. University of Cambridge, Computer Laboratory. [22] Robert Griesemer, Raymond Hu, Wen Kokke, Julien Lange, Ian Lance [9] Gilad Bracha and William R. Cook. 1990. Mixin-based Inheritance. In Taylor, Bernardo Toninho, Philip Wadler, and Nobuko Yoshida. 2020. Conference on Object-Oriented Programming Systems, Languages, and Featherweight Go. CoRR abs/2005.11710 (2020). arXiv:2005.11710 Applications / European Conference on Object-Oriented Programming https://arxiv.org/abs/2005.11710 (OOPSLA/ECOOP), Ottawa, Canada, October 21-25, 1990, Proceedings, [23] Atsushi Igarashi, Benjamin C. Pierce, and Philip Wadler. 2001. Feath- Akinori Yonezawa (Ed.). ACM, New York, 303–311. https://doi.org/10. erweight Java: a minimal core calculus for Java and GJ. ACM Trans- 1145/97945.97982 actions on Programming Languages and Systems 23, 3 (2001), 396–450. [10] Kim B. Bruce, Luca Cardelli, Giuseppe Castagna, Jonathan Eifrig, https://doi.org/10.1145/503502.503505 Scott F. Smith, Valery Trifonov, Gary T. Leavens, and Benjamin C. [24] Hamish Knight. 2020. The dynamic nature of a protocol’s Self type Pierce. 1995. On Binary Methods. TAPOS 1, 3 (1995), 221–242. isn’t checked when equated with another associated type. https:// [11] Luca Cardelli and Peter Wegner. 1985. On Understanding Types, Data bugs.swift.org/browse/SR-10713. 2020 (Accessed on July 22, 2020). Abstraction, and Polymorphism. Comput. Surveys 17, 4 (1985), 471–522. [25] Chris Lattner. 2020. Swift Concurrency Manifesto. https://gist.github. https://doi.org/10.1145/6041.6042 com/lattner/31ed37682ef1576b16bca1432ea9f782. 2020 (Accessed on [12] Elias Castegren and Tobias Wrigstad. 2018. OOlong: an extensible July 22, 2020). concurrent object calculus. In Proceedings of the 33rd Annual ACM [26] Xavier Leroy and Hervé Grall. 2009. Coinductive big-step operational Symposium on Applied Computing, SAC 2018, Pau, France, April 09-13, semantics. Information and Computation 207, 2 (2009), 284–304. https: 2018. ACM, New York, 1022–1029. https://doi.org/10.1145/3167132. //doi.org/10.1016/j.ic.2007.12.004 3167243 [27] Luigi Liquori and Arnaud Spiwack. 2008. Extending FeatherTrait [13] Curtis Clifton, Gary T. Leavens, Craig Chambers, and Todd D. Millstein. Java with Interfaces. Theor. Comput. Sci. 398, 1-3 (2008), 243–260. 2000. MultiJava: modular open classes and symmetric multiple dispatch https://doi.org/10.1016/j.tcs.2008.01.051 for Java. In Proceedings of the 2000 ACM SIGPLAN Conference on Object- [28] Luigi Liquori and Arnaud Spiwack. 2008. FeatherTrait: A modest Oriented Programming Systems, Languages & Applications (OOPSLA extension of Featherweight Java. ACM Transactions on Programming 2000), Minneapolis, Minnesota, USA, October 15-19, 2000, Mary Beth Languages and Systems 30, 2 (2008), 11:1–11:32. https://doi.org/10. Rosson and Doug Lea (Eds.). ACM, New York, 130–145. https://doi. 1145/1330017.1330022 org/10.1145/353171.353181 [29] Barbara Liskov and Jeannette M. Wing. 1994. A Behavioral Notion of [14] Karl Crary, Stephanie Weirich, and J. Gregory Morrisett. 2002. In- Subtyping. ACM Transactions on Programming Languages and Systems tensional polymorphism in type-erasure semantics. Journal of Func- 16, 6 (1994), 1811–1841. https://doi.org/10.1145/197320.197383 tional Programming 12, 6 (2002), 567–600. https://doi.org/10.1017/ [30] Julian Mackay, Hannes Mehnert, Alex Potanin, Lindsay Groves, and S0956796801004282 Nicholas Robert Cameron. 2012. Encoding Featherweight Java with Featherweight Swift: A Core Calculus for Swift’s Type System SLE ’20, November 16–17, 2020, Virtual, USA

assignment and immutability using the Coq proof assistant. In Pro- (Accessed on July 22, 2020). ceedings of the 14th Workshop on Formal Techniques for Java-like Pro- [38] Aminata Sabane, Yann-Gaël Guéhéneuc, Venera Arnaoudova, and Giu- grams, FTfJP 2012, Beijing, China, June 12, 2012. ACM, New York, 11–19. liano Antoniol. 2017. Fragile base-class problem, problem? Empirical https://doi.org/10.1145/2318202.2318206 Software Engineering 22, 5 (2017), 2612–2657. https://doi.org/10.1007/ [31] John C. Mitchell and Gordon D. Plotkin. 1988. Abstract Types Have s10664-016-9448-2 Existential Type. ACM Transactions on Programming Languages and [39] Nathanael Schärli, Stéphane Ducasse, Oscar Nierstrasz, and Andrew P. Systems 10, 3 (1988), 470–502. https://doi.org/10.1145/44501.45065 Black. 2003. Traits: Composable Units of Behaviour. In ECOOP 2003 - [32] Dmitri Nesteruk. 2018. Maybe Monad. Apress, Berkeley, CA, 305–308. Object-Oriented Programming, 17th European Conference, Darmstadt, https://doi.org/10.1007/978-1-4842-3603-1_25 Germany, July 21-25, 2003, Proceedings. Springer, Berlin, 248–274. https: [33] Oscar Nierstrasz, Stéphane Ducasse, and Nathanael Schärli. 2006. //doi.org/10.1007/978-3-540-45070-2_12 Flattening Traits. Journal of Object Technology 5, 4 (2006), 129–148. [40] Charles Smith and Sophia Drossopoulou. 2005. Chai: Traits for Java- https://doi.org/10.5381/jot.2006.5.4.a4 Like Languages. In ECOOP 2005 - Object-Oriented Programming, 19th [34] Johan Östlund and Tobias Wrigstad. 2010. Welterweight Java. In European Conference, Glasgow, UK, July 25-29, 2005, Proceedings (Lec- Objects, Models, Components, Patterns, 48th International Conference, ture Notes in Computer Science, Vol. 3586), Andrew P. Black (Ed.). TOOLS 2010, Málaga, Spain, June 28 - July 2, 2010. Proceedings. Springer, Springer, Berlin, 453–478. https://doi.org/10.1007/11531142_20 Berlin, 97–116. https://doi.org/10.1007/978-3-642-13953-6_6 [41] Stefan Wehr and Peter Thiemann. 2011. JavaGI: The Interaction of [35] Dimitri Racordon. 2019. Revisiting Memory Assignment Semantics in Type Classes with Interfaces and Inheritance. ACM Transactions on Imperative Programming Languages. Ph.D. Dissertation. University of Programming Languages and Systems 33, 4 (2011), 12:1–12:83. https: Geneva, Geneva, Switzerland. //doi.org/10.1145/1985342.1985343 [36] Dimitri Racordon. 2020. Bad downcast to Self not caught at runtime. [42] Andrew K. Wright and Matthias Felleisen. 1994. A Syntactic Approach https://bugs.swift.org/browse/SR-11818. 2020 (Accessed on July 22, to Type Soundness. Information and Computation 115, 1 (1994), 38–94. 2020). https://doi.org/10.1006/inco.1994.1093 [37] Dimitri Racordon. 2020. Crash when attempting to assign an unbound method from a protocol. https://bugs.swift.org/browse/SR-11769. 2020