Session Types at the Mirror
We (re)define session types as projections of process behaviors with respect to the communication channels they use. In this setting, we give session types a semantics based on fair testing. The outcome is a unified theory of behavioral types that shares common aspects with conversation types and that encompass features of both dyadic and multi-party session types. The point of view we provide sheds light on the nature of session types and gives us a chance to reason about them in a framework where every notion, from well-typedness to the subtyping relation between session types, is semantically – rather than syntactically – grounded.
The leitmotif in the flourishing literature on session types [15, 16, 17] is to associate every communication channel with a type that constraints how a process can use that channel. In this paper we take the opposite perspective: we define the session type associated with a channel as the projection of the behavior of the processes restricted to how that channel is used by them. As expected, this approach requires a language of session types that is more general than the ones we usually encounter in other works. But – this is in summary the contribution of this work – the language we come up with is just a minor variation of well-known value-passing process algebras that can be semantically characterized using well-known concepts and techniques.
To get acquainted with our approach, let us consider the following example written in -calculus like language and which is a slightly simplified variant of the motivating example in :
Here we have two buyers that collaborate with each other in order to complete a transaction with a seller. Buyer1 creates a local channel that it sends to Seller through the public channel . The channel is normally dubbed session: it is a fresh channel shared by Buyer1 and Seller on which the two can communicate privately. On , Buyer1 sends to the Seller the name of a book, and Seller answers with its price. At this stage Buyer1 asks for the collaboration of Buyer2: it creates another fresh channel which it communicates to Buyer2 by means of the public channel , it sends Buyer2 the amount of money Buyer2 should contribute, and finally it delegates the private channel to Buyer2, so that Buyer2 can complete the transaction with the Seller. This implies sending the Seller a delivery address and receiving the estimated delivery date.
Let us focus on the public channels and : the former is used by Buyer1 for sending a channel of some type, say , and is used by Seller for receiving a channel of the same type. In our approach we say that the type of is , where is the projected behavior of Seller on , is the projected behavior of Buyer1 on , and denotes the composition of these two behaviors. In a similar way, is used by Buyer1 and Buyer2 and has type , assuming that the channel exchanged between Buyer1 and Buyer2 has type . Channel is more interesting: it is created by Buyer1, which uses it according to the type . However, is delegated to Seller right after its creation, and to Buyer2 when Buyer1 has finished using it. So, the true type of is where is the projection of Seller’s behavior with respect to the channel (after it has been received by Seller), and is the projection of Buyer2’s behavior with respect to the same channel after it has been received by Buyer2. By similar arguments, one can see that the type of is and the mentioned types , , and are defined as , , and , respectively. If we were to depict the projection we have operated for typing the channels in the example, we could summarize it as follows:
Can we tell whether the system composed of Seller and the two buyers “behaves well”? Although at this stage we have not given a formal semantics to session types, by looking at the types for the various channels involved in the example we can argue that they all eventually “reduce” to a parallel composition of ’s. If we read the type as the fact that a process stops using a channel with that type, this roughly indicates that all the conversations initiated in the example eventually terminate successfully.
The projection we have operated abstracts away from the temporal dependencies between communications occurring on different channels. This is a well-known source of problems if one is interested in global progress properties. In our approach, and unlike other presentations of session types, we do not even try to impose any linearity constraint on the channels being used, nor do we use polarities  or indexes [17, 2] for distinguishing different roles. For example, the process Buyer1 keeps using channel after it has been delegated, and it delegates the channel once more before terminating. As a consequence, the projection we operate may not even capture the temporal dependencies between communications occurring on the same channel. This can happen if two distinct free variables are instantiated with the same channel during some execution. Thus, we must impose additional constraints on processes only to ensure the type preservation property. Interestingly, we will see that these additional constraints are similar to those used for ensuring global progress [10, 2, 4].
We can identify three main contributions of this work: (1) we show that session types can be naturally generalized to an algebraic language of processes that closely resembles value-passing ccs; (2) as a consequence, we are able to work on session types reusing a vast toolkit of known results and techniques; in particular, we are able to semantically justify the fundamental concepts (duality, well-typedness, the subtyping relation) that are axiomatically or syntactically presented in other theories; (3) we provide a unified framework of behavioral types that encompasses features not only of dyadic and multi-party session types, but also of conversation types .
Structure of the paper.
In Section 2 we define session types as a proper process algebra equipped with a labeled transition system and a testing semantics based on fair testing. This will immediately provide us with a semantically justified equivalence relation – actually, a pre-order – to reason about safe replacement of channels and well-behaving systems. In Section 3 we formally define a process language that is a minor variant of the -calculus without any explicit construct that is dedicated to session-oriented interaction. We will show how to type processes in this language and illustrate the main features of the type system with several examples. Finally, we will state the main properties (type preservation and local progress) of our typing relation. Section 4 concludes.
Theories of dyadic session types can be traced back to the works of Honda  and Honda et al. . Since then, the application of session types has been extended to functional languages [21, 13] and object-oriented languages (see [11, 9] for just a few examples). A major line of research is the one dealing with so-called multi-party session types, those describing sessions where multiple participants interact simultaneously [17, 2]. An in depth study of a subtyping relation for session types can be found in , while  provides an incremental tutorial presentation of the most relevant features of dyadic session types.
Conversation types  are a recently introduced formalism that aims at generalizing session types for the description of the behavior of processes that interact within and across the scope of structurally organized communications called conversations. Conversation types are very similar to the language of session types we propose here, for example they embed a parallel composition operator for representing the composed behavior of several processes simultaneously accessing a conversation. The difference with our approach mainly resides in the semantics of types: we treat session types as terms of a proper process algebra with a proper transition relation and all the relevant notions on types originate from here. In , the semantics of conversation types is given in terms of syntactically-defined notions of subtyping and merging. Also,  uses a process language that incorporates explicit constructs for dealing with conversations, while we emphasize the idea of projected behavior by working with the naked -calculus.
Elsewhere  we have been advocating the use of a testing approach in order to semantically justify session types. Unlike , here we disallow branch selection depending on the type of channels. This reduces the expressiveness of types for the sake of a simplification of the technicalities in the resulting theory. Another difference is that in the present paper we adopt a fair testing approach .
2 Syntax and semantics of session types
Let us fix some conventions: , , , …range over session types; , …range over actions; , , …range over types; , …range over an unspecified set of basic values; , …range over an unspecified set of basic types such as , , , and so on. The syntax of session types is defined by the grammar in Table 1. Types represent sets of related values: is the empty type, the one inhabited by no value; basic types are arbitrary subsets of ; for every we write for the singleton type whose only value is itself. We will write to state that inhabits type and we will sometimes say that is of type .
Actions represent input/output operations on a channel. An action represents the sending of an arbitrary value of type ; an action represents the receiving of an arbitrary value of type ; actions and are similar but they respectively represent the sending and receiving of a channel of type .
Although session types are used to classify channels, they describe the behavior of processes using those channels. Consistently with this observation, we will often present session types as characterizing processes rather than channels. In the explanation that follows, it is useful to keep in mind that, when a process uses a channel according to some protocol described by a session type, it expects to interact with other processes that use the same channel according to other protocols. For a communication to occur, the process must perform an action on the channel (say, sending a value of some type), and another process must perform the corresponding co-action (say, receiving a value of the same type). The session type classifies a channel on which a communication error has occurred. No correct system should ever involve channels typed by , and we will see that it is useful to have an explicit term denoting a static error. The session type describes a process that performs no further action on a channel. The session type describes a process that performs the action , and then behaves according to the protocol . The session type is the external choice of and and describes a process that offers interacting processes to behave according to one of the branches. Dually, the session type is the internal choice of and and describes a process that internally decides to behave according to one of the branches. The session type describes the simultaneous access to a shared channel by two processes behaving according to and .111We use the word “shared” to highlight the fact that two (or more) processes simultaneously act on the same channel. This should not be confused with the terminology used in different session type theories, where “shared channels” are publicly known channels on which sessions are initiated. If we have processes sharing a common channel and each process behaves according to some protocol , then describes the overall protocol implemented by the processes on the channel.
We do not rely on any explicit syntax for describing recursive behaviors. We borrow the technique already used in  and define the set of session types as the set of possibly infinite syntax trees generated by the productions of the grammar in Table 1 that satisfy the following conditions:
the tree must contain a finite number of different subtrees;
on every infinite branch of the tree there must be infinite occurrences of the action prefix operator;
the tree must contain a finite number of occurrences of the parallel composition operator.
The first condition is a standard regularity condition imposing that the tree must be a regular tree . The second one is a contractivity condition ruling out meaningless regular trees such as those generated by the equations or . Finally, it can be shown that the last condition enforces that the protocol described by a session type is “finite state”.
To familiarize with session types consider the following two examples:
describes a process that waits for either an integer number or a Boolean value. If the process receives an integer number, it sends a string; if the process receives a Boolean value, it sends a real number. After that, in either case, the process stops using the channel. Instead, the session type describes a process that internally decides whether to send an integer or a Boolean value.
It may seem that the syntax of session types is overly generic, and that external choices make sense only when they are guarded by input actions and internal choices make sense only when they are guarded by output actions. As a matter of facts, this is a common restriction in standard session type presentations. In our approach, this generality is actually necessary: a session type describes two processes trying to simultaneously send an integer and a Boolean value on the same channel. A process interacting with these two parties is allowed to read both values in either order, since both are available. In other words, the session type is equivalent to , that is the interleaving of the actions in . Had we expanded to instead, no interacting process would be able to decide which value, the integer or the Boolean value, to read first. The ability to express parallel composition in terms of choices is well studied in process algebra communities where it goes under the name of expansion law [8, 14]. This ability is fundamental in order to define complete proof systems and algorithms for deciding equivalences. Decidability issues aside, we envision two more reasons why this generality is appealing: first, it allows us to express the typing rules (Section 3) in a more compositional way, which is particularly important in our approach where we aim at capturing full, unconstrained process behaviors; second, it clearly separates communications (represented by actions) from choices, thus yielding a clean, algebraic type language with orthogonal features.
We equip session types with an operational semantics that mimics the actions performed by processes behaving according to these types. The labeled transition system of session types is defined by the rules in Table 2 plus the obvious symmetric rules of those concerning choices and parallel composition. Transitions make use of labels ranged over by , …and generated by the grammar:
Strictly speaking, the transition system is defined by two relations: a labeled one describing external, visible actions and an unlabeled one describing internal, invisible actions. Thus, the transition system is an extension of the one of ccs without ’s  to a value-passing calculus. Rule (r1) states that the session type emits a single action denoting successful termination of the protocol, and reduces to itself. By rule (r2), the session type can perform an internal transition to either or . Rules (r3) and (r4) deal with output actions. The session type emits the value and reduces to . Similarly, emits a signal (the output of a channel of type ). Rule (r5) is the dual of rule (r4) and states that emits a signal (the input of a channel of type ). Rule (r6) states that a process behaving according to internally chooses a value of type to send, and once has committed to such a value it reduces to . Rule (r7) is the dual of rule (r3), but because of rule (r6) observe that a process behaving according to commits to sending one particular value of type , whereas a process behaving according to is able to receive any value of type . Rule (r8) states that is indeed an external choice, thus internal choices in either branch do not preempt the other branch. This is a typical reduction rule for those languages with two different choices, such as ccs without ’s . Rules (r9) and (r10) state obvious reductions for external choices, which offer any action that is offered in either branch, and parallel compositions, which allow either component to internally evolve independently. Rule (r11) states that any action other than is offered by a parallel composition whenever it is offered by one of the components; rule (r12) states that a parallel composition has successfully terminated only if both components have; rule (r13) states the obvious synchronization between components offering dual actions. Rule (r14) states that a process sending a channel of type can synchronize with another process willing to receive a channel of type , but only if . Here is a subtyping relation meaning that any channel of type can be used where a channel of type is expected. We shall formally define in a moment; for the time being we must content ourselves with this intuition. Rule (r15) states that if the relation is not satisfied, the synchronization occurs nonetheless, but it yields an error.
Before we move on to the subtyping relation for session types, we should point out a fundamental design decision that relates communication and external choices. On the one hand, values other than channels may drive the selection of the branch in external choices. For example, we have while . The type of the value determines the branch, and this feature allows us to model the label-driven branch selection that is found in standard session types theories. On the other hand, the last two rules in Table 2 show that branch selection cannot be affected by the type of the channel being communicated. It is true that and , but when we compose with either reduction is possible, and the residual may or may not be depending on the relation between , , and :
To be sure that the residual is not , it must be the case that and . In summary, we do not allow dynamic dispatching according to the type of a channel, namely all channels are treated as if they had the same type. This is not the only possible choice (see  for an alternative), but is one that simplifies the theory.
In the following we adopt standard conventions regarding the transition relations: we write for the reflexive, transitive closure of ; we write (respectively, ) if there exists such that (respectively, ); we write , , for the usual negated relations; for example, means that does not perform internal transitions.
The first semantic characterization we give is that of complete session type, namely a session type that can always reach a successful state, no matter of its internal transitions.
Definition 2.1 (completeness).
We say that is complete if implies .
Intuitively, a complete protocol is one implemented by processes which can always terminate successfully their interaction, without the help of any other process. Observe, as a side note, that completeness implies that no evolution of the system may yield an error or lead to a state where one process insists on sending a message that no interacting party is willing to accept. is the simplest complete session type; the session types and we have seen in the introduction are also complete, since every maximal transition leads to a successfully terminated state. The simplest example of incomplete session type is , another example being because of the maximal reduction . If we take as the solution of the equation and as the solution of the equation we have that is not complete, despite it never reaches a deadlock state. In this sense the notion of completeness embeds a fairness principle that is typically found in fair testing theories .
Completeness is the one notion that drives the rest of the theory. We define the subtyping relation for session types, which we call subsession, as the relation that preserves completeness: is “smaller than” if every session type that completes completes as well.
Definition 2.2 (subsession).
We say that is a subsession of , notation , if complete implies complete for every . We write for the equivalence relation induced by , namely .
In other words, we are defining an equivalence relation for session types based on (fair) testing : we use completeness as the notion of test, and we say that two session types are equivalent if they pass the same tests. As a consequence, the equational theory generated by this definition is not immediately obvious, although a few relations are easy to check: for example, , , and are commutative, associative operators; is neutral for and is neutral for ; furthermore . Namely, it is safe to use a channel with type where another one of type is expected. If the safety property mentioned here seems hard to grasp, one should resort to the intuition that the “type” of a channel actually is the behavior of a process communicating on that channel. A process that expects to receive a channel with type will behave on that channel according to ; if we send that process a channel with type , the receiving process will still behave according to , which is a more deterministic behavior than , hence no problem may arise. As a special case of reduction of nondeterminism, we have assuming that is a subtype of . Other useful relations are those concerning failed processes: we have and . More generally, the relation means that there is no session type such that is complete: is intrinsically flawed and cannot be remedied. The class of non-flawed session types will be of primary importance in the following, to the point that we reserve them a name.
Definition 2.3 (viability).
We say that is viable if is complete for some .
At this stage we can appreciate the fact that subsession depends on the transition relation, and that the transition relation depends on subsession. This circularity can be broken by stratifying the definitions: a session type is given weight if it contains no prefix of the form or ; a session type is given weight if any session type in any prefix of the form or occurring in has weight at most . By means of this stratification, one can see that the definitions of the transition relation and of subsession are well founded. ∎
It is fairly easy to see that is a precongruence with respect to action prefix, internal choice, and parallel composition. The case of the action prefix is trivial. As regards the internal choice, it suffices to observe that is complete if and only if both and are complete. Namely, corresponds to a set-theoretic intersection between session types that complete and . As regards the parallel composition, the precongruence follows from the very definition of subsession, since if complete implies complete, namely if complete implies complete, that is if . Because all the non-viable session types are -equal, however, is not a precongruence with respect to the external choice. For example, we have but . This is a major drawback of the subsession relation as it is defined, since it prevents from being used in arbitrary contexts for replacing equals with equals (note that is not a congruence for the same reasons). We resort to a standard technique for defining the largest relation included in that is a precongruence with respect to the external choice. We call this relation strong subsession:
Definition 2.4 (strong subsession).
Let be the largest relation included in that is a precongruence with respect to , namely if and only if for every . We write for the equivalence relation induced by , namely .
We end this section with a few results about and . First of all, we can use for reasoning about viability and completeness of a session type:
The following properties hold:
is not viable if and only if ;
is complete if and only if .
Then, we prove that and are almost the same relation, in the sense that they coincide as soon as the smaller session type is viable. This means that for all practical purposes the use of in place of is immaterial, if not for the gained precongruence, since in no case we will be keen on replacing a channel with a viable type with one that is not viable.
if and only if either or .
It is interesting to compare with the subtyping relation for session types in . From a technical point of view, the two relations arise in completely different ways: arises semantically as a relation between session types that preserves completeness; the subtyping relation in  is defined (co)inductively and by cases on the syntax of session types being related. The essence of this latter relation is strictly connected with the direction of the exchanged messages: when holds, sends more things and receives fewer, regardless of whether such things are labels or actual data. In contrast the relation is fundamentally determined by reduction of nondeterminism, which is captured by the law . Note that this law does not say anything about messages being sent or received. For example, we have but also . We can identify two other significant differences: the first one is that in our theory of session types, the successfully terminated session type can be composed with actions. For example, describes a process that is waiting for an integer, but is also perfectly happy to terminate the session at this time without any further communication. As another example, describes the behavior of a process that internally decides whether to terminate the session without any further communication, or to do so only after having sent an integer. Incidentally, observe that the two examples complete each other. In  (and in most session type theories) the terminal behavior cannot be composed with others. The type system we will describe later does not use this capability either, but this is just to keep it simple and with a reasonable number of rules. The second and last difference we want to emphasize is that the law , which is somehow dual of , does not hold, while it is sound in . Two main reasons justify this fact: the first is that in our theory is an algebraic operator that can combine arbitrary session types, and for this reason the external choice sometimes is an internal choice in disguise: for example, it is possible to prove that . This cannot happen in  because of the very syntax of session types, which prevents arbitrary compositions of behaviors. The second reason is that the synchronous communication model we are relying upon does not tolerate the introduction of interferences. For example, we have because the session type completes the first session type but not the second one: the branch introduces an interference that may enable harmful synchronizations. For this and other reasons the adoption of a synchronous communication model is questionable in practice. However, one can show that by suitably restricting behaviors (for instance, by forbidding outputs in external choices such as in the example above) some instances of the law become sound again. Furthermore, it is possible to simulate partial forms of asynchrony by means of the session type language we have presented (the idea is not explored in detail here, but the interested reader may find some hints in ). In summary, the relation is both an extension and a conservative restriction of the subtyping relation in . ∎
Processes are defined by the grammar in Table 3. We use , , , …to range over processes; we use , …to range over action prefixes; we use , , , …to range over channel names; we let , , , …range over variables and , , …range over channel names and variables ( should not be confused with that we used to range over elements of ); we let , …range over an unspecified language of expressions. The process language is a minor variation of the -calculus, so we remark here only the differences: we have four action prefixes: denotes a receive action for a basic value of type on channel ; denotes a send action for the value of the expression on channel ; denotes a receive action for a channel on channel ; denotes a send action for a channel on channel . Consistently with the language of session types, actions denoting send/receive operations of channels are “untyped”. The process denotes unbounded replications of process , and and respectively denote the external and internal choice between and . We will usually omit the process; we will write for the set of free channel names occurring in (the only binder for channel names is restriction); we will write for the process where all free occurrences of the variable have been replaced by .
The transition relation of processes is defined by an almost standard relation in Table 4, so we will not provide detailed comments here. In the table, we write for the fact that expression evaluates to . Labels of the transition relation are ranged over by , …and are generated by the following grammar:
where , …ranges over messages, namely basic values and channel names. Action denotes an internal computation or a synchronization. Actions of the form and are often called free inputs and free outputs respectively. Actions of the form are called bound outputs and represent the extrusion of a private channel, in this case. We use these actions to model session initiations, whereby a private channel is exchanged and subsequently used for the actual interaction. Notions of free and bound names in labels are standard, with , , and , the other sets being empty.
We remark only two distinctive features of the transition relation: (1) the replicated process evolves by means of an internal transition to ; technically this makes a divergent process, but the fact that we work with a fair semantics makes this only a detail; (2) similarly to the transition relation for session types, the transition relation for processes selects branches of external choices according to the type of the basic value being communicated. This is evident in the transitions for , which are labeled by values of type .
The typing rules for the process language are inductively defined in Table 5. Judgments have the form , where is a standard environment mapping variables to basic types and is an environment mapping channel names and channel variables to session types. We write for the domain of . Rule (t-weak) allows one to enrich with assumptions of the form , indicating that a process does not use the channel . The premise implies since it is always the case that . Rule (t-sub) is an almost standard subsumption rule regarding the type of a channel . The peculiarity is that it works “the other way round” by allowing a session type to become a smaller session type . The intuition is that behaves according to on the channel . Thus, it is safe to declare that the session type associated with is even less deterministic than . This rule is fundamental in the type system since many other rules impose equality constraints on session types that can only be satisfied by finding a lower bound to two or more session types. It should also be appreciated the importance of using , which is a precongruence, since this allows us to apply rule (t-sub) in arbitrary contexts. Rule (t-res) types restrictions, by requiring the session type associated with the restricted channel to be of the form . In light of rule (t-sub) and of Proposition 2.1(2), this requirement imposes that the session type of a restricted channel must be complete. Namely, there must not be communication errors on . Rule (t-nil) types the idle process with the empty session environment. The process should not be confused with the failed session type : the former is the successfully terminated process that does not use any channel; the latter denotes a communication error or a deadlock. Rule (t-input) types an input action for basic values of type . The assumption is moved into the environment and if the session type associated with in the continuation is , then the overall behavior of on is described by . Rule (t-output) is similar, but regards output actions of basic values. We assume an unspecified set of deduction rules for judgments of the form , denoting that the expression has type in the environment . Rule (t-inputS) types an input action for a channel . The continuation must be typed in a session environment of the form , requiring that must not refer to (free) channels other than the received one. Consequently, the whole process behaves according to the session type . The severe restriction on the continuation process is necessary for type preservation, as we will see in Example 3.5 below. Rule (t-outputS) types delegations, whereby a channel is sent over another channel . This rule expresses clearly the idea of projection we are pursuing in our approach: the delegated channel is used in the continuation according to the session type (which may be in case rule (t-weak) is applied); at the same time, the channel is delegated to another process which will behave on it according to . As a consequence, the overall behavior on is expressed by the composition of and , namely by . If is used in the continuation according to , then its type is in the conclusion. Rule (t-ext) types external choices. These are well typed only when each branch of the choice is guarded by an action whose subject is (we write for the subject of action ). For this reason the rule is only applicable to processes of the form , which we abbreviate as , and the resulting behavior on is the sum of the individual behaviors on of each branch, which we abbreviate as . Rule (t-int) types internal choices, but only when the two branches do have the same session environment. This can be achieved by repeated applications of rules (t-weak) and (t-sub). Rule (t-par) types the parallel composition of processes. Again this rule shows the idea of projection and, unlike other session type systems, allows (actually requires) both processes to use exactly the same channels, whose corresponding session types are composed with . In this context rule (t-weak) can be used to enforce that the session environments for and are exactly the same, recalling that is neutral for . Finally, rule (t-bang) types replicated processes: the basic idea is that a replicated process is well typed if any channel it uses is “unlimited” (in the terminology of ), which in our case translates to the property that it must be smaller than two copies of itself. is the simplest session type with this property, but there are others as we will see in Example 3.1.
Thanks to our setting, we have the opportunity to make some interesting connections between the subtyping relations used in type theories for programming languages and the behavioral preorders that arise in many testing theories for process algebras. According to Definition 2.2, if , then it is safe to replace a process behaving according to with another process behaving according to . This is because, by definition of , every context that completes will also complete . Note in particular that the safe substitution regards the larger object. This contrasts with the subtyping relations where it is safe to replace an object of type with another object of type if is a subtype of . In fact, this is exactly the notion of safe substitutability we are using in rule (t-sub). This mismatch can be source of confusion: recall that in our view a session type is not the type of channel, but rather is the allowed behavior of a process on a channel. Thus, if a channel has type , that means that the process using it behaves according to . Now, it is safe to replace that channel with another one with type : since we are replacing the channel, and not the process, the process will still behave according to , but this time on a channel that allows more behaviors. Since , we are assured that the substitution is safe. ∎
Example 3.1 (persistent service provider).
Consider the process
which accepts an unbounded number of connection requests on the channel and processes them in the process . Assume we can type the non-replicated process as follows:
To apply rule (t-bang) for we need to have a type such that , and clearly does not have this property. Consider the session type that is solution of the equation . We have and furthermore . Hence we can now type with an application of rule (t-sub) followed by (t-bang). ∎
Example 3.2 (multi-party session).
Intuitively, a multi-party session is a conversation taking place on a restricted channel that is shared between three or more participants. Consider a system where