Synchronization Expressed in Types of ... - Semantic Scholar

2 downloads 0 Views 159KB Size Report
Systems, Paris, France, March 1996. 14. Ehud Shapiro. The family of concurrent logic programming languages. ACM. Computing Surveys 21 (1989) 412{510.
Synchronization Expressed in Types of Communication Channels Franz Puntigam Technische Universitat Wien, Institut fur Computersprachen Argentinierstr. 8, 1040 Vienna, Austria. E-mail: [email protected]

Abstract. Static typing and subtyping are useful concepts in object-

oriented programming languages. Unfortunately, current type models for concurrent object-oriented languages are not yet as expressive as they should be: Clients have to rely on synchronization behavior not expressed in the objects' types. In the type model proposed in this paper, types of communication channels make synchronization constraints explicit. Static type-checking ensures that messages are sent only if the receivers can deal with the messages at the time when they are received, although the set of accepted messages can change dynamically.

1 Introduction Static typing is useful to increase the readability and reliability of programs and allows the compiler to incorporate additional optimizations. Subtyping supports the reuse of concepts expressed in types. In this paper we investigate a model for statically typed, concurrent, object-oriented programming languages. The objects are regarded as processes (i.e. active objects) that communicate through unidirectional communication channels. The major contribution is the proposal of a type model that supports subtyping and static type checking for communication channels, where types ensure that only such messages can be sent through channels that are actually read from the channel. The dicult part of this contribution is that the behavior of a reader can change and, therefore, the set of messages that can be sent through the channel can also change.

2 The Type Model in Examples Types in object-oriented languages are partial speci cations of object behavior that should express how instances of the types can be used savely [6]. Clients must not assume anything about an object's behavior except what is expressed in the object's type. Static type checking ensures that each object actually behaves as speci ed. A supertype is a less complete speci cation of the behavior speci ed by a subtype; all properties that hold for the supertype also hold for the subtype. The principle of substitutability says that an instance of a subtype can always be used in any context in which an instance of a supertype is expected [16].

Syntax and semantics of the language/model used in this paper resemble that of concurrent logic languages [14]; relationships of these languages to the objectbased actor model [4] and to process algebra are widely known. An example of a process de nition for a simple bu er with a capacity of one element shows the basic constructions of our language/model: Bu er1(q) := q . put(e)  get(a)  r; a / got(e); Bu er1(r): The parameter q is the read-port of a channel transporting commands to an object behaving according to Bu er1. The read-expression q . put(e)  get(a)  r speci es that, rst, a message put(e) is read from q, then a message get(a); r denotes the remaining read-port. The variable e stands for the element put into the bu er, and a for a write-port of a channel through which the element is returned. The write-expression a / got(e) writes the message got(e) to a. The dot () is the sequential composition operator: c  c0 means that a channel rst transports messages according to c and then according to c0 . In a read-expression v . c  c0 , variables occurring in c (and c0 ) are initialized when a message corresponding to c (and c0 ) is received; if c0 is a variable, c0 is initialized to the read-port v after receiving c (and removing c from the read-port). An expression in the body of a process de nition is executable when all variables in this expression have been initialized. Hence, the recursive call Bu er1(r) becomes executable in parallel with a / got(e) when the messages put(e) and get(a) have been received. The next example shows a process de nition for a bu er of capacity n: Bu er[n](q) := n = 1 ! Bu er1(q); n > 1 ! q . r jj s; Bu er1(r); Bu er[n ? 1](s): For n = 1 the bu er behaves as Bu er1; for n > 1 the expression q.r jj s splits the read-port q into two concurrent parts r and s. jj stands for parallel composition: A channel behaving according to c jj c0 can transport messages according to c and c0 in arbitrary interleaving. Because of parallel composition, r and s are initialized immediately and the calls of Bu er1 and Bu er[n ? 1] are not delayed. Our language also supports alternative composition expressed by +. A channel of behavior c + c0 transports messages according to either c or c0 . In a readexpression v . c + c0 , the variables occurring in either c or c0 are initialized. Read- and write-expressions determine the messages transported through channels. A channel's type describes expected orderings of messages by using sequential, parallel and alternative composition operators. For each channel type  , ! denotes the write-port of a channel of this type, and ? the read-port. The next example shows the type de nition of a communication channel that transports commands to a bu er: BC t[A; n] :: n = 1 ! put(!A)  get(!got(!A))  BC t[A; 1]; n > 1 ! BC t[A; 1] jj BC t[A; n ? 1]: A stands for the type of the channels through which elements in the bu er can be accessed. An instance of BC t[A; 1] transports rst a message put(e), where e is the write-port of a channel of type A; the next message is of the form get(a),

where a is the write-port of a channel that transports a message got(e0 ), and e0 is the write-port of a channel of type A. A sequence of such messages (put and get in alternation) is transported through the channel. For n > 1, n arbitrarily interleaved sequences of such messages are transported. We annotate parameters of process de nitions with type information: Bu er[A; n](q:?BC t[A; n]) := n = 1 ! q . put(e)  get(a)  r; a / got(e); Bu er[A; 1](r); n > 1 ! q . r jj s; Bu er[A; n ? 1](r); Bu er[A; 1](s):

3 Typed Channels and Ports Types of channels are denoted by ,  , ' and , the type of the write-port of a channel of type  by ! , and the type of the read-port by ? . We write ^ for the type of a port if the kind (read or write) does not matter. A channel transports a sequence of messages from its write-port to its readport so that the ordering is preserved. The channel's type speci es the allowed sequences of messages. The type of a message m(v ; : : : ; vn ) is the message prototype m(^ ; : : : ; ^n ), where ^i is the type of vi (for 1  i  n). A channel's type is speci ed by a trace set, i.e. the set of all sequences of message prototypes which correspond to all message sequences that can be transported through the channel [13]. Let P denote the set of all message prototypes usable in a programming system, P  the set of all words over the alphabet P , and " the empty word in P  . Then, S  P  is a trace set if S 6= ; and ww0 2 S implies w 2 S for all w; w0 2 P  . Each type  is de ned by the trace set tr( ) of  . Read- and write-ports express di erent concepts to their users. A write-port means that the user (writer) can send messages according to any trace in the trace set. A read-port means that the user (reader) must be able to deal with messages received according to all traces in this set. The writer selects the written messages, while the reader cannot in uence the received messages. This di erence becomes evident when dealing with subtyping. Let a process write messages to a write-port of type ! . These messages depend only on the process' behavior and input, but not on the write-port's type. It is possible to replace this write-port with another write-port of type ! without a ecting the process. We have to de ne !  ! (! is a subtype of ! ) so that a process that assumes a write-port of type ! also works with a write-port of type !. A sucient condition for !  ! is tr( )  tr(), i.e. a channel of type  transports all messages transported through a channel of type  . Let a process receive messages at a read-port of type ? . The process must be able to deal with all messages speci ed by tr( ). We have to de ne ?  ? so that a process that assumes a read-port of type ? can deal with all messages received from a read-port of type ?. A sucient condition for ?  ? is tr()  tr( ), i.e. a channel of type  transports only those messages transported through a channel of type  . Surprisingly, ?  ? is equivalent to !  !. We extend the de nition of subtyping for ports by considering variant argument types. Let a process send messages to a channel v of a type ! , and let 1

1

 describe a message with an argument of type !'. For each  with !  ! , a reader may expect messages from v according to . Let ! be the argument type of the message in  that corresponds to !' in  . The reader of v may send messages to the received write-port according to , although the writer of v provides a write-port of type !'. Hence, type errors are prevented if tr( )  tr(') or (equivalently) !'  ! . By applying similar argumentations to other kinds of ports we get these relationships: Relation Argument in  Argument in  !  ! !' ! !  ! ?' ? ?  ? !' ! ?  ? ?' ?

Trace sets Subtyping tr( )  tr(') !'  ! tr(')  tr( ) ?'  ? tr(')  tr( ) !  !' tr( )  tr(') ?  ?'

From these relationships we can derive a less restrictive de nition of subtyping: De nition 1. !  ! holds if for each p

   pn 2 tr( ) there is a q    qn 2 tr() so that !'i;j  ! i;j , where (for 1  i  n; 1  j  li ) pi = mi ('^i; ; : : : ; '^i;l ) and qi = mi ( ^i; ; : : : ; ^i;l ). Furthermore, ?  ? i !  !. 1

1

1

1

i

i

The syntax of prototypes p 2 P and type expressions  2 T is:

 ::= nil j p j    0 j  jj  0 j  +  0 p ::= m(^ ; : : : ; ^n ) ^ ::= ! j ? 1

(0  n)

where m is a message name. T denotes the set f! :  2 T g of write-port types, T the set f? :  2 T g of read-port types. Elements of T are denoted by ,  , ' and , elements of P by p and q. A set of algebraic laws is de ned on T (as well as T and T ): !

?

!

(   )  ' =   (  ')   nil =  nil   =  ( +  ) + ' =  + ( + ') + = +  +  =  for !  !

?

  ( + ') =    +   ' ( +  )  ' =   ' +   '  jj  =  jj   jj nil =  p   jj q   = p  ( jj q   ) + q  (p   jj  ) ( +  ) jj ' =  jj ' +  jj '

Further general laws are derivable from the given equations. For example,  + =  for !  ! implies  +nil =  and  +  = . The parallel composition operator is in fact syntactic sugar; each type expression containing jj is equal to a type expression not containing jj . We de ne the function tr already used in computing type trace sets: tr(nil) = f"g tr(p   ) = f"g [ fpw : w 2 tr( )g tr( +  ) = tr() [ tr( )

The de nition of tr for parallel composition follows implicitly from the equality relation on type expressions. There is an implicit condition for the usefulness of the above de nitions:  =  , tr() = tr( ). This condition is ful lled as can be seen easily by adapting a proof of a similar sentence [1, 13]. We provide a sound and complete axiomatization of subtyping as given by De nition 1. The following rule set de nes  as a binary relation on T and the auxiliary relation v on T . These relations are easily extended to T [ T using the equivalences !  ! , ?  ? and ! v ! , ? v ?. !  ! S1 ! v ! R1 ! v ! !' v ! !  !nil S2 R2 !(  ') v !(  ) ! v ! !' v ! ! v ! !'  ! S3 R3 !(  ')  !(  ) !( + ') v !( + ) !  ! !'  ! ! v ! S4 R4 !( + ')  !( + ) !( + ') v ! !  !    !n  !n !  !    !n  !n !m(^ ; : : : ; ^n )  !m(^ ; : : : ; ^n ) S5 !m(^ ; : : : ; ^n ) v !m(^ ; : : : ; ^n ) R5 As shown in Sect. 2, functions over type expressions allow us to easily specify large or in nite type expressions of regular structures. Because of space limitations we refrain from formally de ning syntax and semantics of type functions. Type equivalence and subtyping shall be extended to cover type functions. Complete axiomatizations of these notions are not feasible because known algorithms for determining the equivalence of two expressions do not terminate in some cases. However, there are sound and feasible axiomatizations of type equivalence and subtyping that relate only structurally similar type functions. !

!

1

!

1

1

1

1

?

1

1

1

4 Typed Processes The syntax of channel expressions c 2 C , process expressions b 2 B and process de nitions d is given by: c ::= v j m(v ; : : : ; vn ) j c  c j c jj c j c + c b ::= skip j v . c j v / c j b; b j x[s ; : : : ; sm](v ; : : : ; vn ) j cond d ::= x[s ; : : : ; sm ](v :^ ; : : : ; vn :^n ) := b where m is a message name, v; v ; : : : ; vn are variables, x is the name of a process de nition, s ; : : : ; sm are structural parameters, and cond stands for conditional expressions not dealt with here. The semantics should be clear from the explanations of the examples in Sect. 2. The actions are read-expressions (v . c), write-expressions (v / c) and \skip" (which does nothing). Although actions in process expressions are separated by comma and can be rearranged arbitrarily, the rule about using only initialized variables imposes dependences on the actions. We assume that some equality relation on process expressions is de ned so that a compiler can determine whether b = b0 holds for each b; b0 2 B . 1

1

2

1

2

1

1

1

1

1

1

1

2

1

Read- and write-expressions can be split into basic components. Each v.c can be split into actions of the forms v .m(v ; : : : ; vn )  v0 , v .v jj v and v .v + v ; and v /c can be split into v /m(v ; : : : ; vn )  v0 , v /v jj v and v /v + v . There are some special cases: An action v . v0 copies messages from a read-port v to a write-port v0 ; v / v0 creates a new channel with read-port v and write-port v0 . Variables occurring in the head of a process de nition are annotated explicitly with a type. The type of other variables can be derived from the process de nition. (The derivation of this type information is not shown in this paper.) pt(v) denotes a port type associated with a variable v. Often there are several ways to associate types with variables. A compiler has to check whether there is a type assignment so that a process de nition is well-typed. There are only few conditions that must be ful lled: Argument consistency: A call x[s ; : : : ; sm ](v ; : : : ; vn ) is consistent with a process de nition x[s0 ; : : : ; s0m ](v0 :^ ; : : : ; vn0 :^n ) := b if si and s0i are compatible and pt(vj )  ^j (for 1  i  m and 1  j  n). Variable occurrence: Each variable occurs either twice or not at all in a process de nition. A single action contains a variable at most once at the top level (not as an argument). If a variable occurs in two actions at the top level, one occurrence is at the left of . or /, the other at the right of . or /. Well-typed actions: An action is well-typed if its condition is satis ed: Action Condition v / m(v ; : : : ; vn )  v0 pt(v)  !(m(pt(v ); : : : ; pt(v ))   ) where ! = pt(v0 ) v / v jj v pt(v )  !( jj  ) where ! = pt(v ) and ! = pt(v ) v /v +v pt(v )  !( +  ) where ! = pt(v ) and ! = pt(v ) v / v0 pt(v)? and pt(v0 ) = ! 0 v . m(v ; : : : ; vn )  v pt(v)  ?(m(pt(v ); : : : ; pt(v ))   ) where ? = pt(v0 ) v . v jj v pt(v )  ?( jj  ) where ? = pt(v ) and ? = pt(v ) v .v +v pt(v )  ?( +  ) where ? = pt(v ) and ? = pt(v ) v . v0 !  ! where ? = pt(v) and ! = pt(v0 ) Well-typed process expressions ensure that for each message written to a writeport there is an action reading this message from a corresponding read-port. A message can be written to a port v only if pt(v) speci es that the channel associated with v can transport the message. This port can be combined with other parallel or alternative write-ports; the conditions on well-typed actions ensure that all messages from these ports are transported in the channel. If the write-port has been received as an argument of a message or as a head variable, the channel may be able to transport more messages, but not less. If the port was created by an action v0 /v, exactly the messages speci ed by pt(v) are transported. Each channel was created by an action of this form so that there is an appropriate read-port. Conditions on variable occurrences ensure that no variable can be read or written several times and that there are actions reading from each read-port and splitting each read-port at parallel and alternative compositions. Conditions on types associated with read-ports ensure that all messages written to a channel are read from the channel. 1

1

1

1

1

1

1

1

1

2

1

2

1

2

1

2

3

3

1

1

1

1

2

2

3

3

1

2

1

3

2

1

3

3

1

1

1

2

3

1

1

3

2

3

1

2

2

3

3

5 Related Work Much of the work on types for concurrent languages and models is based on the calculus [7]; especially the problem of inferring most general types was considered [3, 15]. Literature on subtyping in such calculi is also available [5, 8, 9, 10, 15]. Each of these type models di ers in important aspects from the one presented in this paper. Nierstrasz [9] proposes \regular types" and \request substitutability"|a speci c form of the principle of substitutability|as foundations of subtyping. However, his very general results are not concrete enough to develop a static type system from them. The proposal of Kobayashi and Yonezawa [5] is more practical; subtyping is de ned in a similar way as in sequential object-oriented languages based on a typed -calculus [2]: A type of an active object speci es the set of messages that will be accepted by all instances; a subtype speci es an extended set of messages. In fact, their approach is a subset of our approach if types of writeports are regarded as types of the objects reading from the corresponding ports. Each type de nition in the subset is of the form x :: (p +    + pn )  x, where p ; : : : ; pn are the prototypes of all messages understood by instances of the type. Kobayashi and Yonezawa assume that messages in a mail queue are processed in arbitrary ordering; but their type system cannot ensure that each received message will be processed eventually. The models of Vasconcelos [15], Pierce and Sangiorgi [10] and Nielson and Nielson [8] also cannot ensure that the receiver reacts to all received messages. However, if an object's type is understood as a contract between the object and its clients, the object must be able to deal properly with all messages received from its clients; the clients can expect that the object responses their type-conforming requests. In the model proposed in the present paper as well as in the process type model [13] objects react to all received messages. This property was a primary goal for this work because we regard it as a precondition for the inclusion of more expressive (partial) behavior speci cations into types. The most important di erence to the work presented in [11, 12, 13] is that process types are types of active objects, not types of ports. Process types can be regarded as equivalent to write-ports; but there is nothing comparable with read-ports. Although the model proposed by Nielson and Nielson [8] does not ensure that all messages are understood, it ensures that instances of subtypes preserve the properties expressed in supertypes: If instances of a supertype understand some message sequences, instances of subtypes also understand them. Because types specify the complete behavior of processes as far as the communication is concerned, subtyping is rather restricted; a subtype cannot specify additional message orderings and messages. 1

1

6 Conclusion We de ned the type of a communication channel as the set of all sequences of messages that can be transported through the channel. Types of channel ports

are not symmetrical: A write-port allows a process to write arbitrary messages speci ed in the type; but the process must be prepared for reading all messages speci ed in the type of a read-port. For write-ports a subtype is essentially a superset of message sequences, for read-ports a subset. This de nition is compatible with the principle of substitutability so that extensions of object behavior are expressible in types. Process expressions can be type-checked statically.

References 1. J. C. M. Baeten and W. P. Weijland. Process Algebra. Cambridge Tracts in Theoretical Computer Science 18. Cambridge University Press, 1990. 2. Luca Cardelli and Peter Wegner. On understanding types, data abstraction, and polymorphism. ACM Computing Surveys 17 (1985) 471{522. 3. Simon J. Gay. A sort inference algorithm for the polyadic -calculus. In Proceedings POPL'93, January 1993. 4. Kenneth M. Kahn and Vijay A. Saraswat. Actors as a special case of concurrent constraint programming. ACM SIGPLAN Notices 25:10 (October 1990) 57{65. Proceedings OOPSLA/ECOOP'90. 5. Naoki Kobayashi and Akinori Yonezawa. Type-theoretic foundations for concurrent object-oriented programming. ACM SIGPLAN Notices 29:10 (October 1994) 31{45. Proceedings OOPSLA'94. 6. Barbara Liskov and Jeannette M. Wing. Speci cations and their use in de ning subtypes. ACM SIGPLAN Notices 28:10 (October 1993) 16{28. Proceedings OOPSLA'93. 7. R. Milner, J. Parrow, and D. Walker. A calculus of mobile processes (parts I and II). Information and Computation 100 (1992) 1{77. 8. Flemming Nielson and Hanne Riis Nielson. From CML to process algebras. In Proceedings CONCUR'93, LNCS 715, Springer-Verlag, 1993, 493{508. 9. Oscar Nierstrasz. Regular types for active objects. ACM SIGPLAN Notices 28:10 (October 1993) 1{15. Proceedings OOPSLA'93. 10. Benjamin Pierce and Davide Sangiorgi. Typing and subtyping for mobile processes. In Proceedings LICS'93, 1993. 11. Franz Puntigam. Flexible types for a concurrent model. In Proceedings of the Workshop on Object-Oriented Programming and Models of Concurrency, Torino, Italy, June 1995. 12. Franz Puntigam. Type speci cations with processes. In Proceedings FORTE'95, IFIP, October 1995. 13. Franz Puntigam. Types for active objects based on trace semantics. In Proceedings of the IFIP Workshop on Formal Methods for Open Object-based Distributed Systems, Paris, France, March 1996. 14. Ehud Shapiro. The family of concurrent logic programming languages. ACM Computing Surveys 21 (1989) 412{510. 15. Vasco T. Vasconcelos. Typed concurrent objects. In Proceedings ECOOP'94, LNCS 821, Springer-Verlag, 1994, 100{117. 16. Peter Wegner and Stanley B. Zdonik. Inheritance as an incremental modi cation mechanism or what like is and isn't like. In S. Gjessing and K. Nygaard (eds.), Proceedings ECOOP'88, LNCS 322, Springer-Verlag, 1988, 55{77. This article was processed using the LATEX macro package with LLNCS style