Higher-Order Linearisability

Linearisability is a central notion for verifying concurrent libraries: a given library is proven safe if its operational history can be rearranged into a new sequential one which, in addition, satisfies a given specification. Linearisability has been examined for libraries in which method arguments and method results are of ground type, including libraries parameterised with such methods. In this paper we extend linearisability to the general higher-order setting: methods can be passed as arguments and returned as values. A library may also depend on abstract methods of any order. We use this generalised notion to show correctness of several higher-order example libraries.


Introduction
Software libraries provide implementations of routines, often of specialised nature, to facilitate code reuse and modularity. To support the latter, they should follow specifications that describe the range of acceptable behaviours for correct and safe deployment. Adherence to specifications can be formalised using the classic notion of contextual approximation (refinement), which scrutinises the behaviour of code in any possible context. Unfortunately, the quantification makes it difficult to prove contextual approximation directly, which motivates research into sound techniques for establishing it.
In the concurrent setting, a notion that has been particularly influential is that of linearisability [1]. Linearisability requires that, for each history generated by a library, one should be able to find another history from the specification (a linearisation), which matches the former up to certain rearrangements of events. In the original formulation by Herlihy and Wing [1], these permutations were not allowed to disturb the order between library returns and client calls. Moreover, linearisations were required to be sequential traces, that is, sequences of method calls immediately followed by their returns.
In this paper we shall work with open higher-order libraries, which provide implementations of public methods and may themselves depend on abstract ones, to be supplied by parameter libraries. The classic notion of linearisability only applies to closed libraries (without abstract methods). Additionally, both method arguments and results had to be of ground type. The closedness limitation was recently lifted in [2,3], which distinguished between public (or implemented) and abstract methods (callable). Although [2] did not in principle exclude higher-order functions, those works focused on linearisability for the case where the allowable methods were restricted to first-order functions (int → int). Herein, we give a systematic exposition of linearisability for general higher-order concurrent libraries, where methods can be of arbitrary higher-order types. In doing so, we also propose a corresponding notion of sequential history for higher-order library interactions. We examine libraries L that can interact with their environments by means of public and abstract methods: a library L with abstract methods of types Ψ = θ 1 , · · · , θ n and public methods Ψ = θ 1 , · · · , θ n is written as L : Ψ → Ψ . We shall work with arbitrary higher-order types generated from the ground types unit and int. Types in Ψ, Ψ must always be function types, i.e. their order is at least 1.
A library L may be used in computations by placing it in a context that will keep on calling its public methods (via a client K ) as well as providing implementations for the abstract ones (via a parameter library L ). The setting is depicted in Fig. 1. Note that, as the library L interacts with K and L , they exchange functions between each other. Consequently, in addition to K making calls to public methods of L and L making calls to its abstract methods, K and L may also issue calls to functions that were passed to them as arguments during higher-order interactions. Analogously, L may call functions that were communicated to it via library calls.
Our framework is operational in flavour and draws upon concurrent [4,5] and operational game semantics [6][7][8]. We shall model library use as a game between two participants: Player (P), corresponding to the library L, and Opponent (O), representing the environment (L , K ) in which the library was deployed. Each call will be of the form call m(v) with the corresponding return of the shape ret m(v), where v is a value. As we work in a higher-order framework, v may contain functions, which can participate in subsequent calls and returns. Histories will be sequences of moves, which are calls and returns paired with thread identifiers. A history is sequential just if every move produced by O is immediately followed by a move by P in the same thread. In other words, the library immediately responds to each call or return delivered by the environment. In contrast to classic linearisability, the move by O and its response by P need not be a call/return pair, as the higher-order setting provides more possibilities (in particular, the P response may well be a call). Accordingly, linearisable higher-order histories can be seen as sequences of atomic segments (linearisation points), starting at environment moves and ending with corresponding library moves.
In the spirit of [3], we are going to consider two scenarios: one in which K and L share an explicit communication channel (the general case) as well as a situation in which they can only communicate through the library (the encapsulated case). Further, we also handle the case in which extra closure assumptions can be made about the parameter library (the relational case), which can be useful for dealing with a variety of assumptions on the use of parameter libraries that may arise in practice. In each case, we present a candidate definition of linearisability and illustrate it with tailored examples. The suitability of each kind of linearisability is demonstrated by showing that it implies the relevant form of contextual approximation (refinement). We also examine compositionality of the proposed concepts. One of our examples will discuss the implementation of the flat-combining approach [9,3], adapted to higher-order types.
The paper is an extended version of [10] and contains complete proofs, fully elaborated examples and appendices with further technical material, e.g. on compositionality.

Example: a higher-order multiset library
Higher-order libraries are common in languages like ML, Java, Python, etc. As an illustrative example, we consider a library written in ML-like syntax which implements a multiset data structure with integer elements. For simplicity, we assume that its signature contains just two methods: The former method returns for each integer its multiplicity in the multiset -this is 0 if the integer is not a member of the multiset. On the other hand, update takes as an argument an integer i and a function g, and updates the multiplicity j of i in the multiset to |g( j)| (we use the absolute value of g( j) in order to meet the multiset requirement that element multiplicities not be negative; alternatively, we could have used exceptions to quarantine such client method behaviour). Methods with the same functionalities can be found in the multiset module of the ocaml-containers library [11]. While our example is simple, the same kind of analysis as below can be applied to more intricate examples such as map methods for integer-valued arrays, maps or multisets.
Example 1 (Multiset). Consider the concurrent multiset library L mset in Fig. 2 on the LHS (the RHS will be discussed only later). It uses a private reference for storing the multiset's characteristic function and reads optimistically, without locking (cf. [12,13]). The update method in particular reads the current multiplicity of the given element i (via count) and computes its new multiplicity without acquiring a lock on the characteristic function. It only acquires a lock when it is ready to write 1 public count, update; 2 Lock lock; 3 F := λx.0; 4 5 count = λi. (!F)i 6 update = λ(i, g). aux(i,g,count i) 7 8 aux = λ(i, g, j). 9 let y = |g j| in = λ(i, g). aux(i,g,count i) 7 8 ... 9 ... ... 19 ... 20 reset = λi. 21 lock . acquire(); 22 let y = |default i| in 23 let f = !F in  the new value (line 10) in the hope that the value at i will still be the same and the update can proceed; if not, another attempt to update the value is made.
Let us look at some example executions of the library via their resulting histories, i.e. sequences of method calls and returns between the library and a client. In the topmost block (a) of history diagrams of Fig. 3, we see three such executions. Note that we do not record internal calls to count or aux, and use m and variants for method identifiers (names). We use the abbreviation cnt for count, and upd for update, and initially ignore the circled events for cnt. Each execution involves 2 threads.
In the first execution, the client calls update(i, m) in the second thread, and subsequently calls count(i) in the first thread. The code for update stipulates that first count(i) be called internally, returning some multiplicity j for i, and then m( j) should be called. As soon m returns a value j , update sets the multiplicity of i to j and itself returns j . The last event in this history is a return of count in the first thread with the old value j. According to our proposed definition, this history will be linearisable to another, intuitively correct one: the last return can be moved to the circled position. At this point the notion of linearisability is used informally, but it will be made precise in the following sections. In the second execution, the last return of count in the first thread returns the updated value. In this case, we will be able to move call cnt(i) to the circled position to obtain a linearisation, which is obviously correct. Finally, in the third execution we have a history that will turn out non-linearisable to an intuitively correct history. Indeed, we should not be able to return the updated value in the first thread before m has returned it in the second one.
The two histories in block (b) in the same figure demonstrate the mechanism for updates. The first history will be linearisable to the second one. In the second history we see that both threads try to update the same element i, but the first one succeeds in it first and returns k on update. Then, the second thread realises that the value of i has been updated to k and calls m again, this time with argument k. An important feature of the second history is that it is sequential: each client event (call or return) is immediately followed by a library event.
Observe that the rearrangements discussed above involve either advancing a library action or postponing an environment action and that each action could be a call or a return. Definition 9 will capture this formally. For now, we note that this generalises the classic setting [1], where library method returns could be advanced and environment method calls deferred.
The next section will introduce histories along with the proposed notion of linearisability. In Section 3 we present the syntax for libraries and clients, and in Section 3.1 we define their semantics in terms of histories and co-histories respectively.

Higher-order linearisability
We examine higher-order libraries interacting with their context by means of abstract and public methods. In particular, we shall rely on types given by the grammar below. We let Meths stand for the set of method names and assume Meths = θ,θ Meths θ,θ , where each set Meths θ,θ contains names for methods of type θ → θ . Methods are ranged over by m (and variants). We let v range over computational values, which include a unit value, integers, methods and pairs of values.
The framework of a higher-order library and its environment is depicted in Fig. 1. Given Ψ, Ψ ⊆ Meths, a library L is said to have type Ψ → Ψ if it defines public methods with names (and types) as in Ψ , using abstract methods Ψ . The environment of L consists of a client K (which invokes public methods of Ψ ), and a parameter library L (which provides code for the abstract methods Ψ ). In general, K and L may interact via a disjoint set of methods Ψ ⊆ Meths, to which L has no access.
In the rest of this paper, we shall implicitly assume that we work with a library L operating in an environment presented in Fig. 1. The client K will consist of a fixed number N of concurrent threads. Next we introduce a notion of history tailored to the setting and define how histories can be linearised.

Higher-order histories
The operational semantics of libraries will be given in terms of histories, which are sequences of method calls and returns, each decorated with a thread identifier t and a polarity index X , where X ∈ {O , P }, as shown below.
We shall refer such decorated calls and returns as moves. Here, m is a method name and v is a value of a matching type.
The index X specifies who produces the move: the library L (polarity P ), or its environment (L , K ) (polarity O ). Using notation e.g. from [3], P corresponds to !, and O to ?. We may be dropping the polarity of a move when it is not important or no confusion arises by doing so. The choice of indices is motivated by the fact that the moves can be seen as defining a 2-player game between the library (L), which represents the Proponent player in the game ( P ), and its environment (L , K ) that represents the Opponent (O ). Finally, we let the dual polarity of X be X , where X = X .
Next we proceed to define histories. Their definition will rely on a more primitive concept of prehistories, which are sequences of O / P -indexed method calls and returns that respect a stack discipline.

Definition 2.
Prehistories are sequences generated by one of the grammars: where, if m ∈ Meths θ,θ , the types of v, v must match θ, θ respectively. We let PreH = PreH O ∪ PreH P .
Thus, prehistories from PreH O start with an O -call, while those in PreH P start with a P -call. In each case, the polarities inside a prehistory alternate between O and P , and the polarities of calls and matching returns are always dual (returns dual to calls).
Histories will be interleavings of prehistories tagged with thread identifiers (natural numbers), subject to a set of wellformedness constrains. In particular, a history h for library L : Ψ → Ψ will have to begin with an O -move and satisfy the following conditions, to be formalised in Definition 3: 1. The name of any method called in h must come from Ψ or Ψ , or be introduced earlier in h as a higher-order argument or result (no methods out of thin air). In addition: • if the method is from Ψ , the call must be tagged with O (i.e. issued by K ); • if the method is from Ψ , the call must be tagged with P (i.e. issued by L towards L ); • for a call of method m / ∈ Ψ ∪ Ψ to be valid, m must be introduced in an earlier move of dual polarity (calls dual to introductions).
2. Any method name appearing inside a call or return argument in h must be fresh, i.e. not used earlier (introductions always fresh).
• This reflects the assumption that methods can be called and returned from, but not compared for identity equality. It is therefore a requirement towards the completeness of histories as a semantics for concurrent libraries. For example, this ensures that rules like η-equality are preserved in the semantics.
• The condition serves the additional purpose of making the setting described in Fig. 1 robust, as it prevents method names in Ψ from being leaked to the client K . This ensures that encapsulation cannot be broken.
Given h ∈ PreH and t ∈ N, we write t × h for h in which each element is decorated with t: 1. For any s 1 (t, call m(v)) X s 2 ∈ H Ψ,Ψ , either m ∈ Ψ and X = O , or m ∈ Ψ and X = P , or there is a move (t , x) X in s 1 that introduces m and X = X . 2. For any s 1 (t, x) X s 2 ∈ H Ψ,Ψ and any m, if m is introduced by x then m must not occur in s 1 .
Note that the definition supports scenarios in which a method sent as a parameter by one thread can be called by a different thread. This feature will be explored in Example 18. We shall range over H Ψ,Ψ using h, s (and variants). The subscripts Ψ, Ψ will often be omitted. Given a history h, we shall write h for the sequence of moves obtained from h by dualising all move polarities inside it. The set of co-histories While in this section histories will be extracted from example libraries informally, in Section 3.1 we give the formal Remark 4. The notion of history introduced above extends the classic notion from [1] to higher-order types. It also extends the notion presented in [3]. The intuition behind the definition is that a history is a sequence of (well-bracketed) method calls and returns, called moves, each tagged with a thread identifier and a polarity, where polarities track the originators and recipients of moves. Moves may be calls or returns related to methods given in the library interface (Ψ → Ψ ), or dynamically created methods that appear earlier inside the histories -recall that, in a higher-order setting, methods can be passed around as arguments to calls or be returned as results by other methods. On the other hand, a sequential history is one in which the operations performed by the library can be perceived as atomic, that is, each move produced by O is to be immediately followed by the library's response, which is a P move in the same thread.
Example 5 (Multiset spec). We now revisit our first example and provide a specification for it. Recall the multiset library L mset from Fig. 2. Our verification goal will be to prove linearisability of L mset to a specification A mset ⊆ H seq ∅,Ψ , where Ψ = {count, update}, which we define below. Intuitively, the specification stipulates that the multiset operations are functionally correct and only includes sequential histories. For example, the following histories are in the specification: (1, call upd(5, m)) O (1, call m(5)) P (1, call cnt(5)) O (1, ret cnt(0)) P (1, ret m(42)) O (1, ret upd(42)) P (1, call upd(5, m)) O (1, call m(5)) P (2, call upd(5, m (24)) P while the next ones are not: (24)) P (1, call cnt(5)) O (1, ret cnt(42)) P A mset will certify that L mset correctly implements some integer multiset I whose elements change over time according to the moves in h. For a multiset I and natural numbers i, j, we write I(i) for the multiplicity of i in I , and I[i → j] for I with its multiplicity of i set to j. We shall stipulate that moves inside histories h ∈ A mset be annotatable with multisets I in such a way that the multiset is empty at the start of h (i.e. I(i) = 0 for all i) and: • If I is changed between two consecutive moves in h then the second move is a P -move. In other words, the client cannot directly update the elements of I .
• Each call to count on argument i must be immediately followed by a return with value I(i), and with I remaining unchanged.
• Each call to update on (i, m) must be followed by a call to m on I(i), with I unchanged. Moreover, m must later return with some value j. Assuming at that point the multiset will have value J , if I(i) = J (i) then the next move is a return of the original update call, with value j; otherwise, a new call to m on J (i) is produced, and so on.
We formally define the specification next.
Let H • ∅,Ψ contain sequences of moves from ∅ → Ψ accompanied by a multiset (i.e. the sequences consist of elements of the form (t, x, I) X ). For each s ∈ H •

Three notions of linearisability
We present three notions of linearisability. First introduce a general notion that generalises classic linearisability [1] and parameterised linearisability [3]. We then develop two more specialised variants: a notion of encapsulated linearisability, following [3], that captures scenarios where the parameter library and the client cannot directly interact; and a relational notion whereby context behaviour (client and parameter library) is known to be relationally invariant.

General linearisability
We begin by introducing a class of reorderings on histories.
Definition 7. Let P O ⊆ H Ψ,Ψ × H Ψ,Ψ be the smallest binary relation over H Ψ,Ψ satisfying, for any t = t : Intuitively, two histories h 1 , h 2 are related by P O if the latter can be obtained from the former by swapping two adjacent moves from different threads in such a way that, after the swap, a P -move will occur earlier or an O -move will occur later. Note that the relation always applies to adjacent moves of the same polarity. On the other hand, we do not have Note that h * P O h by permuting (2, call m(5)) O rightwards and (1, ret m(4)) P leftwards.
As another example, we can revisit the histories in Fig. 3. There, O -moves are coloured purple and P -moves are blue. In part (a) we can see that: • the first history linearises to a sequential one by swapping a P-move of thread 1 to the left of two moves of thread 2, • the second history linearises to a sequential one by swapping an O-move of thread 1 to the right of two moves of thread 2, • the third history is already sequential and it cannot be linearised to a different one.
In part (b), on the other hand, the first history linearises to the second one by a series of swaps (left as exercise).
Analogously, one can consider the symmetric variant O P of P O , which will turn out useful in our soundness argument.

Definition 9 (General linearisability). Given
Given libraries L, L : Ψ → Ψ and a set of sequential histories A ⊆ H seq Ψ,Ψ we write L ¡ A, and say that L can be linearised

Remark 10.
The classic notion of linearisability from [1] states that h linearises to h just if the return/call order of h is preserved in h (and h is sequential), i.e. if a return move precedes a call move in h then so is the case in h . Observing that, in [1], return and call moves coincide with P -and O -moves respectively, we can see that our higher-order notion of linearisability is a generalisation of the classic notion.
Our definition shows that the ownership of actions is the key determinant of what moves can be swapped rather than the call/return distinction, which was prominent in the classic case. It just so happens that, for Ψ = ∅ and Ψ = {m : int → int}, the two coincide.
For further comparison, recall that the classic definition allowed for call /call , ret /ret and call /ret swaps, but ret /call was forbidden. According to our definition, what is allowed depends on polarity, so a call /call swap may well be illegal if the first call is a P -move and the second call is an O -move. Similarly, a ret /call swap is allowed as long as both actions belong to the same player or the return is an O -action and the call is a P -action. For instance, Example 8 involves the following kinds of swaps: Our emphasis on move ownership is motivated by Lemma 34, which will ultimately enable us to prove that, if h ¡ h , then h suffices to demonstrate the interactive potential of h. This intuition is formally captured in Theorem 35. Remark 11. [3] defines linearisation using a "big-step" relation that applies a single permutation to the whole sequence. This contrasts with our definition as * P O , in which we combine multiple adjacent swaps. In Appendix A we show that the two definitions are equivalent.

Encapsulated linearisability
We next show that a more permissive notion of linearisability applies if the parameter library L of Fig. 1 is encapsulated, that is, the client K can have no direct access to it (i.e. Ψ = ∅). To capture this scenario, we define a second polarity function on moves, which determines the side of the move: • a move with side K is played between the library L and the client K , while • a move with side L is played between the library L and the parameter library L .
Formally, given a history h ∈ H Ψ,Ψ , we define a side function on its moves by: where, in the latter case, (t, call m(v )) is the corresponding call of (t, ret m(v)). Thus, every move in h can be assigned a unique side polarity from {K, L}. For simplicity, we shall be tagging moves with a second index Y ∈ {K, L} corresponding to their side polarity.
In this more restrictive nature of interaction, in which K and L are separated, in addition to sequentiality in every thread we shall insist that a move made by the library in the L or K side must be followed by an O move from the same side.  We define the corresponding linearisability notion as follows. First, let ⊆ H Ψ,Ψ × H Ψ,Ψ be the smallest binary relation on H Ψ,Ψ such that, for any X, X , and any Y , Y ∈ {K, L} with Y = Y and t = t : Then, ( P O ∪ ) * prevents (t, call m(i) P L ) from being swapped with any subsequent (t , ret m(i) O L ), and similarly for (t, ret m (i) P K ) and (t , call m (i) O K ). Thus, our definition coincides in this example with Definition 3 of [3].

Remark 15.
The encapsulated framework implies that the client and the parameter library are independent entities. Consequently, whenever their interaction with the library involves two adjacent moves (t, m) X Y (t , m ) X Y with t = t , X = X , permuting them will also generate a valid interaction. This justifies the extra freedom in rearranging moves in Definition 13. The soundness of this intuition is validated in Lemma 39 and Theorem 40.

Example 16 (Parameterised multiset).
We revisit the multiset library of Example 1 and extend it with a public method reset, which performs multiplicity resets to default values using an abstract method default as the default-value function (again, we use absolute values to avoid negative multiplicities). The extended library is shown in the RHS of Fig. 2   L mset2 : Ψ → Ψ , with Ψ = {default} and Ψ = {count, update, reset}. In contrast to the update method of L mset , reset is not optimistic: it retrieves the lock upon its call, and only releases it before return. In particular, the method calls default while it retains the lock.
Observe that, were default able to externally call update, we would reach a deadlock: default would be keeping the lock while waiting for the return of a method that requires the lock. On the other hand, if the library is encapsulated then the latter scenario is not possible. In such a case, L mset2 linearises to the specification A mset2 , defined next.
and the set S is now given by the grammar of Example 5 extended with the rule: Our framework makes it possible to confirm that L mset2 enc-linearises to A mset2 .

Relational linearisability
We finally extend general linearisability to cater for situations where the client and the parameter library adhere to closure constraints expressed by relations R on histories. Let Ψ, Ψ be sets of abstract and public methods respectively.
The closure relations we consider are closed under permutations of methods outside Ψ ∪ Ψ : if h R h and π is a (typepreserving) permutation on Meths \ (Ψ ∪ Ψ ) then π(h) R π(h ). The requirement represents the fact that, apart from the method names from a library interface, the other method names are arbitrary and can be freely permuted without any observable effect. Thus, R should not be distinguishing between such names.
Example 18. We consider a higher-order variant of an example from [3] that motivates relational linearisability. Flat combining [9] is a synchronisation paradigm that advocates the use of a single thread holding a global lock to process requests of all other threads. To facilitate this, threads share an array to which they write the details of their requests and wait either until they acquire a lock or their request has been processed by another thread. Once a thread acquires a lock, it executes all requests stored in the array and the outcomes are written to the array for access by the requesting threads. Fig. 4 is built following the flat combining approach and, on acquisition of the global lock, the winning thread acts as a combiner of all registered requests. Note that the requests will be attended to one after another (thus guaranteeing mutual exclusion) and only one lock acquisition will suffice to process one array of requests. Using our framework, one can show that L fc can be R-linearised to the specification given by the library L spec defined by where each function call in L spec is protected by a lock. Observe that we cannot hope for L fc ¡ L spec , because clients may call library methods with functional arguments that recognise thread identity. Consequently, we can relate the two libraries  only if context behaviour is guaranteed to be independent of thread identifiers. This can be expressed through ¡ R , where R ⊆ H ∅,Ψ × H ∅,Ψ is a relation capturing thread-blind client behaviour (see Subsection 3.2 for details).

Library syntax and semantics
We now look at the concrete syntax of libraries and clients. Libraries comprise collections of typed methods whose argument and result types adhere to the grammar: θ :: We shall use three disjoint enumerable sets of names, referred to as Vars, Meths and Refs, to name respectively variables, methods and references. x, f (and their decorated variants) will be used to range over Vars; m will range over Meths; and r over Refs. Methods and references are implicitly typed, i.e. Meths = θ,θ Meths θ,θ and Refs = Refs int θ,θ Refs θ,θ , where Meths θ,θ contains names for methods of type θ → θ , Refs int contains names of integer references and Refs θ,θ contains names for references to methods of type θ → θ . We write for disjoint set union.
The syntax for libraries and clients is given in Fig. 5. Each library L begins with a series of method declarations (public or abstract) followed by a block B containing method implementations (m = λx.M) and reference initialisations (r := i or r := λx.M). The typing rules ensure that each public method is implemented within the block, in contrast to abstract methods. Clients are parallel compositions of closed terms.
Terms M specify the shape of allowable method bodies. () is the skip command, i ranges over integers, tid is the current thread identifier and ⊕ represents standard arithmetic operations. Thanks to higher-order references, we can simulate divergence by (!r)(), where r ∈ Refs unit,unit is initialised with λx unit .(!r)(). Similarly, while M N can be simulated by (!r)() after r := λx unit .let y = M in (if y then (N; (!r)()) else ()). We also use the standard derived syntax for sequential composition, i.e. M; N stands for let x = M in N, where x does not occur in N. For each term M, we write Meths(M) for the set of method names occurring in M. We use the same notation for method names in blocks and libraries.

Remark 19.
In Section 2 we used lock-related operations in our example libraries (acquire, tryacquire, release), on the understanding that they can be coded using shared memory. We assume that both acquire and release are blocking, while tryacquire is not. tryacquire makes an attempt to acquire the associated lock and returns 0 if the attempt was not successful or 1 otherwise. Similarly, the array of Example 18 in the sequel can be constructed using references.
For simplicity, we do not include private methods, yet the same effect could be achieved by storing them in higher-order references. As we explain in the next section, references present in library definitions are de facto private to the library.
Note also that, according to our definition, sets of abstract and public methods are disjoint. However, given m, m ∈ Refs θ,θ , one can define a "public abstract" method with: public m; abstract m ; m = λx θ .m x .
Terms are typed in environments = {x 1 : θ 1 , · · · , x n : θ n }. Method blocks are typed through judgements B B : Ψ , where Ψ ⊆ Meths. The judgements collect the names of methods defined in a block as well as making sure that the definitions respect types and are not duplicated. Also, the initialisation statements must comply with types.
Finally, we type libraries using statements of the form Ψ L L : Ψ → Ψ , where Ψ, Ψ , Ψ ⊆ Meths and Ψ ∩ Ψ = ∅. The judgement ∅ L L : Ψ → Ψ guarantees that any method occurring in L is present either in Ψ or Ψ , that all methods 6. . Evaluation rules for libraries (−→ lib ), terms (− → t ) and clients (= =⇒ ). In the rules above we use the conditions/notation: in Ψ are declared as abstract and unimplemented, while all methods in Ψ are declared as public and defined. Thus, ∅ L L : Ψ → Ψ is a library in which Ψ, Ψ are the abstract and public methods respectively. In this case, we also write L : Ψ → Ψ .

Semantics
The semantics of our system is given in several stages. First, we define an operational semantics for sequential and concurrent terms that may draw methods from a repository. We then adapt it to capture interactions of concurrent clients with closed libraries (no abstract methods). This notion is then used to define contextual approximation for arbitrary libraries. Finally, we introduce a trace semantics of arbitrary libraries, which generates the histories on which our notions of linearisability are based.

Library-client evaluation
Libraries, terms and clients are evaluated in environments comprising: • A method environment R, called own-method repository, which is a finite partial map on Meths assigning to each m in its domain, with m ∈ Meths θ,θ , a term of the form λy.M (we omit type-superscripts from bound variables for economy). • A finite partial map S : Refs (Z ∪ Meths), called store, which assigns to each r in its domain an integer (if r ∈ Refs int ) or name from Meths θ,θ (if r ∈ Refs θ,θ ).
The evaluation rules are presented in Fig. 6, where we also define evaluation contexts E.
Remark 20. We shall assume that reference names used in libraries are library-private, i.e. sets of reference names used in different libraries are assumed to be disjoint. Similarly, when libraries are being used by client code, this is done on the understanding that the references available to that code do not overlap with those used by libraries. Still, for simplicity, we shall rely on a single set Refs of references in our operational rules.
First we evaluate the library to create an initial repository and store. This is achieved by the first set of rules in Fig. 6, where we assume that S init is empty. Thus, library evaluation produces a tuple ( , R 0 , S 0 ) including a method repository and a store, which can be used as the initial repository and store for evaluating M 1 · · · M N using the (K N ) rule. We shall call the latter evaluation semantics for clients (denoted by = =⇒) the multi-threaded operational semantics. The latter relies on closed-term reduction (− → t ), whose rules are given in the middle group, where t is the current thread index. Note that the rules for E[λx.M] in the middle group, along with those for m = λx.M and r := λx.M in the first group, involve the creation of a fresh method name m, which is used to put the function in the repository R. Name creation is non-deterministic: any fresh m of the appropriate type can be chosen. We define termination for clients linked with libraries that have no abstract methods. Recall our convention (Remark 20) that L and M 1 , · · · , M N must access disjoint parts of the store. Terms M 1 , · · · , M N can share reference names, though.

Definition 21.
Let L : ∅ → Ψ and Ψ K M 1 · · · M N : unit. We say that M 1 · · · M N terminates with linked library L if We shall build a notion of contextual approximation of libraries on top of termination: one library will be said to approximate another if, whenever the former terminates when composed with any parameter library and client, so does the latter.
We will be considering the following notions for composing libraries. Let us denote a library L as L = D; B, where D contains all the (public/abstract) method declarations of L, and B is its method block. We write Refs(L) for the set of m n } ⊆ Ψ 2 and L : ∅ → Ψ 1 , Ψ , we define the union of L 1 and L 2 , the Ψ -hiding of L 1 , and the sequencing of L with L 1 respectively as: where D 1 is D 1 with any abstract m declaration removed for m ∈ Ψ 2 , dually for D 2 ; and where D 1 is D 1 without public m declarations for m ∈ Ψ and each r i is a fresh reference matching the type of m i , and B 1 is obtained from B 1 by replacing each m i = λx.M by r i := λx.M. Thus, the union of libraries L 1 and L 2 corresponds to merging their code and removing any abstract declarations for methods defined in the union. On the other hand, the hiding of a public method simply renders it private via the use of references. Sequencing allows for the following notion.
In this case, we also say that L 2 contextually refines L 1 .
Note that, according to this definition, the parameter library L may communicate directly with the client terms through a common interface Ψ . We shall refer to this case as the general case. Later on, we shall also consider more restrictive testing scenarios in which this possibility of explicit communication is removed. Moreover, from the disjointness conditions in the definitions of sequencing and linking we have that L i , L and M 1 · · · M N access pairwise disjoint parts of the store.

Remark 23.
Our ultimate goal will be to show that our notion of linearisability, written ¡, provides a sound method for proving contextual approximation/refinement, written ∼ . Recall that in order to establish L 1 ¡ L 2 , one has to exhibit a subset A 2 of sequential histories taken from JL 2 K such that L 1 is linearisable to A 2 , written L 1 ¡ A 2 .

Trace semantics
Building on the earlier semantics, we next introduce a trace semantics of libraries in the spirit of game semantics [14]. As mentioned in Section 2, the behaviour of a library will be represented as an exchange of moves between two players called P and O , representing the library and its corresponding context respectively. The context consists of the client of the library as well as the parameter library, with an index on each move (K/L) specifying which of them is involved in the move.
In contrast to the semantics of the previous section, we handle scenarios in which methods need not be present in the repository R. Calls to such undefined methods are represented by labelled transitions -calls to the context made on behalf of the library ( P ). The calls can later be responded to with labelled transitions corresponding to returns, made by the context (O ). On the other hand, O is able to invoke methods in R, which will also be represented through suitable labels.
Because we work in a higher-order setting, calls and returns made by both players may involve methods as arguments or results. Such methods also become available for future calls: function arguments/results supplied by P are added to the repository and can later be invoked by O , while function arguments/results provided by O can be queried in the same way as abstract methods. The trace semantics utilises configurations that carry more components than the previous semantics. We define two kinds of configurations: where the component E is an evaluation stack, that is, a stack of the form [X 1 , X 2 , · · · , X n ] with each X i being either an evaluation context or a method name. On the other hand, P = (P L , P K ) with P L , P K ⊆ dom(R) being sets of public method names, and A = (A L , A K ) is a pair of sets of abstract method names. P will be used to record all the method names produced by P and passed to O : those passed to O K are stored in P K , while those passed to O L are kept in P L . Inside A, the story is the opposite one: A K (A L ) stores the method names produced by O K (resp. O L) and passed to P . Consequently, the sets of names stored in P L , P K , A L , A K will always be disjoint.
given m ∈ P Y and (P).
(ORy) (m :: Given a pair P as above and a set Z ⊆ Meths, we write P ∪ K Z for the pair (P L , P K ∪ Z ). We define ∪ L in a similar manner, and extend it to pairs A as well. Moreover, given P and A, we let φ(P, A) be the set of fresh method names for P, We give the rules generating the trace semantics in Fig. 7. Note that the rules are parameterised by P /O and Y , which together determine the polarity of the next move; C /R, which stands for the move being a call (C) or a return (R) respectively. The rules depict the intuition presented above. When in an O -configuration, the context may issue a call to a public method m ∈ P Y and pass control to the library (rule (OCy)). Note that, when this occurs, the name m is added to the evaluation stack E and a P -configuration is obtained. From there on, the library will compute internally using rule (Int), until: it either needs to evaluate an abstract method (i.e. some m ∈ A Y ), and hence issues a call via rule (PCy); or it completes its computation and returns the call (rule (PRy)). Calls to abstract methods, on the other hand, are met either by further calls to public methods (via (OCy)), or by returns (via (ORy)).
Finally, we extend the trace semantics to a concurrent setting where a fixed number of N-many threads run in parallel.
Each thread has separate evaluation stack and term components, which we write as C = (E, X) (where X is a term or "−").
Thus, a configuration now is of the following form: is a sequential configuration. We shall abuse notation a little and write (C i , R, P, A, S) for (E i , X i , R, P, A, S). The concurrent traces are produced by the following two rules with the proviso that the names freshly produced internally in (PInt) are fresh for the whole of C.
We can now define the trace semantics of a library L. We call a configuration component C i final if it is in one of the following forms, for O -and P -configurations respectively: C i = ([], −) or C i = ([], ()) . We call ( C, R, P, A, S) final just if C = C 1 · · · C N and each C i is final.
For economy, in the sequel we might be dropping the index N from JLK N . We conclude the presentation of the trace semantics by providing a semantics for library contexts.
Recall that in our setting ( Fig. 1) a library L : Ψ → Ψ is deployed in a context consisting of a parameter library L : ∅ → Ψ, Ψ and a concurrent composition of client threads Ψ , Ψ M i : unit (i = 1, · · · , N). We shall write link L ; − in (M 1 · · · M N ), or simply C , to refer to such contexts.

Proofs of examples
With the definition of JLK in place, we can finally revisit the linearisability claims anticipated in Examples 1, 16 and 18. Recall the multiset library L mset and the specification A mset of Example 1 and Fig. 2. We show that L mset ¡ A mset . More precisely, taking an arbitrary history h ∈ JL mset K we show that h can be rearranged using * P O to match an element of A mset . We achieve this by identifying, for each O -move (t, x) O and its following P -move (t, x ) P in h, a linearisation point between them, i.e. a place in h to which (t, x) O can moved right and to which (t, x ) P can be moved left so that they become consecutive and, moreover, the resulting history is still produced by L mset . After all these rearrangements, we obtain a sequential history ĥ such that h ¡ĥ and ĥ is also produced by L mset . It then suffices to show that ĥ ∈ A mset .

Lemma 27 (Multiset). L mset linearises to A mset .
Proof. Given some h ∈ JL mset K, let us assume that h has been generated by a sequence ρ 1 ⇒ ρ 2 ⇒ · · · ⇒ ρ k of atomic transitions and that the variable F of L mset is instantiated with a reference r F . We demonstrate the linearisation points for pairs of (O , P ) moves in h, by case analysis on the moves (we drop K indices from moves as they are ubiquitous). Line numbers below refer to the LHS of Fig. 2: 1. h = · · · (t, call cnt(i)) O s (t, ret cnt(i )) P · · · . Here the linearisation point (LP) is the configuration ρ j that dereferences r F as per line 5 in L mset (the !F expression). 2. h = · · · (t, call upd(i, m)) O s (t, call m( j)) P · · · . The LP is the dereferencing of r F in line 5 (called from within update).
The LP is the dereferencing of r F in line 11.
Each of the linearisation points above specifies a P O -rearrangement of moves. For instance, for The selection of linearisation points is such that it guarantees that ĥ ∈ JL mset K. E.g. in case 1, the transitions occurring in thread t between (t, call cnt(i)) O and configuration ρ j do not access r F . Hence, we can postpone them and fire them in sequence just before ρ j . After ρ j+1 and until (t, ret cnt(i )) P there is again no access of r F in t and we can thus bring forward the corresponding transitions just after ρ j+1 . Similar reasoning applies to case 2. In case 4, we reason similarly but also take into account that rendering the acquisition of the lock by t atomic is sound (i.e. the semantics can produce the rearranged history). Case 3 is similar, but we also use the fact that the access to r F in lines 10-15 is inside the lock, and hence postponing dereferencing (line 11) to occur in sequence before update (line 13) is sound. Now, any transition sequence α which produces ĥ (in JL mult K) can be used to derive an annotated history h • ∈ A • mult , by attaching to each move in ĥ the multiset represented in the configuration that produces the move (ρ produces the move x if ρ x = =⇒ ρ in α). By projection we obtain ĥ ∈ A mult . P Here, we need a linearisation point for all four moves above. We pick this to be the point corresponding to the update of the multiset reference F on lines 24-25 (Fig. 2, RHS). We now transform h to ĥ so that the four moves become consecutive, in two steps: • Let us write s 3 as s 3 = s 1 3 s 2 3 , where the split is at the linearisation point. Since the lock is constantly held by thread t in s 2 s 1 3 , there can be no calls or returns to default in s 2 s 1 3 . Hence, all moves in s 2 s 1 3 are in component K and can be transposed with the L-moves above, using * , to obtain h = s (t, call reset(i)) O K s 1 s 2 s 1 3 (t, call default( j)) P L (t, ret default( j )) O L s 2 3 (t, ret reset(| j |)) P K · · · • Next, by P O -rearrangement we obtain ĥ = s s 1 s 2 s 1 To prove that ĥ ∈ A mult2 we work as in Lemma 27, i.e. via showing that ĥ ∈ JL mult2 K enc . For the latter, we rely on the fact that the linearisation point was taken at the reference update point (so that any dereferencings from other threads are preserved), and that the dereferencings of lines 22 and 23 are within the same lock as the update. P For our last example, recall the flat combination library L fc : ∅ → Ψ of Example 18, and Fig. 4, along with its specification library L spec : ∅ → Ψ , where Ψ = {run ∈ Meths (θ→θ )×θ,θ }.
Remark 29. It is worth observing that in the higher-order setting a client thread may try to call run, even though the previous call to run by the same thread did not complete yet. This scenario happens, for example, when the first call to run passes a functional argument to the library that itself calls run. Observe that in this case both L fc and L spec will deadlock. Consequently, non-trivial histories (all calls are matched by returns) arise only if each client thread uses run serially, i.e. without nesting.
Let R = < * , where < ⊆ H ∅,Ψ × H ∅,Ψ is the smallest relation such that (for economy we omit methods from calls/returns): for any s 1 , s 2 , s 3 , s 4 , s 5 such that s 2 , s 4 do not contain any t-moves.
Intuitively, < is about piecewise delegation of client computations to other existing threads subject to forming a correct history. Because the results do not change, this condition corresponds to thread-blind client behaviour.
Proof. Observe that histories from JL spec K feature threads built from segments of one of the three forms: where w is a name introduced in an earlier move (t , x) P and w is a corresponding name introduced by the move preceding (t , x) P in t , or • (t , ret w (v )) O (t , ret w(v )) P such that a segment (t , call w(v)) O (t , call w (v )) P already occurred earlier.
The first shape represents interaction of the client with the library: a call to run followed by a call to f , possibly some intermediate computation (using calls/returns to higher-order values that have been introduced in the trace), and a return of f followed by a return of run. The value introduced in the last return may well be a function, which -along with method names introduced earlier -provides method names that can be used in calls and returns later. As these methods are related to concrete functions, our trace semantics interprets them in a symbolic manner: each call is forwarded to the move preceding the one in which it was introduced. Note that threads can exchange higher-order values, so we need to allow for scenarios in which the three kinds of interaction are located in different threads.
We shall refer to moves in the second and third kind of segments as inspection moves and write φ to refer to sequences built exclusively from such sequences. Note that · · · in the first kind of block also stand for a segment of inspection moves in t.
Let us write X for the subset of JL spec K containing (sequential) plays of the form: where φ 2 j , φ 2 j+1 may also contain inspection moves not in t j . We take X to be our linearisation target (specification).
Consider h 1 ∈ JL fc K. Threads in h 1 are built from blocks of shapes: In the first case, the j's are meant to represent possibly different values used in each iteration. In the second kind of block, w needs to be introduced earlier by some (t , x) P move and w is then a name introduced by the preceding move. For the third kind, an earlier calling sequence of the second kind must exist in the same thread.
Observe that each segment S j = (t, call f j (x j ) P φ j (t, ret f j (v j )) O in t must be preceded (in h 1 ) by a matching public call (t , call run( f j , x j )) O followed by a corresponding return (t , ret run(v j )) P , where t need not be equal to t. We can obtain the requisite h (for ¡ R ) by changing t to t in the whole of S j for each S j . Note that run-moves are not affected and we get h 1 R * h.
Note that, due to locking and sequentiality of loops, the segments S j must be disjoint in h 1 , although they may be interleaved with inspection moves from other threads. We shall show how to obtain h 2 ∈ X with h * P O h 2 : • First the call to run associated with each S j should be moved right to immediately precede the renamed S j . Next the corresponding return of run should be move left to follow S j .
• Subsequently, inspection moves need to be rearranged to yield a sequential play. This can be done by permuting inspection moves by O to the left through other O actions from different threads until a P -move is encountered and moving the corresponding inspection move P left to immediately follow the O move.
Then we have h * P O h 2 and, hence, h 1 ( P O ∪ R) * h 2 . P

Soundness
To conclude, we clarify in what sense all the notions of linearisability are sound. Recall the general notion of contextual approximation (refinement) from Definition 22. In the encapsulated case libraries are being tested by clients that do not communicate with the parameter library explicitly. The corresponding definition of contextual approximation is defined below.

Definition 31 (Encapsulated ∼ ). Given libraries
For relational linearisability, we need yet another notion that will link R to contextual testing.

Definition 32. Let R ⊆ H Ψ,Ψ × H Ψ,Ψ be a set closed under permutation of names in Meths \ (Ψ ∪ Ψ ). We say that a context formed by
In what follows, we shall aim to establish three correctness results: Finally, we note that linearisability is compatible with library composition. ¡ is closed under union with libraries that use disjoint stores, while ¡ enc is closed under a form of sequencing that respects encapsulations (Appendix E).

Correctness
In this section we prove that the linearisability notions we introduce are correct: linearisability implies contextual approximation. The approach is based on showing that, in each case, the semantics of contexts is saturated relatively to conditions that are dual to linearisability. Hence, linearising histories does not alter the observable behaviour of a library. We start by presenting two compositionality theorems on the trace semantics, which will be used for relating library and context semantics.

Compositionality
The semantics we defined is compositional in the following ways: • To compute the semantics of a library L inside a context C , it suffices to compose the semantics of C with that of L, for a suitable notion of context-library composition (JC K JLK). • To compute the semantics of a union library L 1 ∪ L 2 , we can compose the semantics of L 1 and L 2 , for a suitable notion of library-library composition (JL 1 K ⊗ JL 2 K).
The above are proven using bisimulation techniques for connecting syntactic and semantic compositions, and are presented in Appendix C and Appendix D respectively. The latter correspondence is used in Appendix E for proving that linearisability is a congruence for library composition. From the former correspondence we obtain the following result, which we shall use for showing correctness.

General linearisability
Recall the general notion of linearisability defined in Section 2.2, which is based on move-reorderings inside histories.
In Proof. Recall that the same labelled transition system underpins the definition of X in either case. We make several observations about the single-threaded part of that system.
• The store is examined and modified only during -transitions.
• The only transition possible after a P -move is an O -move. In particular, it is never the case that a P -move is separated from the following O -move by an -transition.
Let us now consider the multi-threaded system and t = t .
lead us to the notion of linearisability defined in Definition 9. We now prove the main theorem of this subsection.
Proof. Unfortunately, some libraries generate only non-sequential histories. We present an example of such a library, call it L, in Fig. 8. Because of locks, the library from Fig. 8 will only allow two threads to complete a computation. Additionally, the first thread (i.e. the one that will increment r to 1) must wait until a second thread increments the internal counter r to 2.
Observe that if L does not generate any sequential histories then we vacuously have L ∼ L, but cannot have L ¡ L. We conjecture that a completeness result would be possible if we allowed for non-sequential specs in the definition of ¡.

Encapsulated linearisability
In this case libraries are being tested by clients that do not communicate with the parameter library explicitly.
Recall from Definition 31 that, given libraries L 1 , L 2 : Ψ → Ψ , we write L 1∼enc L 2 when, for all L : ∅ → Ψ and We call contexts of the above kind encapsulated, because the parameter library L can no longer communicate directly with the client, unlike in Definition 22, where they shared methods in Ψ . Consequently, Jlink L ; − in (M 1 · · · M N )K can be decomposed via parallel composition into two components, whose labels correspond to L (parameter library) and K (client) respectively.
Lemma 37 (Decomposition). Suppose L : ∅ → Ψ and Ψ K M 1 · · · M N : unit, where Ψ ∩ Ψ = ∅. Then, setting C ≡ link ∅ ; − in (M 1 · · · M N ), we have: However, by definition the latter copycat is done by L returning m (m ) to M, for some fresh name m , and recording internally that m → λx.m x. Hence, no methods of L can leak to M and encapsulation holds.
Because of the above decomposition, the context semantics satisfies a stronger closure property than that already specified in Lemma 34, which in turn leads to the notion of encapsulated linearisability of Definition 13. The latter is defined in term of the symmetric reordering relation , which allows for swaps (in either direction) between moves from different threads if they are tagged with K and L respectively. Moreover, we can show the following: Lemma 39 (Encapsulated saturation). Consider X = Jlink L ; − in (M 1 · · · M N )K (Definition 25). Then:  second claim and (t, x), (t, x ) is the earliest such violation in h, i.e. no violations occur in s 1 . Observe that then h restricted to moves of the form (t, z) X Y would not be alternating, which contradicts the fact that h Y is a history (Lemma 37). P Due to Theorem 33, the above property of contexts means that, in order to study termination in the encapsulated case, one can safely restrict attention to library traces satisfying a dual property to the one above, i.e. to elements of JLK enc . Note that JLK enc can be obtained directly from our labelled transition system by restricting its single-threaded part to reflect the switching condition. Observe that Theorem 33 will still hold for JLK enc (instead of JLK), because we have preserved all the histories that are compatible with context histories. We are ready to prove correctness of encapsulated linearisability.
Proof. Similarly to Theorem 35, except we invoke Lemma 39 instead of Lemma 34. P
Because C is R-closed by definition and closed under O P by Lemma 34, we have h 2 ∈ JCK. Because h 2 ∈ JL 2 K and h 2 ∈ JCK, we can conclude C [L 2 ] ⇓. P

Related and future work
Linearisability has been consistently used as a correctness criterion for concurrent algorithms on a variety of data structures [15], and has inspired a variety of proof methods [16]. An explicit connection between linearisability and refinement was made in [17], where it was shown that, in base-type settings, linearisability and refinement coincide. Similar results have been proved in [18][19][20]3]. Our contributions are notions of linearisability that serve as correctness criteria for libraries with methods of arbitrary order and have a similar relationship to refinement. The next natural target is to investigate proof methods for establishing linearisability of higher-order concurrent libraries. The examples proved herein are only an initial step in that direction.
At the conceptual level, [17] proposed that the verification goal behind linearisability is observational refinement. In this vein, [21] utilised logical relations as a direct method for proving refinement in a higher-order concurrent setting, while [22] introduced a program logic that builds on logical relations. On the other hand, proving conformance to a history specification has been addressed in [23] by supplying history-aware interpretations to off-the-shelf Hoare logics for concurrency. Other logic-based approaches for concurrent higher-order libraries, which do not use linearisability, include Higher-Order and Impredicative Concurrent Abstract Predicates [24,25]. [3] defines linearisation in the general case using a "big-step" relation that applies a single permutation to the whole sequence. This contrasts with our definition as * P O , in which we combine multiple adjacent swaps. We show that the two definitions are equivalent.

Definition 42 ([3]).
Let h 1 , h 2 ∈ H Ψ,Ψ of equal length. We write h 1 big P O h 2 if there is a permutation π : {1, · · · , |h 1 |} → {1, · · · , |h 2 |} such that, writing h i ( j) for the j-th element of h i : for all j, we have h 1 ( j) = h 2 (π ( j)) and, for all i < j: In other words, h 2 is obtained from h 1 by permuting moves in such a way that their order in threads is preserved and whenever a O -move occurred after an P -move in h 1 , the same must apply to their permuted copies in h 2 . • Suppose N < |h 2 | and consider h such that N = δ(h, h 2 ). We are going to arrive at a contradiction by exhibiting h ∈ X h 1 ,h 2 such that δ(h , h 2 ) > N.
Because N = δ(h, h 2 ) and N < |h 2 |, we have where t i = t, because order in threads must be preserved. Consider Proof. The relevant sequences of moves are clearly alternating and well-bracketed, when projected on single threads, because the LTS is bipartite (O -and P -configurations) and separate evaluation stacks control the evolution in each thread.
Other conditions for histories follow from the partitioning of names into A K , A L , P K , P L and suitable initialisation: Ψ, Ψ are inserted into A L , P K respectively (for JLK) and into P L , A K for JCK. P

Appendix C. Trace compositionality
In this section we demonstrate how the semantics of a library inside a context can be drawn by composing the semantics of the library and that of the context. The result played a crucial role in our arguments about linearisability and contextual refinement in Section 4.1.
Let us divide (reachable) evaluation stacks into two classes: L-stacks, which can be produced in the trace semantics of a library; and C -stacks, which appear in traces of a context. From here on, when we write E we will mean an L-stack or a C -stack. Moreover, we will call an N-configuration ρ an L-configuration (or a C -configuration), if ρ = ( C, · · · ) and, for each i, C i = (E i , · · · ) with E i an L-stack (resp. a C -stack).
Let ρ, ρ be N-configurations and suppose ρ = ( C, R, P, A, S) is a C -configuration and ρ = ( C , R , P , A , S ) an L-configuration. We say that ρ and ρ are compatible, written ρ ρ , if S and S have disjoint domains and, for each i: • If the public and abstract names of C i are (P L , P K ) and (A L , A K ) respectively, and those of C i are (P L , P K ) and (A L , A K ), then P L = A L , P K = A K , A L = P L and A K = P K .
• The private names of ρ (i.e. those in dom(R) \ P L \ P K ) do not appear in ρ , and dually for the private names of ρ .
• If C i = (E, · · · ) and C i = (E , · · · ) then E and E are in turn compatible, that is: -either E = m :: E :: E 1 , E = m :: E 1 and E 1 , E 1 are compatible, -or E = m :: E 1 , E = m :: E :: E 1 and E 1 , E 1 are compatible, Note, in particular, that if ρ ρ then ρ must be a context configuration, and ρ a library configuration.
We next define a trace semantics on compositions of compatible such N-configurations. We use the symbol for configuration composition: we call this external composition, to distinguish it from the composition of ρ and ρ we can obtain by merging their components, which we will examine later.

Retn
The Int rules above have side-conditions imposing that the resulting pairs of configurations are still compatible. Concretely, this means that the names created fresh in internal transitions do not match the names already present in the configurations of the other component. Note that external composition is not symmetric, due to the context/library distinction we mentioned.
Our next target is to show a correspondence between the above-defined semantic composition and the semantics obtained by (syntactically) merging compatible configurations. This will demonstrate that composing the semantics of two components is equivalent to first syntactically composing them and then evaluating the result. In order to obtain this correspondence, we need to make the semantics of syntactically composed configurations more verbose: in external composition methods belong either to the context or the library, and when e.g. the client wants to evaluate mm , with m a library method, the call is made explicit and, more importantly, m is replaced by a fresh method name. On the other hand, when we compose syntactically such a call will be done internally, and without refreshing m .
To counter-balance the above mismatch, we extend the syntax of terms and evaluation contexts, and the operational semantics of closed terms as follows. The semantics will now involve quadruples of the form: where the two repositories correspond to context and library methods respectively, so in particular dom(R 1 ) ∩ dom(R 2 ) = ∅.

Moreover, inside E[M]
we tag method names and lambda-abstractions with indices 1 and 2 to record which of the two components (context or library) is enclosing them: the tag 1 is used for the context, and 2 for the library. Thus e.g. a name m 1 signals an occurrence of method m inside the context. Tagged methods are passed around and stored as ordinary methods, but their behaviour changes when they are applied. Moreover, we extend (tagged) evaluation contexts by explicitly marking return points of methods: may not necessarily be a (tagged) term, due to the return annotations. The new reduction rules are as follows (we omit indices when they are not used in the rules). λy.m j y}, S) with m j , m j and v as above Above we write M i for the term M with all its methods and lambdas tagged (or re-tagged) with i. Moreover, we use the convention e.g. R 1 (m → λx.M) = (R 1 (m → λx.M), R 2 ). Note that the repositories need not contain tags as, whenever a method is looked up, we subsequently tag its body explicitly.
Thus, the computationally observable difference of the new semantics is in the rule for reducing E[m i v] when m is not in the domain of R i : this corresponds precisely to the case where e.g. a library method is called by the context with another method as argument. A similar behaviour is exposed when such a method is returning. However, this novelty merely adds fresh method names by η-expansions and does not affect the termination of the reduction.
Defining parallel reduction = =⇒ in an analogous way to = =⇒, we can show the following. We let a quadruple (M 1 · · · M N , R, S) be final if M i = () for all i, and we write (M 1 · · · M N , R, S) ⇓ if (M 1 · · · M N , R, S) can reduce to some final quadruple; these notions are defined for (M 1 · · · M N , R 1 , R 2 , S) in the same manner.

Lemma 47. For any legal
We now proceed to syntactic composition of N-configurations. Given a pair ρ 1 ρ 2 , we define a single quadruple corresponding to their syntactic composition, called their internal composition, as follows. Let ρ 1 = ( C, R 1 , P 1 , A 1 , S 1 ) and We let the internal composition of ρ 1 and ρ 2 be the quadruple: where k = 2 − (k mod 2).
We proceed to fleshing out the correspondence. We observe that an L-configuration ρ can be the final configuration of a trace just if all its components are O -configurations with empty evaluation stacks. On the other hand, for C -configurations, we need to reach P -configurations with terms (). Thus, we call an N-configuration ρ final if ρ = ( C, R, P, A, S) and either Let us write (S 1 , → 1 , F 1 ) for the transition system induced from external composition, and (S 2 , → 2 , F 2 ) be the transition system derived from internal composition: • S 1 = {ρ ρ | ρ ρ }, F 1 = {ρ ρ ∈ S 1 | ρ, ρ final}, and → 1 the transition relation −→ defined previously.
A relation R ⊆ S 1 × S 2 is called a bisimulation if, for all (x 1 , x 2 ) ∈ R: Given (x 1 , x 2 ) ∈ S 1 × S 2 , we say that x 1 and x 2 are bisimilar, written x 1 ∼ x 2 , if (x 1 , x 2 ) ∈ R for some bisimulation R.
Recall we write h for the O /P complement of the history h. We can now prove Theorem 33, which states that the behaviour of a library L inside a context C can be deduced by composing the semantics of L and C .
Proof. Let C be the context link L ; − in (M 1 · · · M N ), and suppose (L) −→ * lib ( , We pick these as the initial N-configurations for JLK N and JCK respectively. Moreover, we have that ( n}, assuming Ψ = {m 1 , · · · , m n } and r 1 , · · · , r n are fresh references of corresponding types. Hence, the initial triple for JC[L]K is taken to Then, for the forward direction of the claim, from φ 0 ⇓ we obtain that ρ 0 ⩕ ρ 0 ⇓. From the previous lemma, we have that so does ρ 0 ρ 0 . From the latter reduction we obtain the required common history. Conversely, suppose h ∈ JLK N and h ∈ JCK. WLOG, assume that Meths(h) ∩ (dom(R 0 ) ∪ dom(R 0 )) ⊆ Ψ ∪ Ψ 1 ∪ Ψ (we can appropriately alpha-covert R 0 and R 0 for this). Then, ρ 0 and ρ 0 both produce h, with opposite polarities. By definition of the external composite reduction, we then have that ρ 0 ρ 0 reduces to some final state. By the previous lemma, we have that ρ 0 ⩕ ρ 0 reduces to some final quadruple, which in turn implies that φ 0 ⇓, i.e. link L ; L in (M 1 · · · M N ) ⇓. P We conclude this section with the proofs of the last two lemmata used.

C.1. Proof of Lemma 47
We purpose to show that, for any legal ( We prove something stronger. For any repository R whose  We next define a notion of indexed bisimulation between the transition systems produced from quadruples and triples respectively. Given an expansion class R, a relation R R between quadruples and triples is called an R-bisimulation if, whenever φ 1 R R φ 2 : Thus, Lemma 47 directly follows from the next result.
Lemma 49. For all expansion classes R, the relation Proof. Suppose φ R R φ #R . We note that finality conditions are satisfied: if φ is final then so is φ #R ; while if φ #R is final then all its contexts are from the grammar: In case the reduction is not a function call or return, then it can be clearly simulated by φ #R . Otherwise, suppose: by the way the semantics was defined, so φ #R = φ #R .
On the other hand, if R(m) = λx.m x then: • Finally, the cases for method-return reductions are treated similarly as above.
The size-function we use measures the length of G(R)-paths that appear inside its arguments: where X 1 is the multiset containing all occurrences of methods m ∈ dom(R) inside E[M] in call position (e.g. mM ), and X 2 contains all occurrences of methods m ∈ dom(R) inside E[M] in return position (i.e. m i · · · ). We write |m| R for the length of the unique directed path from m to a leaf in G(R). The fact that X 1 , X 2 are multisets reflects that we count all occurrences of m in call/return positions. Suppose WLOG that the reduction to φ is due to some (E 1 Let φ be the extension of φ 1 to an N-quadruple by using the remaining E i [M i ]'s of φ, so that φ = =⇒ φ . In the first case above we have that φ #R = φ, and in the latter that φ #R = φ (with R = R {m j → λx.m j x | 1 ≤ j ≤ k}), and we appeal to the IH.
Suppose now that m = m and R 12 (m) = λx.M. Then, one of the following is the case: Extending φ 1 to φ as above, in the former case we then have that φ #R = φ , and in the latter that φ #R = φ , as required.
Finally, let us suppose that M 1 is some value v. Then, we can write E 1 as and hence, extending φ 1 to φ , we have φ #R = φ #R . We can now appeal to the IH. P
Otherwise, similarly as above, the reduction can be simulated by a mutual call/return of m.
Finally, it is clear that ρ 1 ρ 2 is final iff ρ 1 ⩕ ρ 2 is final. P History composition is a partial function: if the conditions above are not met, or h 1 , h 2 , σ are not of the appropriate form, then the composition is undefined. The above conditions ensure that the composed histories are indeed compatible and can be produced by composing actual libraries. For instance, the last condition corresponds to determinacy of threads: there can only be at most one component starting with a P -move in each thread t. We then have the following correspondence: Theorem 50. Let L 1 : Ψ 1 → Ψ 2 and L 2 : Ψ 1 → Ψ 2 be libraries accessing disjoint parts of the store. Then, The rest of this section is devoted in proving the Theorem.
Recall that we examine library composition in the sense of union of libraries. This scenario is more general than the one of Appendix C as, during composition via union, the calls and returns of each of the component libraries may be caught by the other library or passed as a call/return to the outer context. Thus, the setting of this section comprises given libraries L 1 : Ψ 1 → Ψ 2 and L 2 : Ψ 1 → Ψ 2 , such that Ψ 2 ∩ Ψ 2 = ∅, and relating their semantics to that of their union Given configurations for L 1 and L 2 , in order to be able to reduce them together we need to determine which of their methods can be used for communication between them, and which for interacting with the external context, which represents player O in the game. We will therefore employ a set of method names, denoted by and variants, to register those methods used for interaction with the external context. Another piece of information we need to know is in which component in the composition was the last call played, or whether it was an internal call instead. This is important so that, when O (or P ) has the choice to return to both components, in the same thread, we know which one was last to call and therefore has precedence. We use for this purpose sequences w = (w 1 , · · · , w N ) where, for each i, w i ∈ {0, 1, 2} * . Thus, if e.g. w 1 = 2w 1 , this would mean that, in thread 1, the last call to O , was done from the second component; if, on the other hand, w 1 = 0w 1 then the last call in thread 1 was an internal one between the two components. Given such a w and some j ∈ {0, 1, 2}, for each index t, we write j + t w for w[t → ( jw t )].
• If C i = (E, · · · ) and C i = (E , · · · ) then E and E are w i -compatible, that is, either E = E = [] or: -E = m :: E 1 and E ∈ E L , with m ∈ , w i = 1u and E 1 , E are u-compatible, -or E = m :: E 1 and E = m :: E :: E 2 , with m ∈ P, w i = 0u and E 1 , E 2 are u-compatible, -or E = m :: E :: E 1 and E ∈ E L , with m ∈ \ P, w i = 1u and E 1 , E are u-compatible, or the dual of one of the three conditions above holds.
Given ρ 1 w ρ 2 , we let their external composition be denoted as ρ 1 ⊗ w ρ 2 (and note that now the notation is symmetric for ρ 1 and ρ 2 ) and define the semantics for external composition by these rules: We can now show the following.
We next juxtapose the semantics of external composition to that obtained by internally composing the libraries and then deriving the multi-threaded semantics of the result. As before, we call the latter form internal composition. The traces we obtain are produced from a transition relation, written = =⇒ , between configurations of the form (C 1 · · · C N , R 1 , R 2 , P, A, S), also written ( C, R, P, A, S). In particular, in each For each pair ρ 1 w ρ 2 , we define a configuration corresponding to their syntactic composition as follows. Let ρ 1 = (C 1 · · · C N , R 1 , P 1 , A 1 , S 1 ) and ρ 2 = (C 1 · · · C N , R 2 , P 2 , A 2 , S 2 ) and, for each i, We then let the internal composition of ρ 1 and ρ 2 be: . Now, as expected, the definition of = =⇒ builds upon − → t . The definition of the latter is given by the following rules.
The other case is treated in the same manner, and we work similarly for (Retn 1 ).
• On the other hand, if the transition is due to (Call) or (Retn) then we work as in the proof of Lemma 48.
Then, assuming WLOG that v ∈ Meths, one of the following must be the case, for some x ∈ {K, L} and i ∈ {1, 2}: We only examine the former case, as the latter one is similar, and suppose that i = 1. Taking ρ j = (C j 1 · · · , R j , P j , A j , S i ), for j = 1, 2, we have that (C 1 1 , and ρ 1 ⩕ w ρ 2 = (C 1 · · · , R , P , A , S) as required. The case for return transitions is similar. • On the other hand, if the transition out of ρ 1 ⩕ w ρ 2 does not have a label then we work as in the proof of Lemma 48.
Moreover, by definition of syntactic composition, ρ 1 ⊗ w ρ 2 is final iff ρ 1 ⩕ w ρ 2 is. P Given an N-configuration ρ and a history h, let us write ρ ⇓ h if ρ h = =⇒ ρ for some final configuration ρ . Similarly if ρ is of the form ( C , R, P, A, S). We have the following connections in history productions. The next lemma is proven in a similar fashion as Lemma 47.
Proof. We show that, for any compatible N-configurations ρ 1 w ρ 2 and history suffix s, (ρ 1 ⊗ w ρ 2 ) ⇓ s iff: where P is computed from ρ 1 , ρ 2 and as in the beginning of this section.
The left-to-right direction follows from straightforward induction on the length of the reduction that produces s. For the right-to-left direction, we do induction on the length of σ . If σ = then s 1 = s 2 = s = . Otherwise, we do a case analysis on the first element of σ . We only look at the most interesting subcase, namely of σ = 0σ . Then, for some m ∈ P: s 1 = (t, call m(v))s 1 s 2 = (t, call m(v))s 2 By ρ i ⇓ s i and ρ 1 w ρ 2 we have that ρ 1 ⊗ w ρ 2 −→ ρ 1 ⊗ w ρ 2 , where w = 0 + t w and ρ 1 w ρ 2 . Also, ρ i ⇓ s i and s = s 1 ⩕ σ ,P s 2 so, by IH, (ρ 1 ⊗ w ρ 2 ) ⇓ s. P We can now prove the correspondence between the traces of component libraries and those of their union.
Proof. Assume L 1 ¡ L 2 and suppose h 1 ∈ JL ∪ L 1 K. By Theorem 50, h 1 = h ⩕ σ ,P h 1 , where h ∈ JLK and h 1 ∈ JL 1 K. Because L 1 ¡ L 2 , there exists h 2 ∈ JL 2 K such that h 1 ¡ h 2 , i.e. h 1 * P O h 2 . Note that some of the rearrangements necessary to transform h 1 into h 2 may concern actions shared by h 1 and h ; their polarity will then be different in h . Let h be obtained by applying such rearrangements to h . We claim that h * O P h . Indeed, suppose that (t , x )(t, x) P are consecutive in h 1 , but swapped in order to obtain h 2 , and (t, x) P appears in h as (t, x) O . Now, the move (t , x ) either appears in h 1 , or it appears in h and gets hidden in h 1 . In every case, let s contain the moves of h that are after (t , x ) in the composition to h 1 , and before (t, x) O . We have that s(t, x) O is a subsequence of h and h * O P h holds just if s contains no moves from t. But, if s contained moves from t then the rightmost one such would be some (t, y) P . Moreover, in the composition towards h 1 , the move would be scheduled with 1. The latter would break the conditions for trace composition as, at that point, the corresponding subsequence of h 1 has as leftmost move in t the P-move (t, x) P . We can show similarly that h * O P h holds in the case that the permutation in h 1 is on consecutive moves (t, x) O (t , x ). Finally, the rearrangements in h 1 that do not affect moves shared with h can be treated in a simpler way: e.g. in the case of (t , x )(t, x) P consecutive in h 1 and swapped in h 2 , if (t, x) P does not appear in h then we can check that h cannot contain any t-moves between (t , x ) and (t, x) as the conditions for trace composition impose that only O is expected to play in that part of h (and any t-move would swap this polarity). Now, since h ∈ JLK, Lemma 34 implies h ∈ JLK. Take h 2 to be h ⩕ σ ,P h 2 , where σ is obtained from σ following these move rearrangements. We then have h 2 ∈ JL ∪ L 2 K. Moreover, h 1 ¡ h 2 thanks to h 1 ¡ h 2 . Hence, h 2 ∈ JL ∪ L 2 K and h 1 ¡ h 2 . Thus, L ∪ L 1 ¡ L ∪ L 2 . P We next examine the behaviour of ¡ enc with respect to library composition. In contrast to general linearisability, we need to restrict composition for it to be compatible with encapsulation.
Remark 56. The general case of union does not conform with encapsulation in the sense that encapsulated testing of L ∪ L i (i = 1, 2) according to Definition 31 may subject L i to unencapsulated testing. For example, because method names of L and L i are allowed to overlap, methods in L may call public methods from L i as well as implementing abstract methods from We now see that h i / ∈ JL i K enc as in the last move O is changing component from K to L.
Proof. Let us consider the first sequencing case (the second one is dual), and assume that L 1 , L 2 : Ψ → Ψ and L : Ψ → Ψ . Assume L 1 ¡ enc L 2 and suppose h 1 ∈ JL ; L 1 K enc . By Theorem 50, h 1 = h ⩕ σ ,P h 1 , where h ∈ JLK, h 1 ∈ JL 1 K and method calls from Ψ are always scheduled with 0. The fact that O cannot switch between L/K components in (threads of) h 1 implies that the same holds for h , h 1 , hence h ∈ JLK enc and h 1 ∈ JL 1 K enc . Because L 1 ¡ enc L 2 , there exists h 2 ∈ JL 2 K enc such that h 1 ¡ h 2 , i.e. h 1 ( P O ∪ ) * h 2 . As before, some of the rearrangements necessary to transform h 1 into h 2 may concern actions shared by h 1 and h ; we need to check that these can lead to compatible h ∈ JLK enc . Let h be obtained by applying such rearrangements to h . We claim that h * O P h . The transpositions covered by P O are treated as in Lemma 55. Suppose now that (t , x ) P K (t, x) O L are consecutive in h 1 but swapped in order to obtain h 2 , and (t, x) O L appears in h as (t, x) P K . Now, the move (t , x ) cannot appear in h as it is in L 1 's K-component (L is the L-component of L 1 ). Let s contain the moves of h that are after (t , x ) in the composition to h 1 , and before (t, x) P K . We claim that s contains no moves from t, so h can be directly composed with h 2 as far as this transposition is concerned. Indeed, if s contained moves from t then, taking into account the encapsulation conditions, the leftmost one such would be some (t, y) O K . But the K-component of L is L 1 , which contradicts the fact that the moves we consider are consecutive in h 1 . Hence, taking h 2 to be h ⩕ σ ,P h 2 , where σ is obtained from σ following the P O move rearrangements, we have h 2 ∈ JL ; L 2 K enc and h 1 ¡ enc h 2 . Thus, L ; L 1 ¡ enc L ; L 2 .
The case of L L 1 ¡ enc L L 2 is treated in a similar fashion. In this case, because of disjointness, the moves transposed in h 1 do not have any counterparts in h . Again, we consider consecutive moves (t , x ) P K (t, x) O L in h 1 that are swapped in order to obtain h 2 . Let s contain the moves of h that are after (t , x ) in the composition to h 1 , and before (t, x). As Ψ 1 , Ψ 1 is first-order, (t, x) O L must be a return move and the t-move preceding it in h 1 must be the corresponding call. The latter is a move in h 1 , which therefore implies that there can be no moves from t in s. Similarly for the other transposition case. P