Verifying traits: an incremental proof system for fine-grained reuse

Traits have been proposed as a more flexible mechanism than class inheritance for structuring code in object-oriented programming, to achieve fine-grained code reuse. A trait originally developed for one purpose can be adapted and reused in a completely different context. Formalizations of traits have been extensively studied, and implementations of traits have started to appear in programming languages. So far, work on formally establishing properties of trait-based programs has mostly concentrated on type systems. This paper presents the first deductive proof system for a trait-based object-oriented language. If a specification of a trait can be given a priori, covering all actual usage of that trait, our proof system is modular as each trait is analyzed only once. However, imposing such a restriction may in many cases unnecessarily limit traits as a mechanism for flexible code reuse. In order to reflect the flexible reuse potential of traits, our proof system additionally allows new specifications to be added to a trait in an incremental way which does not violate established proofs. We formalize and show the soundness of the proof system.


Introduction
In object-oriented languages with class inheritance, classes traditionally have three competing roles as generators of objects, as types for objects, and as units of reuse. In contrast, traits are pure units of behavior, designed for flexible, fine-grained reuse [SDNB03, DNS + 06]. A trait contains a set of methods which is completely independent from any class hierarchy. Thus, the common methods of a set of classes can be factored into a trait. Traits can be composed in an arbitrary order. The resulting composite unit (which can be a class or another trait) has complete control over the conflicts which may arise in the composition, and must solve these conflicts explicitly. A trait which was developed for a particular purpose may later be adapted and reused in a completely different context. This way, traits achieve a very attractive level of code reuse, but this flexibility can lead to potentially undesired or conflicting program behavior.
Since their formulation in SMALLTALK-like languages [SDNB03, DNS + 06, BDNW08, BDN + 09], various formulations of traits have been studied for inheritance-based JAVA-like languages (e.g., [SD05,NDS06,RT07,BDG07,BDG08,LS08b,LS08a,BDSS10,BDSS13]). The recent programming language FORTRESS [SAC + 11] (which has no class-based inheritance) has a trait construct, while the 'trait' construct of SCALA [OSV10] is a form of mixin, i.e., a subclass parametrized over its superclass (e.g., [BC90,LM96,FKF98,ALZ03]). Research on ensuring properties of trait-based programs has so far mostly considered type systems (e.g., [RT06, SD05, RT07, BDG08, LS08a, BCD12, BDD + 10, BDGS13]). These approaches establish that the composed program is type correct; i.e., all required fields and methods are present with the appropriate types. This paper presents a deductive proof system for verifying behavioral properties of trait-based programs. Flexible, fine-grained code reuse motivates the development of traits as a mechanism for code structuring, but this flexibility poses challenges when developing a corresponding proof system: a high degree of code reuse in a code structuring mechanism typically limits the degree of reasoning reuse which can be supported by the proof system. Ideally, when traits are composed into a class, the trait specifications should already provide enough information to ensure that the interface contracts of that class hold. This scenario would result in a purely compositional proof system in which the actual usage of a trait always corresponds to its originally intended usage, as captured by its original specification. These specifications can be established by modular reasoning; i.e., it is sufficient to analyze each trait once during the verification process. In practice, a priori imposing a fixed specification on a trait may overly restrict the flexibility of code reuse in that trait, which goes against the original motivation for traits.
The challenge in developing a deductive proof system for trait-based programs is to support the flexibility offered by traits as a code reuse mechanism, while providing an incremental and compositional reasoning system. Without restricting the flexibility of traits as a code reuse mechanism, a trait cannot be fully verified independently of its context of composition. In order to align our proof system with this flexibility, traits will be associated with sets of possible specifications, and the applicable specifications of a trait depend on its context of composition. By incremental reasoning, new specifications may be added incrementally to a trait without violating previous specifications and proofs. When traits are composed, the specifications of the composed traits are selected from the compatible specifications of the constituent traits. Hence, our proof system subsumes modularity and supports modular reasoning for traits when applicable, but extends this modularity to incremental reasoning when required for flexible trait reuse. In particular, the incremental approach supports a gradual extension of existing trait libraries with specifications, driven by the verification of programs using the library.
In order to focus the paper on the particular challenges proposed by trait-based programs, the proof system is presented for a kernel of TRAITRECORDJ [BDSS13,Tra11], a trait-based JAVA-like language with a prototype implementation. The proof system presented in this paper can be used to guarantee that programs obtained through the flexible adaptation and composition of traits satisfy critical requirements, by reasoning modularly and incrementally about traits, trait adaptation, and composition. The analysis of trait-based programs is formalized as an inference system which tracks specification sets for traits, when traits are modified and composed. This inference system adapts previous work on lazy behavioral subtyping [DJOS10], which developed an incremental inference system for late bound method calls by separating the required and provided behavior of methods, to trait modification and composition. The inference system presented in this paper does not depend on a particular program logic. For simplicity, we use a Hoare-style notation to specify the pre-and postconditions of method definitions in terms of proof outlines and do not consider, e.g., class or trait invariants. The main approach of our proof system has previously been presented in a short paper at FTfJP 2011 [DDJS11]. This paper extends [DDJS11] with more examples and explanations, details of the formalization, and the proofs of the main results. As far as we know, no other deductive proof system for trait-based languages has been proposed so far.
The paper is structured as follows. Section 2 gives a high-level introduction to our approach to verifying traitbased programs as an incremental reasoning process. Section 3 introduces the kernel trait language used in this paper and Section 4 presents a specification notation for traits. Sections 5 and 6 introduce the two aspects of the proposed proof system for the considered kernel trait language. Section 5 discusses how the proof system is used to verify basic and composed trait expressions and Section 6 explains how to verify interface contracts for classes. The formal inference system for program analysis is defined in Section 7, which also shows soundness for the proof system. Section 8 illustrates by example how the proof system may be used. Related work is discussed in Section 9. Section 10 concludes the paper and discusses future work. The paper includes three appendixes. Appendix A contains technical definitions omitted in the main paper, Appendix B contains the proofs of the soundness theorem and Appendix C details the verification of the example from Section 8.

Verifying Trait-based Programs as an Incremental Reasoning Process
The main goal of the verification process for trait-based programs is to show that the classes that are built from the traits implement the contracts of their declared interfaces. This section gives an informal introduction to this verification process, which consists of two parts: trait analysis and class analysis. Section 7 shows that the overall verification process meets its goal through the soundness of the formalized proof system (Theorem 7.4). Figure 1 illustrates the envisaged workflow for verifying trait-based programs using our verification process. We assume given a library of traits, annotated with specifications (possibly without any non-trivial specifications). These trait specifications are stored in the trait environment. The specifications of a trait contain a pre-/post-condition pair for each method, denoting the method's guarantee. This guarantee holds if the other methods called by this method satisfy certain properties which are contained as requirements in the method specification. While requirements to external calls can be checked via the behavioral interfaces, the guarantees of internal calls depend on how the traits are assembled into classes; internal calls are checked with respect to the class environment. During the trait analysis, the specifications of methods in composed trait expressions are derived from the specifications of methods in the basic traits, depending on trait modifiers and composition. The specifications of the methods in the basic traits have to be verified by a suitable proof system before they are stored in the trait environment during the trait analysis. In this setting, the trait environment plays the role of a cache of already established specifications that can be reused if applicable during the analysis of classes. For a trait library, the trait environment can be modularly reused and incrementally extended during the analysis of different programs using the library.
During the class analysis, the verification of a program comprising a set of classes built from traits is driven by the external requirements to the classes of the program. These external requirements are specified in the behavioral interfaces which are implemented by the classes of the program. The external requirements to the methods of a class are decomposed into requirements on methods in trait expressions used to build the class. The class environment stores the information about the method specifications used to verify the trait expressions in order to retrieve those when verifying the requirements of other methods. When an external requirement is imposed on a method in a trait expression during the class analysis, there are three cases: 1. Modular verification: The specifications already contained in the trait environment suffice to prove the external requirements imposed on the method. We obtain specification reuse by simply showing that the specifications stored in the trait environment imply the external requirement. 2. Incremental verification: The specifications already contained in the trait environment do not suffice to prove the external requirements. The user can add new specifications to the traits, which need to be verified. This verification triggers new trait analysis operations in which external calls are verified based on behavioral interfaces and internal calls based on methods on other traits. During this verification process, we can return to the modular case in which specifications follow from previous specifications or remain in the incremental case which can repeatedly trigger new trait analysis operations until the analysis is complete. 3. Non-verifiable case: The verification process for the program fails if we cannot find provable specifications to be added to the trait environment which resolve the external requirements on the classes.
The approach allows program verification to interact with a trait library without assuming that the library already contains specifications: When verifying the first program built from a set of traits, we can start with an empty trait environment. The verification process will then enter the incremental case and derive appropriate annotations for the methods as required by the program and store them in the trait environment. When another program is built by reusing already verified traits, we can have the modular case such that we are able to reuse the previously established specifications or again enter the incremental case and derive new specifications. In this way, while verifying a set of programs, we stepwise obtain all necessary specifications for the traits that are contained. In practice, we expect that programs will often use a trait in the same way so the potential for specification reuse is good. However, the proposed approach also caters for programs that use some traits in innovative ways, supporting fine-grained specification reuse.

A Kernel Language for Trait-Based Programs
For the purposes of this paper we consider a kernel of the trait-based programming language TRAITRECORDJ [BDSS13,Tra11] which highlights the specific features of trait-based programming from a reasoning perspective. In particular, TRAITRECORDJ completely separates the three traditional roles of classes as types, units of code reuse, and object generators. Interfaces and primitive types are the only source language types; fields and methods are typed by source language types, and subtyping reflects the extends-relation in interface declarations. Traits only play the role of units of code reuse and are not types. Class-based inheritance is not present, so classes only play the role of object generators.
A trait in TRAITRECORDJ consists of provided methods, which are the methods defined in the trait; required methods, which parametrize the behavior of auxiliary methods assumed to be available in a class using the trait; and required fields, which are similarly assumed to be available in a class using the trait. The required fields of a trait can be directly accessed in the body of the provided methods of the trait, and the required methods can be called internally in the trait's provided methods. Traits are building blocks which can be used to compose classes and other traits by means of a trait summation operation and a suite of trait alteration operations. Since traits do not introduce any state, a class assembled from traits has to provide the required fields of its constituent traits. The kernel language represents a "normal form" syntax which simplifies the analysis proposed in this paper, since it ensures that trait summation happens as late as possible in a trait composition.

Kernel Language Syntax
The syntax of the kernel language is given in Figure 2. A program P consists of (lists of) interface declarations ID, trait declarations TD, and class declarations CD. Following [IPW01] we use the overline notation for (possibly empty) sequences. In TRAITRECORDJ, interface declarations ID, method headers H, field declarations F, and method declarations M have a similar syntax as in JAVA (but ignoring, e.g., visibility modifiers and exceptions). For simplicity, in the kernel language the syntax of methods is restricted. For instance, a method may only contain a single return statement which must be the last statement in the body of the method, and method parameters are not assignable. These language features are well-understood from the literature (e.g., [Hoa69,Apt81,AdBO09]) and do not impose any new difficulties for our proof system. In the sequel, we will use the notation body(M) to denote the body of a method declaration M. We syntactically distinguish internal method calls m(e) from external method calls v.m(e) (where the variable v is typed by an interface).
A trait declaration TD binds a trait name T to a trait expression. Traits are either basic or composed. A basic trait binds a basic trait name Tb to a basic trait expression BTE, whereas a composed trait binds a composed trait name Tc to a composed trait expression CTE. Only basic traits can be adapted by means of alteration operations, which explains the normal form restriction of the kernel language, and assembled into composed traits.
A basic trait expression BTE, written { F; H; M }, provides the methods M and declares the types of the required fields F and methods H (which can be directly accessed in the bodies of the methods M). A trait alteration expression TAE applies trait alteration operations ao to a basic trait Tb. The operation exclude forms a new trait by removing a method from an existing trait. The operation aliasAs forms a new trait by giving a new name to an existing method; in particular, when a recursive method is aliased, its recursive invocation refers to the original method. The operation P ::= ID TD CD program  Kernel language syntax. The following naming convention is used in the syntax: I ∈ interface names; Tb ∈ basic trait names; Tc ∈ composed trait names; C ∈ Cid (the class names); f ∈ field names; m ∈ Mid (the method names); x ∈ method parameter or local variable names. We further denote by Mtd the set of method declarations and by Label the set of field and method names.
renameTo creates a new trait by renaming all occurrences of the name of a required field name or of a required or provided method name from an existing trait. A composed trait expression CTE is either a trait alteration expression TAE or the sum of two composed trait expressions. The symmetric sum + merges two traits to form a new trait and requires that the summed traits are disjoint; i.e., the summed traits cannot provide identically named methods but they may require identically named (and typed) fields or methods. Classes in TRAITRECORDJ are assembled from a trait expression by providing the fields required by that trait expression. Thus, a class declaration CD binds a class name C to a set of interfaces I, which specify the possible types for an instance of the class, fields F, and a trait expression CTE. All fields are private. For simplicity, class constructors are omitted in the paper; each class C is assumed to have an implicit constructor that behaves like the JAVA constructor C(S x) { f = x }, where S f are all the fields of the class.
Example 3.1. As a running example in this paper, we consider the implementation of a bank account. The following trait TAcc provides the basic operations for inserting and withdrawing money: The public methods of an object are those listed in the interfaces implemented by its class; the other methods and fields are private to the object. For instance, the only public members of classes CAcc and CFeeAcc are the methods deposit and withdraw.

Kernel Language Semantics
The semantics of a class composed from traits is defined through the flattening principle [DNS + 06] (see also [NDS06,LSZ09]), which states that the semantics of a method introduced in a class through a trait should be identical to the semantics of the same method defined directly within a class. A flattening function defines the semantics of TRAITRECORDJ by translating TRAITRECORDJ class declarations to JAVA class declarations, and a trait expression to a sequence of method declarations. TRAITRECORDJ interfaces are literally JAVA interfaces and need no translation.
Let a TRAITRECORDJ program be represented by an interface table IT, a trait table TT, and a class table CT, which map interface, trait, and class names to interface, trait, and class declarations, respectively. For simplicity, we assume fixed, global tables IT, TT, and CT. The flattening function · , defined in Figure 3, maps a TRAITRECORDJ class declaration to a JAVA class declaration, and a trait expression to a sequence of method declarations. (The implicit class constructor of TRAITRECORDJ is unaltered by the flattening function, and omitted in Figure 3 rep( TAE , m, m ) Example 3.2. The flattening of the class CFeeAcc, which is introduced in Example 3.1 above, is as follows (the implicit TRAITRECORDJ constructor is omitted).  int factorial(int n) { int r = -1; if (n >= 0) r = fAux(n); return r; } int fAux(int n) { int r = 1; if (n >= 2) r = n * fAux(n-1); return r; } int fact(int n) { int r = 1; if (n >= 2) r = n * fAux(n-1); return r; } while the flattening of TFactorial[fAux renameTo fact] is the following sequence of two methods: int factorial(int n) { int r = -1; if (n >= 0) r = fact(n); return r; } int fact(int n) { int r = 1; if (n >= 2) r = n * fact(n-1); return r; } The TRAITRECORDJ type system ensures that the flattening of a well-typed TRAITRECORDJ program is a welltyped JAVA program. It has been formalized for FEATHERWEIGHT RECORD-TRAIT JAVA (FRTJ) [BDS10,BDS09], a minimal core calculus for TRAITRECORDJ in the spirit of FEATHERWEIGHT JAVA [IPW01]. A type system for the kernel language considered in this paper would be a straightforward adaptation of the type system for FRTJ; in the sequel, it is assumed that programs are well-typed according to such a type system.

Specifying Trait-Based Programs
This section considers the specification of trait-based programs. The proof system developed in this paper does not depend on a particular program logic. Let PL be a (sound) program logic and let a, p, q range over assertions in the assertion language of PL. For simplicity in the presentation we use Hoare triples {p}s{q} [Hoa69], with a standard partial correctness semantics [Apt81,AdBO09], adapted to the object-oriented setting; in particular, de Boer's technique using sequences in assertions addresses the issue of object creation [dB99]. Thus, the triple {p}s{q} expresses that if s is executed in a state where the precondition p holds and the execution terminates, then the postcondition q holds after s has terminated. Let A PL {p}s{q} denote that {p}s{q} is derivable from a (possibly empty) set of axioms A using the inference rules of PL. An assertion pair (p, q) is a pair of assertions such that p is a precondition and q a postcondition (for some sequence of program statements).
Entailment. The standard rule of consequence in Hoare Logic (e.g., [AdBO09]) is insufficient for dealing with sets of assertion pairs, which we will need to flexibly combine information from assertion pairs. We take a relational approach to entailment, and let q o denote the assertion q in which all occurrences of fields f and method parameters x have been substituted by the corresponding fields f o and local variables x o , respectively, avoiding name capture. The assertion pair (p, q) is understood as an input/output relation ∀z . p ⇒ q o , where the formula q o ensures that the postcondition applies to the values of fields and local variables in the post state, z are the logical variables in p and q, and the universal quantifier defines the scope of the logical variables (for further details on relational assertions, see e.g. [BvW98, HLL + 12]). The standard entailment relation is lifted to assertion pairs and to sets of assertion pairs, as follows [DJOS10]: Definition 4.1 (Entailment). Let (p, q) and (r,t) be assertion pairs and let U and V denote the sets {(p i , q i ) | 1 ≤ i ≤ n} and {(r i ,t i ) | 1 ≤ i ≤ m}. Entailment is defined over assertion pairs and sets of assertion pairs by , where z 1 and z 2 are the logical variables in (p, q) and (r,t), respectively.
The relation U (r,t) corresponds to classic Hoare style reasoning, proving {r}s{t} from {p i }s{q i } for all 1 ≤ i ≤ n, by means of the consequence and conjunction rules [AdBO09]. When proving entailment, program variables (input and output) are implicitly universally quantified. Furthermore, entailment is reflexive and transitive, and V ⊆ U implies U V .
Behavioral Interfaces and Method Contracts. The (external) behavior of a program can be described in terms of behavioral interfaces which extend the interfaces of a program with method contracts. A method contract guarantees that a method has a certain behavior, captured by an assertion pair relating the prestate and the poststate of the method execution. In addition to describing the relation between the values of the method's formal parameters and its returned output value, a method's effect on the state can be described by means of so-called model variables (e.g., [HLL + 12]) in the interface. To avoid representation exposure, a representation function is used to relate the actual fields of a class implementing the interface to the model variables of the interface. Logical variables, which are not model variables, are scoped within an assertion pair so they have the same value in the pre-and postcondition (this scope is formally captured in Definition 4.1 by quantification). In the syntax, an annotated method header extends a method header H as defined in Figure 2 with an assertion pair, and an annotated interface declaration extends an interface declaration ID with contracts for its exported methods. Formally, annotated method headers AH and annotated interface declarations In this assertion language, this denotes the current object, result the current method's return value, v a program variable, z a logical variable, and op an operation on data types. In particular, the equality of two assertions a 1 and a 2 is denoted a 1 == a 2 . We now extend the interfaces IAcc and IFeeAcc of Example 3.1 with contracts as follows: Logical variables are conventionally denoted by subscripts and all formal parameters are read-only. For instance, the initial value of bal is captured by the logical variable b 0 in (bal == b 0 , bal == b 0 + x), and x is the value of the formal parameter.
Specifying Basic Traits. For a basic trait, a guarantee for the behavior of each provided method is given by an assertion pair. Since the guarantee of a provided method m may crucially depend on the behavior of the methods called by m, the guarantee of m has an associated set of requirements on other methods; e.g., the requirement expressed by n : (r,t) is that the method n must guarantee (r,t). The guarantee (p, q) of a method together with an associated set R of such requirements constitute a method specification, denoted (p, q), R . The validity of a specification (p, q), R for a method m can be mechanically checked by providing a proof outline [OG76] for the method body of m. A proof outline typically annotates the method body with information which is difficult to infer but needed for a proof, such as loop invariants and method call annotations. We focus on the latter here, and assume that method calls in a proof outline for the body of m are annotated with the behavioral requirements on auxiliary methods which are needed by m to fulfill the guarantee (p, q). If external calls are checked with respect to their method contracts as given in behavioral interfaces, it is sufficient for the developer to annotate internal calls. Let A trait is designed for flexible reuse. It can be difficult to specify the methods in the trait in a way which covers all possible future usages of the trait. In practice, there may be many possible guarantees for the provided methods of a trait, depending on the context of use. These guarantees can have different associated proof outlines, which give rise to different requirements on the called methods. Thus, a provided method in a trait can have several specifications reflecting different usage contexts. The initial specifications reflect the originally intended usage of the method; further specifications may be added later if new ways of using the trait are discovered. If the initial specification happens to be sufficient for the later actual usage, this is the special case which coincides with modular specification. In general, an annotated method associates a list of method specifications to a method declaration and an annotated basic trait has annotated method declarations for its provided methods. Similarly, an annotated class provides a representation function rp I for each interface I that it implements, which maps model variables f to assertions over the fields of the class. Formally, requirements R, specifications sp, annotated methods AM, annotated basic traits ABT, and annotated classes AC have the syntax  trait TAcc is { // no required fields boolean validate(int a); // required method void update(int y); Trivial specifications are here omitted for brevity; e.g., that bal is not modified by validate. The specifications w1 and w2 are provided under the assumption that the auxiliary calls to update and validate manipulate the fields bal and owner, which are otherwise not required by the trait. However, they are required by the trait TAux. TAux may be given the following specifications, which do not lead to any requirements: trait TAux is { int bal; int owner; // required fields void update(int y) {bal = bal + y;} guar: The rule of consequence in Hoare logic [AdBO09] allows us to infer that if {p}s{q} holds for some statement s and (p, q) (p , q ) then {p }s{q }. However, the order of entailment is reversed for substitutability of assumptions in proof outlines: Given that {p}s 1 ; s 2 ; s 3 {q} holds for statements s 1 , s 2 , and s 3 by assuming {p 1 }s 2 {q 1 }, let (p 2 , q 2 ) be such that (p 2 , q 2 ) (p 1 , q 1 ). Then {p}s 1 ; s 2 ; s 3 {q} must hold by assuming {p 2 }s 2 {q 2 }. This leads to the following observation about substitutability of decorated method calls in proof outlines: Observation 4.5. Let s be a statement, and p, q, p 1 , p 2 , q 1 , q 2 assertions such that (p 2 , q 2 ) (p 1 , q 1 ). If A, n() : This observation motivates how the entailment relation is lifted to method specifications to express that a specification (p 2 , q 2 ), R 2 can be derived from a proof of a specification (p 1 , q 1 ), R 1 .
Proof. Follows from the transitivity of specification entailment.
Assume that the user has supplied (p 2 , q 2 ), R 2 as a specification for some statement s. It follows from Lemma 4.7 that to ensure this specification, we may prove a different specification (p 1 , q 1 ), R 1 with a (possibly) stronger guarantee. Note that the requirement set R 2 may contain requirements that are superfluous in order to derive the proof outline for (p 1 , q 1 ).

Compositional Verification of Traits
The goal of our verification technique is to reason incrementally about trait expressions while verifying trait-based programs. By incremental, we mean that new specifications may be introduced but that old specifications, and consequently old proofs, are never violated. Due to the flexible reuse potential of traits, we do not assume that a fixed specification of a trait, given a priori, covers all potential usages of that trait. This would be a special modular case of our more general incremental approach. Thus, our incremental approach subsumes a modular approach where this is applicable, but it also supports a gradual introduction of specifications in an existing trait library. Instead, traits have a set of possible method specifications for each provided method. This set can be incrementally extended. We devise compositional proof rules that apply to sets of method specifications when traits are composed.
During the verification of trait expressions, a trait environment is constructed to keep track of the specifications for the provided methods of trait expressions. The trait environment formalizes a "specification cache" for a trait library, and stores the currently known specifications for methods in a set of traits expressions. The trait environment supports reasoning reuse for the considered trait library in a modular way, but it may also be extended to support incremental reasoning when the knows specifications are insufficient. The analysis of a program using the traits of the library interacts with the trait environment to verify the program. For the analysis, we assume that the interfaces of a program have been annotated, so every method in an interface has a method contract as defined in Section 4. This allows us to reason compositionally about calls to methods on interface types. In this section, we examine the construction of the trait environment during the analysis of basic traits and composite traits assembled using the trait composition and alteration operations.
Basic Traits. Consider a basic trait T which provides a method m with the method body t and assume an annotated method declaration M sp (p, q), R for m. The correctness of the guarantee (p, q) can be established from the requirement set R either by means of automated techniques or by asking the developer for a proof outline O and letting a verification system verify O PL t : (p, q). For simplicity we assume in the sequel that it is the developer who provides a proof outline O when necessary. In the proof outline, external calls may be analyzed directly, since they are based on the method contracts in the behavioral interface of the callee. This leaves the requirements to internal calls, which are provided as annotations in the proof outline. However, the behavior of these internal calls depends on how a class is finally assembled from trait expressions. Even if the proof outline is valid, it remains to check that the requirements R are correct when the class is assembled. Therefore, the method specification (p, q), R is stored in the trait environment for T. A provided method m may have different guarantees depending on different requirements on its internally called methods. Each of these guarantees is proven using a different proof outline, leading to different specifications for m. Hence, this analysis is repeated for an annotated method AM until the validity of all specifications has been checked.
Trait Modifiers. When a trait alteration expression modifies another trait expression TAE, it gets its own specification stored in the trait environment. This specification is obtained from the specification of TAE and may lead to new proof obligations. Excluding a method from a trait does not generate any proof obligations. The trait environment of the resulting trait expression is obtained from the trait environment of the previous trait expression by removing the method specifications of the removed method. Aliasing does not generate proof obligations. The trait environment for the resulting trait expression is obtained by copying the method specifications of the aliased method. Renaming of methods does not generate proof obligations, but proof obligations for distinct methods may now apply to the same method. The trait environment for the resulting trait expression is obtained by consistently renaming the respective method. Field renaming does not generate proof obligations, but some specifications may have to be discarded in order to maintain soundness. Therefore, the trait environment for the trait resulting from the trait alteration [f renameTo f ] is obtained by distinguishing different cases. If the old field f does not occur in the previous trait expression, the trait environment for the new trait expression is obtained directly from the trait environment of the old trait expression. Otherwise, for each method m, we consider whether the new field f occurs in the original body of m or not. If f occurs in m, the specifications of m are dropped, which can be illustrated by the triple illustrates that field renaming should be used with care in order to avoid unintended name clashes in the program (a more fine-grained analysis of field renaming may be obtained depending on the expressivity of the program logic PL; e.g., [PBC06]).
Example 5.1. Let the trait TAux be as specified in Example 4.4, and consider the rename operation TAux[update renameTo basicUpd]. The implementation of validate is unaltered by the operation, but the update method is renamed, and the specification given in TAux applies to the new method: void basicUpd(int y) {bal = bal + y;} guar: Symmetric Sum of Traits. For a composed trait expression CTE obtained from two trait expressions by symmetric sum, we maintain the distinction that each method specification has particular assumptions on the required methods. Thus, the trait environment of the composed trait expression is the union of the trait environments of the summand trait expressions. In particular, method specifications are kept in the trait environment even if their requirements cannot become satisfied by the implementations found in other trait expressions of the composition. The reason is that the composed trait expression may be the subject to later trait composition operations. Thus, method specifications that were unsatisfiable in the original composition may again become satisfiable. However, if the composed trait expression is used in a class declaration, the analysis of the class ignores method specifications that are unnecessary in order to verify the interface contract of the class, thereby selecting a set of consistent method specifications from the set of all provided method specifications from the constituents of the composed trait expression.

Verifying Trait-Based Programs
For each class, it is necessary to show that every public method exposed through an interface guarantees the contract in that interface. This result should eventually follow from the specification of the methods, as provided by the trait expression. In the case where the trait specifications contain sufficient guarantees for the public methods, this follows directly in a modular way. Otherwise, a new method specification with the additional guarantees may be added to the trait specifications, and method specifications are collected when a class is assembled from the traits by trait composition. For each added method specification, the respective method must be reinspected to verify the new proof outline associated with the new specification. Such proof outlines may lead to new requirements on internally called methods, which again make it necessary to supply new proof outlines for these methods. This procedure repeats for internal calls until the analysis is complete. Note that all proofs which rely on previously established guarantees of the provided method remain valid. Thus, the presented approach is incremental. The class must implement the model variables of the interface by providing a representation function (in the terminology of JML [BCC + 05]); for simplicity in the examples of this paper, the representation function will always just be the identity function and we omit its explicit representation. Thus, in order to implement the interface IAcc, the method withdraw in TAcc must satisfy the following contract given in Example 4.2: ). Since this contract follows by entailment from the guarantees of w1 and w2 in Example 4.4, it suffices to ensure that the requirements of w1 and w2 are satisfied for the implementations found in TAux, which is straightforward. As for CAcc, the representation function here is the identity function, and the contract ( This contract does not follow from the guarantees of w1 and w2, so a new proof outline is needed. It suffices to extend the specifications of withdraw with the following specification, labelled w3: The interface contract follows by entailment from the guarantees w2 and w3. Now, the requirements of these specifications need to be verified. The only non-trivial requirement is the one to update, which can be verified by the following specification in TFee: The requirement of this specification follows from the guarantee of basicUpd as given in Example 5.1. Assume that class CMini is defined by TAcc+TMini where bal is the only declared field. The original specifications w1 and w2 contain the field owner, reflecting that TAcc was originally developed together with TAux, but this field is not present in the current composition. To analyze method withdraw, we may provide the following specification: This specification expresses that any client can make a withdrawal from a CMiniAcc.

PST(PL): A Proof System for Verifying Trait-Based Programs
The verification process for trait-based programs outlined in the previous sections is now formalized as a calculus PST(PL) which is parametric in the underlying program logic PL. The calculus PST(PL) relies on a sound program logic PL and defines inference rules for analyzing trait expressions and classes, given in Sections 7.2 and 7.3 below.
The proof system considers annotated basic traits ABT. For simplicity, we assume that unannotated method declarations in AM have a default guarantee (true,true), with corresponding requirements (true,true) for internal calls.
A program is analyzed in PST(PL) as a sequence of analysis operations concerning the trait and class definitions of the program. These operations manipulate a proof environment which consists of a trait environment and a class environment. For each analyzed trait alteration expression, the trait environment is extended with the trait definition and with the specifications for the methods provided by that trait expression. Thus, if the analysis of a trait expression TAE is initiated in some trait environment T , the successful analysis of TAE will lead to a trait environment T , such that T extends T . In this case we say that T is the trait environment resulting from the analysis. When analyzing classes, the class environment is extended similarly. Traits and classes are analyzed in the context of the trait and class environments which have been obtained from the analysis of previous traits and classes. In this way, the rules of PST(PL) explain how the analysis of language artefacts constructs a sequence of proof environments, starting with empty trait and class environments. This process formalizes the accumulation of specifications for a collection of traits during the analysis of programs using those traits.

Judgments in PST(PL)
Judgments in PST(PL) are of the form C , T P, where C is a class environment for class analysis, T is a trait environment for trait analysis, and P is a sequence of analysis operations. We define the syntax for judgments in PST(PL), including the analysis operations and the proof environment which is manipulated by these operations.

Proof Environments
Class environments are used to accumulate knowledge about classes during the analysis. Class environments, which represent classes by a unique name and a tuple I, CTE, F of type Class, are defined as follows: Definition 7.1 (Class environments). A class environment C consists of two mappings D C and S C , where D C : Cid → Class, and S C : Here, D C contains the definitions of verified classes and S C contains their verified specifications. The main purpose of the class environment is to record the method specifications used to establish the contracts of the implemented interfaces. The function impl : Class → CTE returns the trait expression of a class. Update functions for the class environment C are defined as follows, where sp is a set of method specifications: Trait environments are used to accumulate knowledge about trait expressions during analysis, and are defined as follows: Definition 7.2 (Trait environments). A trait environment T is a mapping from trait alteration expressions to annotated basic traits: T : TAE → ABTE.
Recall that trait alteration expressions TAE are defined by Tb ao; i.e., they consist of a basic trait name followed by a possibly empty sequence of alteration operations. The mapping T takes such a trait alteration expression and returns

Analysis operations
The analysis assumes that basic traits are annotated as explained in Section 4. The syntax for the analysis operations P is given in Figure 5.

Trait Analysis in PST(PL)
The inference rules for trait analysis are given in Figure 6. Traits are analyzed compositionally in the context of the trait environment T . A trait is either an annotated basic trait of the form trait Tb is {F; H; AM} or a composed trait of the form trait Tc is CTE. For an annotated basic trait {F; H; AM} we assume by type safety that F and H contain all fields and method signatures used in the provided methods. Furthermore, we assume for simplicity that F and H are minimal in the sense that they do not contain field and method signatures that are not used in the provided methods. An annotated basic trait trait Tb is {F; H; AM} is analyzed by the rule BASICTRAIT, which extends T with the definition of the trait and generates a verify operation for analyzing the user-given specifications for the provided methods of the trait. The verify operation on a set AM of annotated methods is decomposed by the rules DECOMP1 and DECOMP2, which leads to a verify(Tb, M sp) operation for each specification sp of Min AM. The predicates nonempty(AM i ) and nonempty(sp i ) (for i ∈ {1, 2}) express that decomposition rules only apply to nonempty sequences. The rule ADAPTATION builds specification entailment into the proof system. This rule replaces the userprovided specification by a stronger specification. For a method I m(I x){t} with the specification (p, q), R , the rule VERIFY requires that the user provides a proof outline O for the method body t such that O PL t : (p, q) (for example by the user, as discussed in Section 5). In this case (p, q), reqs(O) is a valid method specification for m, and the annotated method T (Tb)(m) in the trait environment is extended with this specification.
Upon the successful analysis of Tb, each specification is recorded by the trait environment T . Note that when the trait is defined it is not known to which actual implementation an internal call will be bound, since the method binding depends on how the traits are used to form classes. Consequently, the imposed requirements are not verified with regard to any implementation during trait analysis. Instead these requirements are verified as needed when a specification is actually used during the analysis of a class. Composed traits trait Tc is CTE are analyzed by the rule COMPTRAIT. Here CTE is of the form TAE 1 + . . . + TAE n for n ≥ 1, where each TAE i is of the form Tb i ao i . For simplicity, we here assume that all basic traits Tb 1 , . . . , Tb n have been analyzed before the analysis of composite trait expressions. By the rule COMPTRAIT, an operation extend is generated in order to extend the trait environment for each trait alteration expression TAE i in the composition. The composed trait expression is decomposed to a sequence of extend operations by the rule DECOMP3. Rule LOOKUP applies to TAE i if TAE i is already defined in the trait environment. Especially, this rule applies to all basic trait names used in the composition. Otherwise, the analysis depends on the structure of TAE i , and the extend operation is analyzed by either EXTEND or EXTENDREC.
Rule EXTEND is the main rule for extending the trait environment for each TAE i of the form TAE ao. The premise of the rule ensures that the prefix TAE is defined in the trait environment. The trait environment is extended for TAE ao by the update T ⊕(TAE, ao), which modifies a copy of the annotated basic trait bound to TAE depending on the actual alteration operation ao. The definition of this update function is given in Appendix A. For an expression TAE ao where TAE has not already been analyzed (i.e., TAE is not in T ), the rule EXTENDREC recursively ensures that the trait environment is extended for TAE before it is extended for TAE ao. After extending the trait environment for TAE, the rule EXTEND may be applied to extend(TAE ao). Since TAE starts with a basic trait name Tb, the recursion over the structure of TAE ao is guaranteed to terminate. In this manner, properties for each TAE i in the composition are remembered in the trait environment. By the successful analysis of Tc, the mapping T binds TAE i to an annotated basic trait definition containing the methods provided by TAE i with verified specifications. These annotated methods are derived by manipulating those of Tb i according to the modifiers ao i .
A trait alteration expression TAE is introduced into T by rule BASICTRAIT or rule EXTEND. After the initial analysis by one of these rules, the method definitions in TAE are not manipulated, but specifications may be added. (CLASS) C ⊕ (C, I, CTE, rp I , F), T extend(CTE) · C : discharge(contracts(rp I , I)) · P C , T class C implements I by { rp I F; } and CTE · P Fig. 7. The inference rules for class analysis. Here, TAE ∈ CTE denotes that TAE is a syntactical part of CTE, i.e., if CTE is TAE 1 + . . . + TAE n , then TAE = TAE i for some i (1 ≤ i ≤ n).
The inference system for trait analysis ensures that there exists a valid proof outline for each specification recorded by the trait environment. (This is formalized by Lemma B.2 in Appendix B.) Especially, the analysis ensures that each user given specification in a basic trait is valid.

Class Analysis in PST(PL)
We now consider the analysis of a class declaration class C implements I by { rp I F; } and CTE. As for composed traits, the expression CTE is of the form TAE 1 + . . . + TAE n and by type safety we have that each provided method m is defined in exactly one of the summand trait expressions TAE i . In addition to the trait environment T , the class analysis extends a class environment C which contains the definitions and specifications of classes. The analysis of class C is driven by the contracts of its interfaces I. Upon the successful analysis of C, each contract of a provided method m in the interfaces of the class follows by entailment from the guarantees of S C (C, m). If m is provided by TAE i , the interface contracts are ensured by reusing already verified specifications contained in T (TAE i )(m), and by extending this set if needed. Thus, S C (C, m) contains the subset of T (TAE i )(m) that is actually used to verify the current class. In addition, the requirements imposed by the used specifications are analyzed with regard to the implementation to which they bind in C. For a method specification sp = (p, q), R , we define the functions guar : Spec → Guar and req : Spec → Set[Req] where guar(sp) (p, q) and req(sp) R. These functions are straightforwardly lifted to sets of method specifications, returning sets of guarantees and requirements, respectively. Thus, if sp ∈ S C (C, m), then each requirement n : (r, s) ∈ req(sp) follows by entailment from the guarantees of S C (C, n). Let contracts(rp I , I) denote the set of method contracts of I obtained by applying the respective representation functions rp I to the model variables in the assertions of each interface, which are of the form m : (p, q). The analysis of the class C is initiated by the rule CLASS. By this rule, the class environment C is extended by the definition of C, and the analysis operation C : discharge(contracts(rp I , I)) is generated. This operation reflects that the analysis of C is driven by the contracts of the implemented interfaces, in which the model fields of the contracts have been adapted to the class by application of its representation function for each interface, and that these contracts are analyzed in the context of C. The set of method contracts is decomposed by the rule DECOMP4, and each contract m : (p, q) is analyzed either by rule OPENANALYSIS or CLOSEANALYSIS. The rule CLOSEANALYSIS applies to a discharge operation if the requirement follows from earlier verified specifications for the current class. Otherwise, the requirement is opened for analysis at the trait level by rule OPENANALYSIS. This rule selects the conjunct TAE in CTE where m is defined, leading to an operation analyze(TAE, m : (p, q)). This operation is analyzed by rule ANALYZE.
Rule ANALYZE captures modular reasoning in the inference system, reusing previous analysis from the trait environment. This rule applies when the contract can be derived from previously verified method specifications for m in TAE. In that case, the analysis continues with an discharge operation for the requirements of these specifications, which are analyzed in the same manner as the original interface contract. Consequently, each requirement is either discharged by CLOSEANALYSIS, or analyzed using OPENANALYSIS with respect to the actual implementation of the called method in the current trait composition CTE.
The rule INCREMENT captures incremental reasoning in the inference system and allows the user to extend the verified specifications of a trait in the trait environment, incrementally building knowledge about the traits. It needs to be applied if the requirement of an analyze operation does not follow from previously verified specifications of the current trait. The user must suggest the additional specification (p, q), R for the trait, which is analyzed by a verify operation for the current trait. This verify operation is resolved by the inference rules for trait analysis and the trait environment is extended before the class analysis proceeds. To cover the case of self-recursion, the method specification itself is assumed when analyzing the requirements, similar to rule BASICTRAIT above. This captures the standard approach to reasoning about recursive method calls [Hoa71]. An empty set of requirements or contracts is discarded by the rule EMPDISCHARGE, and the successful analysis of class C is completed by the rule EMPCLASS.

Soundness of PST(PL)
When reasoning about a set of mutually recursive methods, the guarantees in the specifications of all methods are assumed to hold in order to verify the body of each method (e.g., [AdBO09]). We now extend this approach to define the consistency of a set of proof outlines for methods in a flattened class with given interfaces. The flattened version of a class that is defined by class C implements I by { rp I , F; } and CTE is given by class C implements I { rp I , F; M } as defined in Section 3.1 (where the annotation with representation functions is unchanged by the flattening). 1. ∀(m : (r, s)) ∈ contracts(rp I , I) . guar(S m ) (r, s) 2. ∀ (p, q), R ∈ S m . ∀(n : (r, s)) ∈ R . guar(S n ) (r, s) The first condition expresses that the interface contracts are satisfied, whereas the second condition expresses that the requirements of all internal calls are satisfied. Previous work [DJOS10] defines a sound calculus for analyzing single inheritance class hierarchies. Given a consistent set of specifications, the analysis of a flattened class succeeds in this calculus. In order to ensure soundness of PST(PL), it thereby suffices to prove that the successful analysis of some class C leads to a consistent set of specifications for the flattened version of C. The proof of this theorem is given in Appendix B.

Example: A Trait-Based Implementation of Bank Accounts
This section illustrates how traits can be used to construct a range of classes implementing behavioral interfaces which specify different bank accounts, and how these classes can be verified by means of the proposed incremental proof system. We start with the trait definitions given in Figure 8, where each trait contains a set of annotated methods. To simplify the presentation, we assume that the language provides the type nat of positive integers. Default specifications, with guarantees (true,true), are omitted. Let us assume that only a few specifications are initially provided in the traits. The incremental aspect of PST(PL) is used to provide additional specifications to the traits when these are required by the class analysis.
The trait TBasicAccount implements basic functionality for bank accounts by the two methods deposit and withdraw; the method deposit increases the balance bal of the account by the parameter value and withdraw decreases the balance of the account by calling an auxiliary method update. The exact definition of update depends on the specific account, so update is a required method in this trait. Additionally, deposit assumes access to a field bal, so bal is also required by the trait. To implement an account, the trait TBasicAccount must be composed with another trait where update is defined, in a class where bal is defined.
The trait TBasicUpd provides a basic implementation of the update method which simply reduces the balance by the argument value. In contrast, the trait TFeeUpd charges a fee for each update, and update is defined by calling an auxiliary, required method bUpdate where the argument is increased by fee. In a similar way, the trait TPosUpd calls an auxiliary, required method bUpdate. However, in this case the required method in TPosUpd is only called if the current balance is greater or equal to the parameter value.
Bank accounts with different behavioral properties may be assembled, depending on how the traits of Figure 8 are combined. Different trait combinations lead to different behaviors for the withdraw method. These bank accounts are first specified in terms of behavioral interfaces and then implemented in classes using different trait combinations. We define an interface hierarchy such that each type of account extends a superinterface IAccount which declares the methods deposit and withdraw, but where withdraw has no behavioral requirement. This interface further specifies the effect of making a deposit as increasing the balance of the bank account by the deposited amount. The subinterfaces vary in the properties they specify for withdraw. In the interface IBasicAccount, withdraw decreases the balance of the bank account by exactly the withdrawn amount; in IFeeAccount the balance is decreased by a fee on withdrawals; in IPosAccount the account cannot be overdrawn; in IPosFeeAccount a fee is charged on withdrawal and the withdrawn amount cannot be larger than the balance on the account; and in IFeePosAccount, a fee is charged on withdrawals and the balance is guaranteed not to be overdrawn. The definitions of these interfaces are given in Figure 9; observe that the method deposit is only specified in IAccount whereas withdraw is given different specifications in the different subinterfaces of IAccount.
The interfaces are implemented by classes, shown in Figure 10, which combine TBasicAccount with other traits in different ways. The update method is renamed in some of the traits such that the call to update in withdraw may lead to a chain of calls to renamed update methods. The class CBasicAccount is defined in terms of the basic update method. The class CFeeAccount combines the basic update method with the one from TFeeUpd, so the balance is reduced by an additional fee for each withdrawal. For comparison, the flattened version of this class is shown in Figure 11. The class CPosAccount is defined in a similar way, but the update is not performed if it would lead to a negative balance. The classes CPosFeeAccount and CFeePosAccount, combine all the traits TFeeUpd, TPosUpd, and TBasicUpd. Here, the names reflect the binding order of a call to update. In CPosFeeAccount, a call to update will bind to the implementation found in TPosUpd and a recursive call to the implementation in TFeeUpd. Thus, in CPosFeeAccount the balance must be positive before the fee is added to the argument. This means that −fee is the lower limit of the balance, as specified by the interface IPosFeeAccount. In contrast, the traits of CFeePosAccount are ordered such that the fee is added to the argument before the positive balance test. In this way, CFeePosAccount ensures that the balance is non-negative after a call to update. The verification of these classes with respect to their interfaces is discussed in Appendix C. Figure 12 summarizes the environments C , T resulting from the analysis of the different classes, focussing on the method withdraw. We assume that classes are analyzed in the top-down order in which they appear in the table, after the analysis of the basic trait definitions in Figure 8. Thus, the analysis is assumed to start in some initial environments  C 0 and T 0 where C 0 is empty and where each basic trait is bound to an annotated basic trait expression in T 0 , corresponding to the definition found in Figure 8. The environment T 0 is further detailed in Appendix C. Figure 12 shows the valid specifications for the methods in the classes CFeeAccount, CBasicAccount, CPosAccount, CPosFeeAccount, and CFeePosAccount. Furthermore, the trait in which the method is defined is indicated in the column Trait, and the column labelled PO indicates whether a new specification for the trait was needed to make the proof go through. Thus, if C and T are the class and trait environments resulting from the class analysis, a row C m sp TAE in the table means that sp ∈ S C (C, m) and sp ∈ specs(T (TAE)(m)), and an * indicates that a new specification for the method was provided during the analysis of C.
The specifications for each class in Figure 12 are consistent: Each internal call requirement follows from the guarantee of the called method, and each method contract in the interface follows from the corresponding guarantee in the class. If an interface has two contracts for withdraw, both are entailed by the verified specification. Note that the number of user-supplied specifications may be reduced by introducing uninterpreted boolean assertions in specifications (see [DDJ + 12]). For instance, withdraw in TBasicAccount could then be specified by (p, q), update : (p, q) for some p and q, which means that it would suffice to provide only one proof outline for this method.

Related Work
This section relates the presented work on a proof system for a trait-based object-oriented language to related work on proof systems for object-oriented programming languages. We refer to [BDSS13] for an in-depth discussion of traits Abbreviations for trait expressions:  and of how the trait language considered in this paper relates to other trait languages. We do not attempt to give a general discusion of object-oriented program verification here, but focus on how different approaches address code reuse mechanisms.
Multiple specifications of methods have been recognized as a convenient way of specifying behavior, for example in Fresco capsules [Wil91], with the also-constructs of JML [BCC + 05], and in Parkinson and Bierman's work [PB08]. In these approaches, two specifications are flattened (or "desugared") into a single specification by a composition rule; e.g., in Fresco two specifications (p 1 , q 1 ) and (p 2 , q 2 ) of the same method have the interpretation (p 1 ∨ p 2 , (p 1 → q o 1 ) ∧ (p 2 → q o 2 )) according to our notation. Note that this example demonstrates how it is never necessary to allow multiple specifications, but rather it is a convenience which is particularly clear with incremental approaches to deductive reasoning. In the context of the flexible code reuse offered by traits, there can be several specifications and we have therefore opted for an approach based on reasoning over sets of specifications instead of flattening these sets.
Single inheritance is the object-oriented code reuse mechanism which is by far the most studied and best supported in formal systems for program analysis. In the context of single inheritance, behavioral reasoning about extensible class hierarchies with late bound method calls is often performed in the context of behavioral subtyping (see, e.g., [LW94,Ame91,LN06,PHM99]). Behavioral subtyping is an incremental reasoning strategy in the sense that a subclass may be analyzed in the context of previously defined classes. In order to avoid reverification of superclasses, method overriding must preserve the specifications of overridden methods. This approach has also been used for SCALA's 'trait' construct, but "significantly reduced the applicability and thereby benefits of traits" [Sch10]. Combining separation logic with object-oriented structuring mechanisms, Parkinson and Bierman propose abstract predicate families which relate a set of implementations to the late binding mechanism [PB08]. The approach separates behavioral subtyping requirements on dynamic specifications from code reuse flexibility on static specifications and goes beyond behavioral subtyping by allowing new specifications of inherited code in a subclass, which need not respect the dynamic specifications of the superclass. Lazy behavioral subtyping [DJOS10] is an incremental reasoning strategy which supports more flexible code reuse than behavioral subtyping. With lazy behavioral subtyping, the requirements that a method guarantee imposes on late bound method calls are identified, and the main idea is that there is no need to preserve the full specifications of overridden methods. In order to avoid reverification of superclass methods, only the weaker requirements imposed on late bound method calls need to be preserved by method redefinitions in subclasses. Lazy behavioral subtyping is more flexible than the approach of [PB08] as it completely separates interface inheritance (for late bound external calls) and code reuse, and only requires compliance for requirements on internal calls instead of their specifications. Although traits do not support late bound internal calls, the flexible reuse of traits motivates us to follow the lazy behavioral subtyping approach in maintaining a separation of concerns between required and guaranteed assertions for method calls and definitions, respectively, and in allowing sets of specifications for each method definition.
Multiple inheritance is widely used in modeling notations such as UML [BRJ99], to capture that a concept naturally inherits from several other concepts. Versions of multiple inheritance are found in C++, CLOS, Eiffel, and OCaml. Creol [JOY06] has proposed a so-called healthy binding strategy which resolves horizontal name conflicts by avoiding accidental overriding. The proof systems presented in [NCMM09,DJOS11,LQ08,vSC10] are the only proof systems we know for multiple inheritance class hierarchies. The work in [NCMM09] presents a Hoare-style program logic for Eiffel that handles multiple inheritance based on an existing program logic for single inheritance by extending the method lookup definition. In [LQ08], method calls are assumed to be fully qualified in order to avoid ambiguities, and diamond inheritance is not considered. In [vSC10], ambiguities are assumed to be resolved by the programmer, a method can only be inherited if it has the same implementation in all parents. In contrast, [DJOS11] applies lazy behavioral subtyping to multiple inheritance and shows that healthy method binding is sufficient to allow incremental reasoning about multiple inheritance class hierarchies. The main challenges for reasoning about class hierarchies with multiple inheritance are related to late bound method calls, such as accidental or ambiguous overriding (sometimes called the "diamond problem"). In contrast, traits do not support late binding and require explicit disambiguation from the programmer. However, the flexible composition supported by traits necessitates a delayed selection of relevant method specifications, such that the requirements in our proof system are first checked when classes are assembled from traits. Technically, this makes lazy behavioral subtyping fairly different from the proposed proof system for traits. We are not aware of any previous proposal for a deductive proof system for a trait-based language.
Invasive code reuse mechanisms such as aspect-oriented programming (AOP) [KLM + 97,FES10], feature-oriented programming (FOP) [BSR04,AKL13] and delta-oriented programming (DOP) [SBB + 10] have been proposed to improve code reuse at different levels of the software design by allowing methods defined in one module to be intercepted or changed in another module. Similar to traits, this code reuse flexibility poses a challenge for program verification. In contrast to traits, AOP, FOP and DOP have a notion of original call, which allows the redefined method to be called from inside the redefinition. Most prominently, AOP aims to modularize code that crosscuts the basic program modules [KLM + 97]; so-called advice is used to allow a definition in an aspect to affect methods defined elsewhere. The two levels of modularity supported by AOP often improve code reuse in a program, compared to a single level of modularity as in traditional object-oriented programming. However, the highly invasive nature of aspects makes it very challenging to reason formally about program behavior. In contrast to traits, aspects rarely modify the state of a program in practice [KF07]; i.e., the aspects are largely external to the functionality of the core programs. Neither Aldrich [Ald05] nor Krishnamurthi and Fisler [KF07] address aspects which modify the program state in their work.
Extending AOP with open modules allow hiding implementation details from the advice mechanism, by using interfaces to export pointcuts. For a functional core calculus of open modules, Aldrich uses weak bisimulation techniques to reason about module equivalence with respect to the application of advice [Ald05]. Krishnamurthi and Fisler use CTL model checking to verify AOP programs expressed as state machines with pointcut interfaces [KF07], to identify when the application of an aspect may violate properties of the original program. Similar to our work their approach is incremental and uses a cache. Extending the idea of pointcut interfaces, translucent contracts have been proposed to behaviorally restrict the applicability of aspects [BRLM11], thereby making AOP amenable to modular deductive verification. These works on AOP are akin to ours in that they address reasoning about mechanisms which aim at better code reuse than class inheritance. However, the proposed use of interfaces between classes and aspects would quickly become unwieldy if adapted to the composition of trait expressions.
Whereas AOP addresses changes to method calls in terms of pointcuts, FOP and DOP address changes to a set of classes to accomodate feature selection in software product lines, allowing in particular methods to be redefined. Verification of FOP programs based on a meta-representation of all program variants that can be generated from a set of feature modules is considered in [TSAH12]. In [TSKA11], proof scripts for single feature modules are extracted from proofs for complete program variants and later composed for other program variants using these feature modules.
Hähnle and Schaefer propose an approach to deductive verification for DOP which relies on behavioral subtyping for DOP [HS12]; i.e., specifications of methods introduced by deltas must be more specific than previous versions of these methods. Thus, a delta can only modify state in a way which refines the program state and each delta can be verified by approximating called methods defined in other deltas by the specification of their first declaration. We have proposed a different approach [DDJ + 12]; which considers deltas as transformations of a program, and delta specifications as higher-order specifications which are instantiated at the delta composition time to transform a specific specification. This transformational approach uses symbolic assumptions on called methods and thus separates the specifications of method implementations from the requirements to method calls in a way which is similar to lazy behavioral subtyping [DJOS10]. The transformational approach leads to a two-phase verification process: the verification of deltas and the verification of the actual products based on the specifications already established for the used deltas. We believe that a transformational approach similar to [DDJ + 12] could be applied to traits and a comparison between the approach taken in this paper and a transformational proof system would be an interesting extension of the work presented in this paper.

Conclusion and Future Work
This paper describes an approach to behavioral reasoning about trait-based object-oriented programs. Traits have been proposed as a particularly flexible way to achieve a high degree of fine-grained code reuse. We develop a deductive proof system, PST(PL), which reflects this fine-grained reuse potential at the level of behavioral reasoning. The approach focusses on verifying interface contracts for classes assembled from traits, based on method specifications in the traits. For flexible reuse, methods in traits have associated sets of possible specifications. These sets can be extended with new specifications as needed for class verification in an incremental way. When verifying a class, the interface contracts of the class drive the selection of possible specifications from the specification sets in the traits, in such a way that the internal consistency among the selected specifications is guaranteed and such that the interface contracts are valid. We show the soundness of PST(PL). Trait-based code reuse is an interesting challenge for deductive proof systems because a high degree of reuse in a code structuring mechanism typically limits the degree of reasoning reuse which can be supported by the proof system. In particular, a trait cannot be fully verified independently of its context of composition. The presented approach addresses this challenge by proposing an incremental and compositional proof system for traits, in which specifications for methods in trait alteration expressions and in composed trait expressions are compositionally derived from basic trait expressions, and in which the sets of possible specifications can be incremented at need during the verification process. The approach combines bottom-up compositional reasoning about trait expressions with top-down selection of consistent specifications for methods declared in different traits during the verification process for classes.
The complexity of verifying trait-based programs using our proof system can be compared to the naive approach of first flattening the programs and then verifying them. When flattening each program built from a set of traits before verifying it, we need to verify each method in isolation which requires as many proofs are there are methods. In this case, there is no specification reuse. In the completely modular case of our proof system where the specifications in the trait environment suffice to establish the external requirements, we do not need any new code analysis to verify the new program. In the fully incremental case of our proof system where each external requirement needs a new trait specification to be verified, we need one proof for each method which is the same as for the naive approach. In all cases where some external requirements can be shown modularly from existing specifications and some external specifications need incremental verification by adding new specifications, we have some specification reuse and thereby less code analysis than when verifying flattened programs. With our approach, the gain comes from analyzing many programs with the incrementally constructed trait environment, to achieve specification reuse similar to modular reasoning for common ways of using of traits.
In this paper, we have concentrated on verifying method contracts given as pre-and postconditions. As future work, it is interesting to investigate to what extent invariants could be useful for trait-based programs, both at the level of classes and traits. A trait invariant can, for instance, capture relations between the required fields of a trait; this will extend the range of properties that can be incrementally verified for trait-based programs. Further, we plan to extend the KeY system [BHS07] for deductive verification of JAVA programs to a trait-based language such as TRAITRECORDJ [BDSS13] and to implement the proof system proposed in this paper within KeY.

A. Auxiliary Functions for Extending the Trait Environment
This section details the auxiliary functions used to update the trait environment for trait alteration expressions in the rule EXTEND of the proof system for trait analysis given in Section 7.2. The auxiliary functions are defined in Figure 13. The update function T ⊕ (TAE, ao) creates an entry for TAE ao in T by modifying the existing entry for TAE. In this case, the old field f does not occur in the method, which means that the method definition itself is not changed. To avoid name clashes, we then discard the specifications which contain f. The soundness of T ⊕ (TAE, ao) follows by Lemma B.2. (A more fine-grained analysis of field renaming may be possible in program logics PL which support variables-asresources [PBC06].) The auxiliary function renSM(sp, m, m ) renames the method m in sp. Since method names do not occur in assertions, this function is defined in terms of renRM which replaces each requirement n : (r, s) by n[m /m] : (r, s). Similarly, the function renSF(sp, f, f ) renames the field f in sp, and is defined in terms of renRF which renames fields in requirements. The function renMF renames fields in method definitions, and the function discard(sp, f) returns sp except specifications that contain variables in f.

B. Soundness of PST(PL)
Appendix B.1 presents the proof for the soundness of PST(PL). The main soundness result is formalized by Theorem 7.4, which expresses that the verification of a class leads to a consistent set of specifications for that class. Appendix B.2 contains auxiliary lemmas used for the soundness proof. Especially, the proof of Lemma B.2 ensures that the trait environment T is sound after the successful analysis of the basic trait declarations; i.e., there is a valid proof outline for all specifications recorded in T during the analysis of traits and classes. We here assume that trait and class environments have been constructed from the empty trait and class environments by application of the rules of PST(PL).

B.1. Main Theorem
Theorem 7.4. For a given class class C implements I by { rp I , F; } and CTE, if the successful analysis of C in PST(PL) leads to a class environment C , then the set of method specifications for C in C are consistent for the flattened version of C.
Proof. We first check Condition 2 in Definition 7.3. For each m ∈ mtds(CTE), we consider the set S C (C, m). Let CTE TAE 1 + . . . + TAE n . By type safety, there must be exactly one i (for 1 ≤ i ≤ n) such that m ∈ mtds(T (TAE i )). By Lemma B.6 we know that S C (C, m) ⊆ specs(T (TAE i )(m)). Let (p, q), R ∈ S C (C, m). By Lemma B.2, there exists a proof outline O for the method body of m with guarantee (p, q) such that R reqs(O). For each n : (r, s) ∈ R, we prove guar(S C (C, n)) (r, s) by induction over the inference rules of PST(PL).
To include (p, q), R in S C (C, m), rule ANALYZE must be applied, which again generates a discharge operation for a set of requirements which includes R. Repeatedly applying rule DECOMP4 results in a discharge(n : (r, s)) operation, which is analyzed by either OPENANALYSIS or CLOSEANALYSIS. If OPENANALYSIS is applied, we get an operation analyze(TAE j , n : (r, s)) where j is such that n ∈ mtds(T (TAE j )). This operation must again be handled by the ANALYZE rule, which ensures the entailment guar(S C (C, n)) (r, s). Before ANALYZE can be applied in the proof, INCREMENT may be needed to introduce the necessary specifications sp into the trait environment to ensure that guar(sp) (r, s). The application of ANALYZE again generates a discharge operation for a set of requirements which includes req(sp). Since the analysis of C succeeds, the repeated application of ANALYZE must eventually terminate. If CLOSEANALYSIS is applied, the conclusion guar(S C (C, n)) (r, s) follows directly.
For Condition 1 in Definition 7.3, we have by the rules CLASS and DECOMP4 that a discharge(m : (r, s)) operation is analyzed for each m : (r, s) ∈ contracts(rp I , I). By an argument corresponding to the one for discharge above, we get S C (C, m) (r, s).
It follows from Lemma B.5 that the sets of method specifications S C (C, m) for all m ∈ mtds(CTE) constitute a consistent set of method specifications for the flattened version of C.

B.2. Auxiliary Lemmas
Lemma B.1. Let the trait alteration expression TAE be defined by Tb ao. If TAE ∈ T , then for any (possibly empty) prefix ao of ao, we also have Tb ao ∈ T .
Proof. The proof is by induction over the length of the list ao of alteration operations. If ao is empty, then TAE is a basic trait Tb which is introduced in T by rule BASICTRAIT. For the induction step, consider TAE ao, where TAE = Tb ao. Since TAE ao must have been introduced by rule EXTEND, we have that TAE ∈ T , i.e., we have Tb ao ∈ T . By the induction hypothesis, Tb ao ∈ T for all prefixes ao of ao.
Lemma B.2 (Soundness of T ). Let T be a trait environment such that all basic traits in T are successfully analyzed. Then the following holds for all TAE ∈ T : Proof. The proof is by induction over the structure of TAE. By Lemma B.1 each prefix of TAE is also in T . Base case: TAE = Tb. Then (p, q), R is included in sp by either VERIFY or BASICTRAIT. If rule VERIFY is applied, the lemma follows immediately from the premise of the rule. The application of rule BASICTRAIT, possibly followed by a number of DECOMP1 and DECOMP2 applications, results in an operation verify(Tb, M (p, q), R ) for every specification (p, q), R of some M in Tb. This operation is analyzed by VERIFY after zero or more applications of ADAPTATION. We close this case of the proof by induction over the number of applications of ADAPTATION. For zero applications, the lemma follows directly from the application of VERIFY. For the induction step, we assume a specification (p , q ), R such that (p , q ), R The only rules that extend T with a new specification for non-basic traits are VERIFY and EXTEND. If (p, q), R is included in the trait environment by VERIFY, the conclusion follows immediately. If EXTEND is applied, the trait environment is extended to T [TAE → mod(T (TAE ), ao)], where the definition of mod can be found in Figure 13. The different cases for ao ensure the conditions of the lemma as follows: -Case f ∈ fields(t) ∧ f ∈ fields(t).
The new method body is obtained by renaming f to f . For each specification (p, q), R ∈ sp, the modified specification renSF ( (p, q), By IH there is a proof outline O such that O PL t : (p, q) and R reqs(O). Since f does not occur in O, a proof outline for t[f /f] can be constructed directly by field renaming, resulting in the specification renSF ( (p, q), R , f, f ).
-Case f ∈ fields(t) ∧ f / ∈ fields(t). In this case, the method body is unaltered by the rename operation. However, we discard specifications containing the renamed field f. Proof outlines for the remaining specifications follow directly by IH.       = CTE Lemma B.6. Consider class C implements I by { rp I F; } and CTE such that CTE TAE 1 + . . . + TAE n . Let the environments T and C result from the successful analysis of this class. For m ∈ mtds(TAE i ) and 1 ≤ i ≤ n, we have S C (C, m) ⊆ specs(T (TAE i )(m)).
Proof. By type safety, each method in CTE is defined in exactly one TAE i . The relation S C (C, m) ⊆ specs(T (TAE i )(m)) follows by induction over the inference rules of PST(PL). When the analysis of class C starts by rule CLASS, the mapping S C (C, m) is initially empty, so the subset relation holds initially. Since S C (C, m) is only extended by ANALYZE, it suffices to consider this rule. The rule maintains the relation since if S C (C, m) is extended by some set sp by the rule, it follows from the premises that sp ⊆ specs(T (TAE i )(m)).

C. Verification of the Example
This section details the verification of the bank account classes from Section 8. In order to verify proof outlines, we must fix the program logic PL. In this example, we use a standard Hoare logic for sequential statements [AdBO09].
Since formal parameters are read-only in the example, we may use the following rule for analyzing method calls: The only proof outlines which need to be supplied during the basic trait analysis are for this update method and for deposit in TBasicAccount. It is straightforward to provide these proof outlines given the guarantees.
We now consider the analysis of the class CFeeAccount in detail, assuming that the class is analyzed in the environment C 0 , T 0 , where CFeeAccount / ∈ C 0 . Figure 14 shows the application of the proof system to the analysis of this class, leading to a successful analysis, where C 5 , T 3 are the resulting environments.
In the first step, the class definition leads to the analysis of the trait expression TBasicAccount + CTE followed by discharge operations for the contracts of the interface IFeeAccount. The trait expression decomposes and as the basic traits are already analyzed, we get to the extend operation for the trait alteration expression TBasicUpd[update rT bUpdate]. The result is an extended trait environment T 1 where a trait expression for the renaming of TBasicUpd is included in the trait environment. It is not necessary to reanalyze the renamed method, the specification is generated by renaming the existing method specification in TBasicUpd.
At this point, the discharge operation is at the head of the analysis operation sequence, and is decomposed. For the method deposit, ANALYZE can be applied and the specification found in TBasicAccount is included in the class environment, resulting in the class environment C 2 . Since neither withdraw nor update is specified in TBasicAccount and TFeeUpd, respectively, the analysis continues with OPENANALYSIS. Proof outlines for these methods must be provided at the level of their trait declarations by applying INCREMENT and checked by applying VERIFY. In these proof outlines, the requirement for the call to bUpdate follows from the generated specification of this method. CFeeAccount : discharge(bUpdate : (bal == b 0 , bal == b 0 − x)) (ANALYZE) (12) C 3 , T 3 CFeeAccount : analyze(TFeeUpd, update : (bal == b 0 , bal == b 0 − x − fee)) (VERIFY) (11) C 3 , T 2 verify(TFeeUpd, U (bal == b 0 , bal == b 0 − x − fee), bUpdaate : (bal == b 0 , bal == b 0 − x) ) · CFeeAccount : . . .