A Separate Compilation Extension to Standard ML

David Swasey Tom Murphy VII Karl Crary Robert Harper Carnegie Mellon {swasey,tom7,crary,rwh}@cs.cmu.edu

Abstract The goal of this work is to consolidate and synthesize previ- We present an extension to Standard ML, called SMLSC, to support ous work on compilation management for ML into a formally de- separate compilation. The system gives meaning to individual pro- fined extension to the Standard ML language. The extension itself gram fragments, called units. Units may depend on one another in a is syntactically and conceptually very simple. A unit is a series of way specified by the programmer. A dependency may be mediated Standard ML top-level declarations, given a name. To the current by an interface (the type of a unit); if so, the units can be compiled top-level declarations such as structure and functor we add an separately. Otherwise, they must be compiled in sequence. We also import declaration that is to units what the open declaration is to propose a methodology for programming in SMLSC that reflects structures. An import declaration may optionally specify an inter- code development practice and avoids syntactic repetition of inter- face for the unit, in which case we are able to compile separately faces. The language is given a formal , and we argue that against that dependency; with no interface we must compile incre- this semantics is implementable in a variety of . mentally. Compatibility with existing compilers, including whole- program compilers, is assured by making no commitment to the Categories and Subject Descriptors D.3.3 [Programming Lan- precise meaning of “compile” and “link”—a is free to guages]: Language Constructs and Features—Modules, pack- limit compilation to elaboration and type checking, and to perform ages; D.3.1 [Programming Languages]: Formal Definitions and code generation as part of linking. Theory—Syntax Sections 1 and 2 summarize our main design principles, and provide an overview of the system. In Section 2 we give a small General Terms programming languages, modularity, compilation example of its use. The semantics, formulated in the framework of the Harper-Stone semantics of ML [12, 13], is given in Section 3.1 Keywords standard ml, separate compilation, incremental compi- Some implementation issues are discussed in Section 4. We con- lation, types clude with a discussion of related work in Section 6.

Introduction 1. Design Principles We propose an extension to Standard ML called SMLSC. SMLSC A language, not a tool. We propose an extension to the Standard supports separate compilation in the sense that it gives a static se- ML language to support separate compilation, rather than a tool to mantics to individual program fragments, which we call units.A implement it. The extension is defined by a semantics that extends unit may depend on other units, and can be type-checked indepen- the semantics of Standard ML to provide a declarative description dently of those units by specifying what it expects of them. These of the meanings of the language constructs. The semantics provides expectations are given in the form of interfaces for those other a clear correctness criterion for implementations to ensure source- units. When unit A is checked against another unit B via a medi- level compatibility among them. ating interface, we need not have access to B at all. Therefore we Flexibility. A compilation unit consists of any sequence of top- say that A is separately compiled (SC) against B. 2 It is also useful to allow unit A to depend on another unit level declarations, including signature and functor declarations. B without specifying an interface for B. In this case, the only However, since Standard ML lacks syntactically expressible signa- way to derive the context necessary to check A is to first check B tures, some units cannot be separately compiled from one another. and read off its actual interface. In this scenario we say that A is We therefore support incremental, as well as separate, compilation incrementally compiled (IC) against B. for any unit. This means that the interface of a unit can either be in- Units may be compiled and then linked together to satisfy de- ferred from its source (incremental compilation) or explicitly spec- pendencies. The compiled form of a unit or set of linked units is ified (separate compilation) at the programmer’s discretion. called a linkset. A linkset may be further linked with other linksets. Simplicity. The design provides only the minimum functionality If a linkset has no remaining dependencies, then it can be trans- of a separate compilation system. It omits any form of compilation formed into an executable program. parameters, conditional compilation directives, or compiler direc- tives. We leave for future work the specification of such additional machinery. Conservativity. The semantics of Standard ML should not be changed by the introduction of separate compilation. In particu- lar, we do not permit “circular dependencies” or similar concepts

1 We plan to give a semantics in the framework of The Definition of Stan- dard ML [16] in a forthcoming technical report [21]. [copyright notice will appear here] 2 Consequently, units cannot be identified with Standard ML structures.

Draft of June 6, 2006 1 2006/6/6 srcunit ::= unit unitid = top topdec end unit declaration topdec ::= import impexp open units strdec structure-level declaration sigdec signature declaration fundec functor declaration local topdec1 in topdec2 end local declaration topdec1 topdec2 impexp ::= unitid h: intexpi open unit unitid impexp1 impexp2 intexp ::= intf topspec end interface expression topspec ::= spec structure-level specification functor funspec functor specification topspec1 topspec2 funspec ::= funid(strid : sigexp): sigexp0 hand funspeci

Figure 1. SMLSC concrete syntax that are not otherwise expressible in Standard ML. This ensures to be inferred from its source code. This is called incremental that compilers should not be disturbed by the proposed extension compilation, or IC for short. beyond what is required to implement the extension itself. The concrete syntax for units and interfaces in SMLSC is given in Figure 1. We extend topdecs to add import and local. The Explicit dependencies. The dependencies among units are ex- import declaration (like open) allows multiple units to be simulta- plicitly specified, not inferred. The chief reason for this is that de- neously imported. Interfaces are topspecs; this is the syntactic class pendencies among units may not be syntactically evident—for ex- spec of Standard ML, with the addition of a specification form for ample, the side effects of one unit may influence the behavior of functors. The local declaration limits the of imports, just another. There are in general many ways to order effects consis- as the structure declaration of the same name. tently with syntactic dependencies, and these orderings need not be equivalent. A lesser reason is that supporting dependency inference requires restrictions on compilation units that are not semantically necessary, reducing flexibility. Environment independence. The separate compilation system is Projects and Linksets defined independently of any environment in which it might be A project consists of a linearly ordered sequence of source units implemented. The design speaks in terms of linguistic and semantic and compiled units, which we call linksets (following Cardelli [5]). entities, rather than implementation-specific concepts such as files The ordering of the components in a project is significant, both be- or directories. cause it specifies the order of identifier resolution, and because it specifies the order of computational effects when executed. Com- 2. Overview pilation of a project consists of processing the source units in the Units and Interfaces specified order to obtain linksets, and then knitting them together to resolve dependencies. The SMLSC extension is organized around the concept of a unit.A Each linkset consists of several compiled units, called its ex- unit consists of top-level declarations, which include declarations ports, together with the names and interfaces of its imports, the of signatures, structures, and functors. Each unit is given a name units on which it depends. Linking consists of resolving inter-unit by which the unit is known throughout the program. One unit may dependencies by binding exports to imports among linksets. When refer to the components of another using an import declaration, all references have been resolved, the resulting linkset can be com- which records the dependency of the importing unit on the imported pleted to form an executable. unit, and opens it for use within the importing unit. This is the We do not give a concrete syntax for linksets, as we do not in- only means by which one unit may refer to another; we do not tend for programmers to write them, nor do we expect compati- support “dot notation” for accessing the components of a unit. An bility of linksets across implementations. Rather, they are left as import declaration is a new form of top-level declaration. (This is implementation-specific concepts (such as object files), which are the only modification that we make to an existing syntactic category modeled here by the abstract semantic objects described in Sec- of Standard ML.) tion 3. The compilation context for a unit is entirely determined by its imports. That is, all dependencies of a unit on another unit must be explicitly indicated using import declarations. The dependency of one unit on another is mediated by an interface, the type of a unit. The interface of an imported unit can be specified in one of two Examples ways, either implicitly or explicitly, corresponding to incremental or separate compilation. We begin with a few simple examples to illustrate the features of An import declaration of the form import unitid : intexp the system, building up to the idiom of handoff units. specifies an explicit interface for the imported unit. This permits the Suppose that we have a library of data structures whose name importing unit to be compiled independently of the implementation is Collections. It is natural to place this library in a unit. Let’s of unitid, relying only on the specified interface. This is called assume it contains only the queue data structure: separate compilation, or SC for short. An import declaration of the form import unitid specifies that the interface for unitid is

Draft of June 6, 2006 2 2006/6/6 unit Collections = However, writing the SC import this way forces an undesirable top repetition of code. If more than one client uses Collections— signature QUEUE = which we would expect—each client repeats the interface for its sig import of the unit. A further problem is that this style asks the client type α queue to supply the interface of the library, but the interface of a library is val empty : α queue usually provided by the library author, not the client. Fortunately, val push : α * α queue -> α a combination of SC and IC allows us to use the system in a much val pop : α queue -> α * α queue cleaner way. end structure Queue :> QUEUE = Handoff Units struct (* ... *) end A programmer who wishes his code to be available for separate end compilation can provide a handoff unit which supplies the interface. A client of the Collections library can import it using IC easily: Starting from scratch, the handoff unit contains an SC import: unit Scheduler = unit Collections = top top import Collections signature QUEUE = structure Sched = sig struct type α queue type job = (* ... *) val empty : α queue val readyqueue = val push : α * α queue -> α ref Queue.empty : job Queue.queue ref val pop : α queue -> α * α queue (* ... *) end end import CollectionsImpl : end intf In these examples we use link to stand for the semantic operation structure Queue : QUEUE of compiling and linking a list of source units and linksets. We can end compile and link this program as end L = link(Collections, Scheduler) The implementation of the collections library is moved to the or we can compile the library and then the client unit CollectionsImpl. Because the import declaration opens the imported unit, all of the contents of CollectionsImpl are L = link(Collections) 0 available in the Collections unit. (Note that signature declara- L = link(L , Scheduler) 1 0 tions do not appear in interfaces, but we can write these before the but the Scheduler unit may not be compiled on its own. import declaration and then use the signature bindings in the inter- Incremental compilation is convenient when we have source or face for the same effect.) Clients wishing to make use of the library a compiled linkset for the Collections unit. We may prefer to use simply import the handoff unit using IC: separate compilation, or may be forced to because the implementa- tion for Collections is not available. A client with an SC import unit Scheduler3 = looks like this: top import Collections unit Scheduler2 = structure Sched = (* ... *) top end import Collections : intf This additionally has the benefit that the clients only need to structure Queue : know the name of the handoff unit, not the implementation unit. A sig few such clients can be linked with the handoff unit: type α queue L = link(Collections, Scheduler3, OtherClient) val empty : α queue 0 val push : α * α queue -> α The result can later be linked with the implementation of the Col- val pop : α queue -> α * α queue lections library: end end L1 = link(CollectionsImpl, L0) structure Sched = Definite References struct In the terminology of Harper and Pierce [11] an import of one job = (* ... *) in another is interpreted as a definite reference—that is, as a free val readyqueue = variable that refers to single, specific unit through an interface for ref Queue.empty : job Queue.queue ref it, either inferred or specified. This ensures that if two separate units (* ... *) import a common unit, such as a well-known library, these units end share a common understanding of the abstract types exported by end that unit. No additional sharing specifications are required to use This allows Scheduler2 and Collections to be compiled sepa- the separate compilation system. rately: This is in sharp contrast to the so-called fully functorized style of L0 = link(Scheduler2) use of the ML modules system, in which a functor is λ-abstracted L1 = link(Collections) over the modules on which it depends. In this formulation refer- L2 = link(L1,L0) ences are interpreted as indefinite, in that the functors involved may

Draft of June 6, 2006 3 2006/6/6 be applied to any modules satisfying those interfaces, not necessar- Judgement... Meaning... ily in a coherent manner. Different functors with a parameter refer- ` decs ok decs is well-formed ring to “the” shared library might be applied to different instances decs ` sdecs ok sdecs is well-formed of it. To ensure coherence in the presence of indefinite references, decs ` sig : Sig sig is well-formed one must resort to explicit type sharing specifications, which are decs ` sig ≡ sig 0 : Sig signature equivalence potentially burdensome. decs ` sbnds : sdecs sbnds has declaration list sdecs The handoff methodology in SMLSC facilitates programming decs ` mod : sig mod has signature sig with definite references. Two pieces of code that SC import the same unit may only be linked if they import that unit at equivalent Figure 2. TSIL judgements (summary) interfaces. The imports are then consolidated into a single import, ensuring that type equations hold. When the same handoff unit is used to create the two imports, these interfaces will always be A bnd binds a variable to an expression (var=exp), constructor equivalent. In corner cases such as skew between versions of a (var=con), or module (var=mod). A structure binding list sbnds library’s handoff unit, the programmer may manually consolidate has the form two imports. We discuss this further in Section 5. lab1Bbnd 1,..., labnBbnd n. 3. Semantics A structure is written [sbnds]. The module syntax is closed under the formation of functors: dependently typed functions from mod- We give a semantics to SMLSC by extending Harper and Stone’s 3 ules to modules. Typed Semantics (TS) for Standard ML [13]. At a high level the We shall use the TSIL judgements given in Figure 2. These typed semantics consists of an elaboration relation from an exter- judgements have the following meaning. nal language, called TSEL, into an internal language, called TSIL. The external language is a slight extension of the abstract syntax of • decs ` sdecs ok. No label is used twice and every declaration Standard ML. The internal language is a typed λ-calculus based on is well-formed. For example, the Harper-Lillibridge type theory for modules [10]. Elaboration ` T t:Ω,X x:t ok. comprises , pattern compilation, equality compila- B B tion, identifier resolution, and insertions of coercions for signature • decs ` sig : Sig. The signature sig is well-formed. matching. The result of elaboration is a well-formed program in • 0 0 the TSIL, to which a dynamic semantics is given to provide an ex- decs ` sig ≡ sig : Sig. The signatures sig and sig declare ecution model. The semantics of SMLSC is an extension of the the same components, in the same order, with the same labels, Harper-Stone semantics that elaborates units into linksets that can and that corresponding type components are equivalent. be completed for execution. • decs ` sbnds : sdecs. The structure binding list sbnds sdecs The TSIL. We begin with a brief review of the structure of the matches the structure declaration list . Corresponding TSIL. The TSIL consists of a core level and a module level. The labels must agree and each bound expression, constructor, or sbnds sdecs core level includes expressions exp, constructors con, and kinds module in must match its declaration in . For ex- knd. Kinds classify constructors. Constructors of kind Ω are types; ample, the judgement they classify expressions. The module level includes modules mod decs ` (labBvar=mod, sbnds):(labBvar:sig, sdecs) and signatures sig, which classify modules. We write {} to denote the empty module, and mod.lab to denote the projection of a holds if decs ` mod : sig and decs, var:sig ` sbnds : sdecs. component named lab from the structure mod. The semantics • decs ` mod : sig. The module mod has signature sig. The works mainly with modules, ultimately elaborating units to TSIL signature sig may or may not be fully transparent. For example, structures. we may derive both Declaration lists serve as contexts in the TSIL static semantics. m :[T t:Ω,X x:t] ` m :[T t:Ω=m.T, X x:t] A declaration list decs = dec1,..., decn declares expression B B B B (var:con), constructor (var:kndh=coni), and module (var:sig) and variables. A structure declaration list sdecs has the form m :[T Bt:Ω,XBx:t] ` m :[T Bt:Ω,XBx:t]. lab dec ,..., lab dec 1B 1 nB n The former signature is said to be selfified with respect to the associating a label with each declaration. The structure declara- variable m. tion list labBdec, sdecs binds the variable declared by dec with scope sdecs. We write [sdecs] to denote the signature of a structure TS elaboration. Harper and Stone give a semantics to Standard containing fields described by sdecs. Variables express dependen- ML by elaboration of TSEL into TSIL. Elaboration is performed cies between components in a structure signature and may be freely in a context Γ consisting of a structure declaration list (sdecs) that, alpha-varied. Labels name components for external reference and due to shadowing, may have duplicate labels. We shall use the TS may not be renamed without changing the meaning of the signature. elaboration judgements given in Figure 3. These judgements have Consider the declaration of a structure m containing an opaque type the following meaning: component T and value component X of that type: • Γ ` strdec sbnds : sdecs. Elaborate the TSEL structure m :[T Bt:Ω,XBx:t]. declaration strdec to the structure binding list sbnds : sdecs. Since the TSEL permits functors within structures, this includes We can systematically rename the bound variables t and x.A path elaboration of functor declarations. is a module variable followed by a list of labels, serving a role similar to SML long identifiers. The paths m.T (a constructor) and • Γ ` sigexp sig : Sig. Elaborate the TSEL signature m.X (an expression) refer to m’s components. expression sigexp to the signature sig. The TSEL does not include signature declarations; we treat them as abbreviations 3 In a planned technical report [21], we intend to also give a semantics by for TSIL signatures, recording them in linksets and expanding extending The Definition of Standard ML [16]. them during elaboration.

Draft of June 6, 2006 4 2006/6/6 Judgement... Meaning... Judgement... Meaning... Γ ` strdec sbnds : sdecs structure declaration elaboration decs ` L ok L is well-formed Γ ` sigexp sig : Sig signature elaboration decs ` S ok S is well-formed Γ ` spec sdecs specification elaboration L exp : {} L completes to exp 0 00 0 00 Γ `ctx labs path : class context lookup decs ` L++L L L and L merge to L 0 decs `sub path : sig 0  sig mod : sig coercion compilation Figure 4. Linking judgements

Figure 3. TS elaboration judgements (summary) L ::= sdecs0 → sbnds : sdecs; S linkset S ::= · • Γ ` spec sdecs. Elaborate the TSEL specification spec to S, sigid = sig top-level the structure declaration list sdecs. This includes elaboration of S, unitid = S0 declared by unitid functor specifications.

• Γ `ctx labs path : class. Perform identifier resolution in Figure 5. Linkset syntax the context Γ. The input is a list of labels, which is derived from an SML long identifier; the output is a path classified by the type, kind, or signature class. Some labels in the context value Y : a.T but can be linked with (a linkset exporting) a are annotated with a star, indicating that they are “open” (in structure B providing more components. the sense of the SML open declaration). Identifier resolution • The exports sbnds : sdecs are the TSIL code associated with searches Γ from right to left, descending into structures with the linkset. They may make reference to the linkset’s imports. starred labels. For example, we may derive Continuing our example, the exports T t1:Ω,T t2:Ω={} ` T t2 : Ω={} B B sbndsZR : sdecsZR = ZBz=b.Y, RBr=a.T : and ZBz:a.T, RBr:Ω=a.T ? XBx1:{}, 1 Bm:[T Bt:Ω,XBx2:t] ` X m.X : m.T. reference the imports sdecsAB to bind an expression Z of the imported type and an equivalent type . • decs ` path : sig  sig mod : sig 0. Perform sub 0 • The signature abbreviations S are used during elaboration. transparent signature ascription. The inputs are a signature sig , 0 They may make reference to the linkset’s imports and exports. a path having that signature, and a target signature sig. The Continuing our example, the signature abbreviations output is a module mod : sig 0, where sig 0 has the same shape as sig but is fully transparent relative to path. SSIG = SIG=[MBm:Ω=r] Elaboration maps TSEL identifiers to TSIL labels using a func- specify that elaboration should treat the signature identifier SIG tion · . To implement identifier “shadowing,” elaboration employs as an abbreviation for a TSIL signature referencing the exported a function sbnds++sbnds0 : sdecs++sdecs0 that concatenates type R. sbnds : sdecs and sbnds0 : sdecs0, renaming labels in the left hand sides that appear in the right hand sides. The function chooses The dynamic semantics for SMLSC is very simple. The com- fresh labels that do not correspond to TSEL identifiers. For exam- pletion judgment L exp : {} translates a linkset ple, if ·; sbnds : sdecs; S

sbnds : sdecs = T Bt1={} : T Bt1:Ω={} with no imports to a TSIL expression 0 0 sbnds : sdecs = T Bt2=Int : T Bt2:Ω=Int, [sbnds, labBvar={}].lab : {} then sbnds++sbnds0 : sdecs++sdecs0 might be where lab and var are fresh. Under the TSIL dynamic semantics, (labBt1={}, T Bt2=Int):(labBt1:Ω={}, T Bt2:Ω=Int) the resulting expression evaluates the linkset’s exports from left to right for their side-effects. Evaluation terminates when an uncaught where lab is not in the range of the · function. exception is raised or when every export has been evaluated. 3.1 Linking We give the full syntax for linksets in Figure 5 and the rules in Appendix A. The remainder of this section explains the rules for We define linking for the TSIL by giving rules for deriving the linkset merge. linking judgements in Figure 4. A linkset Notation. We write decs, sdecs to extend a context decs, implic- sdecs → sbnds : sdecs; S 0 itly dropping the labels in sdecs. We define the domain of a struc- comprises imports sdecs0, exports sbnds : sdecs, and signature ture declaration list, dom(sdecs), by abbreviations S. dom(lab1Bdec1,..., labnBdecn) = {lab1,..., labn}. • The imports sdecs describe the TSIL structures on which 0 We write {var/var 0}L for the capture-free substitution of var for the linkset depends; they must be well-formed in the ambient 0 4 context. For example, the imports free occurrences of var in L. Linkset merge. The rules for linkset merge decs ` L ++L sdecsAB = ABa:[T Bt:Ω,XBx:t], 1 2 L combine L and L to produce L . The rules presuppose that BBb:[Y By:a.T ] 3 1 2 3 L1 is well-formed with respect to decs but permit L2 to make express dependency on structures labelled A and B. reference (via free TSIL variables) not only to decs but to the Imports specify assumptions to be satisfied by linking. A linkset 4 with imports sdecsAB assumes structure B binds (at least) a Linkset bound variables and scopes are discussed in Appendix A.

Draft of June 6, 2006 5 2006/6/6 imports and exports of L1. Formally, the rules satisfy the following Judgement... Meaning... 5 property. project L project elaboration Γ ` srcunit L unit elaboration L = sdecs → sbnds : sdecs If 1 1 Γ ` topdec L top-level declaration elaboration decs ` L ok and 1 Γ ` impexp L import expression elaboration decs, sdecs , sdecs ` L ok and 1 2 , Γ ` sigbind S signature binding elaboration and decs ` L1++L2 L3, then decs ` L ok. 3 Γ `ctx sigid sig : Sig signature lookup Γ ` unitid S If a linkset is well-formed, then it neither imports nor exports ctx Γ ok Γ is well-formed the same label twice (although it may both import and export a particular label). The rules process the imports in L2 from left to right. If L2 has Figure 6. Elaboration judgements no imports, then the following rule applies.

L = sdecs0 → sbnds : sdecs project ::= · empty 0 0 project, srcunit source unit decs ` L++(· → sbnds : sdecs ) 0 0 project,L compiled unit(s) sdecs0 → sbnds++sbnds : sdecs++sdecs srcunit ::= unit unitid = topdec unit declaration

L3 imports what L1 does and exports what L1 and L2 do. To topdec ::= import impexp open units ensure that L3 is well-formed, the rule uses the TS function ++ strdec to concatenate the exports in L1 with the exports in L2, renaming signature sigbind labels exported by L1 that are also exported by L2. local topdec1 in topdec2 end topdec topdec Otherwise, the rules examine the first import labBvar:sig in 1 2 L2 and distinguish three mutually exclusive cases: impexp ::= unitid hintf spec endi open unitid impexp1 impexp2 • L1 exports lab. sigbind ::= sigid = sigexp hand sigbindi 00 0 0 000 sdecs = sdecs , labBvar :sig , sdecs 0 0 00 Figure 7. SMLSC abstract syntax decs, sdecs0, sdecs `sub var :sig  sig mod:sig 00 sbnd := labBvar=mod sdec := labBvar:sig L := sdecs0 → sbnds++sbnd : sdecs++sdec 0 0 00 • L1 neither imports nor exports lab. decs ` L++(sdecs1 → sbnds : sdecs ) L lab 6∈ dom(sdecs) ∪ dom(sdecs0) decs ` (sdecs0 → sbnds : sdecs)++ 0 0 0 00 decs, sdecs0, sdecs ` sig ≡ sig : Sig (lab var:sig, sdecs1 → sbnds : sdecs ) L 0 B decs, sdecs0 ` sig : Sig 0 0 0 L := sdecs0, labBvar:sig → sbnds : sdecs The first premise picks out the L1 export labBvar :sig for 0 0 00 decs ` L++(sdecs1 → sbnds : sdecs ) L lab; there can be at most one since L1 is well-formed. The second premise calls the TS coercion compiler to match the decs ` (sdecs0 → sbnds : sdecs)++ 0 0 0 0 00 export var :sig to the import signature sig. Linking fails if (labBvar:sig, sdecs1 → sbnds : sdecs ) L no match is possible; otherwise, sig 00 has the same “shape” as The first premise ensures that L neither imports nor exports sig, but is fully transparent relative to the variable var 0. The 1 lab. The next two premises choose a signature sig 0 equivalent structure binding sbnd : sdec is constructed using the coercion to sig but well-formed without reference to the exports of L . module mod at the signature sig 00, maximizing type sharing. 1 Linking fails if no such signature exists—when opaque types The linkset L has the same imports as L , and exports those of 1 exported by L occur in sig. Otherwise, L is constructed by L plus the result of the preceding coercion. To ensure that L 1 1 adding a new import to the imports in L . is well-formed—in particular, that it exports nothing more than 1 once—the rule uses ++ to construct its exports. 3.2 Elaboration • L1 imports lab but does not export it. We define a semantics for SMLSC by giving rules for the elabora- lab 6∈ dom(sdecs) tion judgements given in Figure 6. We give the abstract syntax for 00 0 0 000 SMLSC in Figure 7. The elaboration rules appear in Appendix B. sdecs0 = sdecs , labBvar :sig , sdecs 0 These judgements have the following meaning. decs, sdecs0, sdecs ` sig ≡ sig : Sig 0 0 0 0 L := {var /var}(sdecs1 → sbnds : sdecs ) • project L. Elaborate project, using linkset merge to accu- 0 00 decs ` (sdecs0 → sbnds : sdecs)++L L mulate a resulting linkset L. A source unit is elaborated in a context Γ that declares the imports and exports in L. decs ` (sdecs0 → sbnds : sdecs)++ 0 0 00 • (labBvar:sig, sdecs1 → sbnds : sdecs ) L Γ ` srcunit L. Elaborate the topdec in srcunit to the linkset The first premise ensures L1 does not export lab. The second 0 0 sdecs0 → sbnds : sdecs; S. premise picks out the L1 import labBvar :sig . Linking fails if sig and sig 0 are not equivalent; otherwise, L0 is constructed by The imports sdecs0 arise from the import declarations in topdec. The exports sbnds : sdecs arise from the structure dec- changing references in the remainder of L2 to use the import in L . larations in topdec. The signature abbreviations S arise from 1 the signature declarations in topdec. The result, L, exports a single module 5 In this description of linkset merge, we suppress all details related to signature abbreviations. unitidBvar=[sbnds]: unitidBvar:[sdecs].

Draft of June 6, 2006 6 2006/6/6 • Γ ` topdec L. Elaborate topdec using linkset merge and ology of definite references by introducing “views” of the same identifier resolution. underlying unit. For example, suppose that two linksets L1 and L2 import the • Γ ` impexp L. Elaborate impexp using identifier resolu- tion and spec elaboration. same unit MathLib at disparate interfaces I1 and I2. This may hap- pen because the developers of L1 and L2 compiled using different • Γ ` sigbind S. Elaborate sigbind using signature elabora- versions of the handoff unit for MathLib, or because the developers tion. wrote their import interfaces by hand. The link link(L1, L2) 4. Implementation fails because the linksets are required to agree on the interfaces of The semantics of SMLSC avoids commitment to the meaning of their common imports. Aside from recompiling the two linksets “compilation,” “linking,” and “completion” to ensure compatibility to use the same interface, the programmer has several options with various implementation strategies. These phases may be im- for resolving this situation. First, she can satisfy the imports by plemented using classical methods (code generation during com- providing the implementation of MathLib: pilation, object code weaving during linking, and writing an ex- 0 ecutable for completion), or in other, more novel, ways (such as L1 = link(MathLib, L1) 0 type checking during compilation, and code generation during link- L = link(L1 , L2) ing). The design is, as far as we know, implementable in all current The first step satisfies the SC import of MathLib in L1, as long Standard ML compilers without requiring radical changes to their as the actual interface of MathLib matches the import inter- infrastructure. face I1. The result L10 does not import MathLib, so it does not conflict with the import of MathLib in L2. L10 does ex- Parallel Build. The purpose of separate compilation is to permit port MathLib, so if the actual interface of MathLib matches I2, a client unit to be compiled independently of its implementation. then the second link succeeds. Because linking is left-associative, A compiler can exploit this by permitting clients of a separately L = link(MathLib, L1, L2) accomplishes the same thing. compiled unit to be compiled in parallel with one another in order Any implementation of MathLib that satisfies I1 and I2 to speed up system build times. The TILT compiler, which imple- will suffice. Because we do not require unit names to be glob- ments an earlier version of the present extension, implements such ally unique, this implementation of MathLib might even import a strategy. Moreover, it also implements cut-off incremental recom- MathLib (again) and then contain some glue code to make it com- pilation [1], where it is able to interrupt the normal cascade of re- patible with the two given interfaces I1 and I2 (Figure 8). We compilation when a source change does not cause a unit’s interface expect such cases to be uncommon, the preferred methodology to change. being to use a single handoff unit for all clients. Parsing. This presentation of SMLSC provides concrete and ab- stract syntax, but does not formalize parsing. The only issue that 6. Related Work entangles separate compilation and parsing is fixity declarations. There are several closely related systems that influenced the design To support fixity declarations at parse-time, we include a pars- of SMLSC. ing context in the concrete representation of linksets (object files). The notion of linkset in SMLSC comes from Cardelli’s investi- A source unit that is incrementally compiled against a linkset is gation of separate compilation and type-safe linking in the simply- parsed using that linkset’s included parsing context. We do not per- typed λ-calculus [5]. Our formalization of linking extends these mit fixity specifications in user-specified interfaces, and therefore ideas to support the Standard ML module system including signa- they do not affect interface matching or any other part of the se- ture subtyping, abstract types, and module and type definitions in mantics. structures. Note that a library may specify fixity information by placing ap- Harper and Pierce [11] discuss language design for module sys- propriate declarations in the handoff unit. For example, to describe tems, including separate compilation. Particularly relevant to the a matrix library that supplies an infix ** operator for multiplication, current work is their discussion of sharing of abstract types. They we may write the following handoff unit: describe the use of definite references to avoid the coherence prob- unit Matrices = lems (and excess sharing specifications) that arise from aliasing. top Glew and Morrisett [8] describe separate compilation for Typed import MatricesImpl : [19]. Their language, MTAL, permits type intf definitions, abstract types, and polymorphic types in interfaces and type matrix supports recursive linking. val ** : matrix * matrix -> matrix Jim [14] describes a λ-calculus P2 with rank 2 intersection (* ... *) types that has principal typings. The principal typings property end means that from a term M, one can infer both Γ and τ such that any infix ** typing derivation Γ0 ` M : τ 0 is an instance of Γ ` M : τ. In a end

5. Multiple Interfaces for the Same Import In Section 2 we presented the programming methodology of hand- off units. As long as two linksets that import the same unit identifier do so by using the same handoff unit, they will always agree on the interface for that unit and so can be linked together. However, in some situations it may be useful to permit two clients to import the Figure 8. The linkset Lglue imports MathLib at interface I and same unit, each with a different interface. Since interface matching, then exports it to satisfy the imports in L1 and L2 at disparate like signature matching, is coercive, this complicates the method- interfaces I1 and I2.

Draft of June 6, 2006 7 2006/6/6 system with principal typings, program fragments can be separately meaning. ML Basis is given a formal semantics [6] in terms of The compiled without context information, meaning that SC imports Definition of Standard ML. The implementation of ML Basis in the need not even specify interfaces. Standard ML, however, does not ML Kit supports cut-off incremental recompilation based on Els- have principal typings. It remains an open problem to design a type man’s thesis work [7]. Like CM, ML Basis does not provide a way system that supports principal types for features such as abstract for programmers to write down interfaces or separately compile and recursive types, and type definitions in modules. against unimplemented bases. Objective . The separate compilation system of Objective Caml (O’Caml) [15] is similar in many regards to SMLSC. The 7. Conclusion declaration of a unit U is an O’Caml module stored within a file We have presented an extension to Standard ML for separate com- called U.ml. The interface for U may optionally be given in a file pilation called SMLSC. Its focus is the unit, a program fragment called U.mli. If the interface is present, other units depending on that can depend on other program fragments through either separate U can compile even if the implementation is not available, just as or incremental compilation. Via the programming idiom of handoff in SMLSC. Because the filename of an interface indicates the unit units—that uses both separate and incremental compilation—we that it describes, O’Caml interfaces play the role of handoff units limit the number and complexity of linguistic mechanisms while in SMLSC. Additionally, O’Caml’s use of the filesystem to provide supporting a convenient programming style. Our formal and ab- a canonical location for each unit and interface means that all unit stract definition of the language ensures that it is unambiguously references are definite. specified, and admits a variety of implementation strategies. On the other hand, O’Caml’s dependence on the filesystem means that the language is not independent from its environment. References For instance, unit names are limited to valid filenames on the host system, and restructuring a project on disk may force changes to the [1] Rolf Adams, Walter Tichy, and Annette Weinert. The cost of selective recompilation and environment processing. ACM Transactions on code. Another significant difference is that O’Caml conflates the Software Engineering and Methodology, 3(1):3–28, January 1994. notions of units and modules. This earns O’Caml some conceptual economy, but it makes it impossible to separate the notions of top- [2] Matthias Blume. Dependency analysis for Standard ML. ACM level declarations and structure components. This makes it neces- Transactions on Programming Languages and Systems, 21(4):790– 812, 1999. sary to support signature and functor definitions within structures, so such a choice would not be compatible with our design princi- [3] Matthias Blume. CM: The SML/NJ compilation and library ple of conservativity over Standard ML. Finally, unlike SMLSC, manager (for SML/NJ version 110.40 and later) user manual, 2002. O’Caml and its separate compilation system are defined informally http://www.smlnj.org/doc/CM/new.pdf. in terms of their implementation. [4] Matthias Blume and Andrew W. Appel. Hierarchical modularity. ACM Transactions on Programming Languages and Systems, Moscow ML. The Moscow ML [20] compiler for Standard ML 21(4):813–847, 1999. supports a separate compilation system nearly identical to Objec- [5] Luca Cardelli. Program fragments, linking, and modularization. tive Caml’s. Moscow ML extends the Standard ML module system In Proceedings of the ACM SIGPLAN-SIGACT Symposium on to allow (among other things) functor and signature declara- Principles of Programming Languages, pages 266–277. ACM Press, tions in structures and specifications for them in signatures. Then, 1997. like O’Caml, units are structures. In contrast, SMLSC does not re- [6] Henry Cejtin, Matthew Fluet, Suresh Jagannathan, and Stephen quire any changes to the Standard ML module language. Weeks. Formal specification of the ML Basis system, January 2005. http://mlton.org/MLBasis. Other Standard ML implementations include mechanisms for [7] Martin Elsman. Program Modules, Separate Compilation, and breaking programs up into compilation units. None support sepa- Intermodule Optimisation. PhD thesis, Department of Computer rate compilation in the sense we use it here; they use the term to Science, University of Copenhagen, January 1999. mean cut-off incremental recompilation (recall Section 4). [8] Neal Glew and Greg Morrisett. Type-safe linking and modular SML/NJ CM. The Compilation Manager for Standard ML of assembly language. In Proceedings of the ACM SIGPLAN-SIGACT New Jersey (CM) [3] is a tool for compiling Standard ML pro- Symposium on Principles of Programming Languages, pages 250– 261. ACM Press, 1999. grams spread across many source files. CM permits a program to be divided into a hierarchy of libraries [4]. A library comprises a [9] Robert Harper, Peter Lee, Frank Pfenning, and Eugene Rollins. list of imported libraries, Standard ML source files, and a list of Incremental recompilation for Standard ML of New Jersey. Technical symbols exported by the library. Dependencies between libraries Report CMU-CS-94-116, School of Computer Science, Carnegie Mellon University, February 1994. are explicit but dependencies among the source files in a library are inferred [2, 9]. CM provides control over the identifiers visible to [10] Robert Harper and Mark Lillibridge. A type-theoretic approach a source file, and supports conditional compilation, parallel compi- to higher-order modules with sharing. In Proceedings of the lation, and cut-off incremental recompilation. CM provides no way ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pages 123–137. ACM Press, 1994. for the programmer to write interfaces nor to compile against unim- plemented units. SMLSC is not a replacement for CM; we believe [11] Robert Harper and Benjamin . Pierce. Design considerations for that dependency analysis and recompilation tools are useful, and ML-style module systems. In Benjamin C. Pierce, editor, Advanced that SMLSC provides a good linguistic target for such tools. Topics in Types and Programming Languages, chapter 8, pages 293– 346. MIT Press, 2005. ML Basis. The MLton compiler [18] and ML Kit [17] implement [12] Robert Harper and Christopher Stone. An interpretation of Standard a language called ML Basis. A “basis” in their terminology is what ML in type theory. Technical Report CMU-CS-97-147, School of we call a unit. An ML Basis program is a series of declarations, Computer Science, Carnegie Mellon University, June 1997. including a binding construct for bases and an open construct for [13] Robert Harper and Christopher Stone. A type-theoretic interpretation basis identifiers. These are analogous to SMLSC’s unit declaration of Standard ML. In Gordon Plotkin, Colin Stirling, and Mads Tofte, and IC import declaration. Like SMLSC, the order of compila- editors, Proof, Language, and Interaction: Essays in Honour of Robin tion entities is explicit, and thus each program has unambiguous Milner. MIT Press, 2000.

Draft of June 6, 2006 8 2006/6/6 [14] Trevor Jim. What are principal typings and what are they good We usually omit the initial ·; for example, for? In Proceedings of the ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages. ACM Press, 1996. sigid 1=sig 1,..., sigid 1=sig 1. [15] Xavier Leroy, Damien Doligez, Jacques Garrigue, Didier Remy,´ • We define the domain of a signature abbreviation, dom(S), by and Jer´ omeˆ Vouillon. The Objective Caml system release 3.09: Documentation and user’s manual, 2005. http://caml.inria. dom(·) = ∅ fr/pub/docs/manual-/index.html. dom(S, sigid=sig) = dom(S) ∪ {sigid} [16] Robin Milner, Mads Tofte, Robert Harper, and David MacQueen. The dom(S, unitid=Su) = dom(S) ∪ {unitid}. Definition of Standard ML (Revised). MIT Press, 1997. • We define the function S++S0 by [17] MLKit web site. http://www.itu.dk/research/mlkit/index. 0 0 /Main_Page. (·++S ) = S ((sigid=sig,S)++S0) = [18] MLton web site. http://mlton.org/.  sigid=sig,S00 if sigid 6∈ dom(S00) [19] Greg Morrisett, David Walker, Karl Crary, and Neal Glew. From S00 otherwise system F to typed assembly language. ACM Transactions on where S00 = S++S0 Programming Languages and Systems, 21(3):527–568, 1999. 0 ((unitid=Su,S)++S ) = [20] Sergei Romanenko, Claudio Russo, and Peter Sestoft. Moscow ML  00 00 unitid=Su,S if unitid 6∈ dom(S ) owner’s manual version 2.00, June 2000. http://www.dina.kvl. 00 dk/~sestoft/mosml/manual.pdf. S otherwise where S00 = S++S0. [21] David Swasey, Tom Murphy, VII, Karl Crary, and Robert Harper. A separate compilation extension to Standard ML (extended technical It concatenates S and S0, making the result well-formed by report). Technical Report CMU-CS-06-133, School of Computer dropping signature abbreviations if dom(S) ∩ dom(S0) 6= ∅. Science, Carnegie Mellon University, 2006. • We write both “=” and “:=” in side-conditions. Interpreting the rules algorithmically, the former pattern-matches inputs, and A. Linking Rules the latter specifies an output.

The typed semantics defines a closed structure mod basis :sig basis decs ` L ok serving as an initial basis for the TSIL. The elaborator assumes Γ declares basis:sig basis , which includes components such as the built-in Match exception. This basis structure is introduced in decs ` sdecs0 ok Rule 6 for completion and Rule 12 for elaboration of source units decs, sdecs0 ` sbnds : sdecs in projects. decs, sdecs0, sdecs ` S ok (1) We use the following definitions and notation. sdecs0 = lab1Bvar 1:[sdecs1],..., labnBvar n:[sdecsn] decs ` sdecs → sbnds : sdecs; S ok • Writing BV(dec) for the variable declared by dec, we define 0 the bound variables of a structure declaration list, BV(sdecs), Rule 1: Imports are restricted to structures. The elaborator in Ap- by pendix B needs nothing else.

BV(lab1Bdec1,..., labnBdecn) = {BV(dec1),..., decs ` S ok BV(decn)}. ` decs ok A linkset (2) decs ` · ok L = sdecs0 → sbnds : sdecs; S decs ` sig : Sig decs ` S ok sigid 6∈ dom(S) binds variables BV(sdecs0) with scope sbnds : sdecs; S (3) and variables BV(sdecs) with scope S. We write BV(L) for decs ` sigid=sig,S ok BV(sdecs ) ∪ BV(sdecs). 0 decs ` S0 ok decs ` S ok unitid 6∈ dom(S) • For readability, we sometimes elide variables in structure bind- 0 S = (sigid 1=sig 1,..., sigid n=sig n) (4) ings and declarations. It should be immediately obvious how to 0 consistently restore these with fresh variables. decs ` unitid=S ,S ok • We assume that unit identifiers are disjoint from all other iden- L exp : {} tifier classes. • We assume that the TS overbar injection · maps identifiers of lab 6∈ dom(sdecs) different classes to different labels and that there are infinitely (5) · → sbnds : sdecs; S [sbnds, lab={}].lab : {} many labels not in its range. Lbasis := · → basis=mod basis : basis:sig basis ; · We assume that its range includes neither the distinguished 0 0 label basis, nor the labels chosen fresh in the rules. ` Lbasis ++L L L exp : {} (6) • Structure declaration lists sdecs, signature abbreviations S, and L exp : {}

so on specify lists of elements. We adopt the following notation 0 00 for lists. decs ` L++L L We denote by (·, ·) the operation of syntactic concatenation; for example, S, S0. L = sdecs0 → sbnds : sdecs; S 0 0 0 decs ` L++(· → sbnds : sdecs ; S ) (7) We sometimes use at the left end of a list, 0 0 0 writing sigid=sig,S to match the first binding in the list. sdecs0 → sbnds++sbnds : sdecs++sdecs ; S++S

Draft of June 6, 2006 9 2006/6/6 where {path/var}S denotes the capture-free substitution of 00 0 0 000 path var S σ sdecs = sdecs , labBvar :sig , sdecs for free occurrences of in . Rule 14 uses to 0 0 00 elaborate source units. decs, sdecs0, sdecs `sub var :sig  sig mod:sig 00 sbnd := labBvar=mod sdec := labBvar:sig project L L := sdecs0 → sbnds++sbnd : sdecs++sdec; S (8) 0 0 0 00 decs ` L++(sdecs1 → sbnds : sdecs ; S ) L (11) decs ` (sdecs0 → sbnds : sdecs; S)++ · (· → · : ·; ·) 0 0 0 00 (labBvar:sig, sdecs1 → sbnds : sdecs ; S ) L project L basis 6∈ BV(L) lab 6∈ dom(sdecs) L = sdecs0 → sbnds : sdecs; S 00 0 0 000 sdecs0 = sdecs , labBvar :sig , sdecs Γ := basis:sig basis ,R(sdecs0), sdecs; S 0 0 0 decs, sdecs0, sdecs ` sig ≡ sig : Sig Γ ` srcunit L var 6∈ BV(L ) 0 0 0 0 0 0 0 0 0 0 (12) L := {var /var}(sdecs1 → sbnds : sdecs ; S ) (9) sdecs1 → sbnds : sdecs ; S := {var/basis}L 0 00 0 decs ` (sdecs0 → sbnds : sdecs; S)++L L sdecs1 := basisBvar:sig basis , sdecs1 0 0 0 00 ` L++(sdecs1 → sbnds : sdecs ; S ) L decs ` (sdecs0 → sbnds : sdecs; S)++ 0 0 0 00 00 (labBvar:sig, sdecs1 → sbnds : sdecs ; S ) L project, srcunit L Rule 12: The side-condition basis 6∈ BV(L) can always be lab 6∈ dom(sdecs) ∪ dom(sdecs0) 0 achieved by renaming bound variables in L. decs, sdecs0, sdecs ` sig ≡ sig : Sig 0 decs, sdecs0 ` sig : Sig 0 project L L := sdecs0, labBvar:sig → sbnds : sdecs; S (10) 0 0 0 00 BV(L) ∩ BV(L0) = ∅ ` L0 ok ` L++L0 L00 decs ` L++(sdecs1 → sbnds : sdecs ; S ) L (13) 0 00 decs ` (sdecs0 → sbnds : sdecs; S)++ project,L L 0 0 0 00 (labBvar:sig, sdecs1 → sbnds : sdecs ; S ) L Γ ` srcunit L B. Elaboration Rules We change the TS elaborator to expand signature abbreviations. Γ ` topdec L First, we modify every TS elaboration judgement and rule us- L = sdecs0 → sbnds : sdecs; S ing a TS elaboration context sdecs to use sdecs; S. A context var 6∈ BV(Γ) ∪ BV(L) 0 sdec, sdecs; S binds the variable BV(sdec) with scope sdecs; S sbnds := unitidBvar=[sbnds] 0 (14) and a context sdecs; S binds variables BV(sdecs) with scope S. sdecs := unitidBvar:[sdecs] We define BV(Γ) by BV(sdecs). Second, we extend the syntax S0 := unitid=σ(var, sdecs,S) for TSEL signature expressions: Γ ` unit unitid = topdec 0 0 0 sigexp ::= ... sdecs0 → sbnds : sdecs ; S sigid signature identifier Γ ` topdec L Finally, we extend the TS judgement Γ ` sigexp sig : Sig, adding the rule Γ ` impexp L Γ `ctx sigid sig : Sig (15) Γ ` import impexp L Γ ` sigid sig : Sig Γ ` strdec sbnds : sdecs to elaborate signature identifiers. (16) We use the following definitions and notation. Γ ` strdec · → sbnds : sdecs; · • Γ = sdecs; S To extend an elaboration context , we write Γ ` sigbind S Γ, dec for sdecs, 1 dec; S, (17) B Γ ` signature sigbind · → · : ·; S Γ, sdecs0 for sdecs, sdecs0; S, and Γ,S0 sdecs; S, S0 for . Γ ` topdec sdecs0 → sbnds : sdecs; S We also define a function R(sdecs) that renames the labels in var 6∈ BV(Γ) ∪ BV(sdecs0) ? 0 0 sdecs to make them inaccessible to identifier resolution: Γ,R(sdecs0), 1 Bvar:[sdecs],S ` topdec L (18) L := sdecs0 → 1Bvar=[sbnds] : 1Bvar:[sdecs]; · R(lab dec ,..., lab dec ) = 1 dec ,..., 1 dec . 0 00 1B 1 nB n B 1 B n Γ ` L++L L 0 00 • We define a function U(sdecs) that drops the labels in sdecs: Γ ` local topdec in topdec end L U(lab1Bdec1,..., labnBdecn) = dec1,..., decn. Γ ` topdec L • L = sdecs0 → sbnds : sdecs; S When an elaboration context Γ = sdecs; S appears in a judge- 0 0 decs Γ Γ,R(sdecs0), sdecs,S ` topdec L (19) ment requiring an IL context , we implicitly coerce to 0 00 U(sdecs). Γ ` L++L L 0 00 • We define the substitution function σ(var, sdecs,S) by Γ ` topdec topdec L σ(var, ·,S) = S σ(var, (labBdec, sdecs),S) = {var.lab/BV(dec)}σ(var, sdecs,S)

Draft of June 6, 2006 10 2006/6/6 Γ ` impexp L

Γ `ctx unitid var : sig 0 Γ `ctx unitid S var 6∈ BV(Γ) 0 ? 0 ? (20) L := unitidBvar :sig → 1 =var : 1 :sig; S Γ ` unitid L Rule 20: Rules 12, 18, and 19 use R(·) to hide imported units from IR imports. The signature sig should be fully selfified.

0 Γ ` spec sdecs var 6∈ BV(Γ) Γ, var 0 :[sdecs] ` var 0 : sig 0 ? 0 ? (21) L := unitidBvar :[sdecs] → 1 =var : 1 :sig; · Γ ` unitid : intf spec end L Rule 21: The signature sig should be fully selfified.

0 0 Γ ` impexp L Γ ` impexp L 0 0 00 BV(L) ∩ BV(L ) = ∅ Γ ` L++L L (22) 0 00 Γ ` impexp impexp L

Γ ` sigbind S

Γ ` sigexp sig : Sig S := sigid=sig 0 0 hΓ ` sigbind S sigid 6∈ dom(S )i (23) 0 Γ ` sigid = sigexp hand sigbindi Sh,S i Rule 23: Either all optional elements or none must be present.

Γ `ctx sigid sig : Sig

(24) sdecs; S, sigid=sig ` sigid sig : Sig sigid 0 6= sigid sdecs; S ` sigid sig : Sig (25) 0 0 sdecs; S, sigid =sig ` sigid sig : Sig sdecs; S ` sigid sig : Sig 0 (26) sdecs; S, unitid=S ` sigid sig : Sig

Γ `ctx unitid S

0 0 (27) sdecs; S, unitid=S ` unitid S unitid 0 6= unitid 00 sdecs; S ` unitid S (28) 0 0 00 sdecs; S, unitid =S ` unitid S 0 sdecs; S ` unitid S 0 (29) sdecs; S, sigid=sig ` unitid S Γ ok

` U(sdecs) ok (30) sdecs; · ok sdecs; S ok sdecs ` sig : Sig (31) sdecs; S, sigid=sig ok sdecs; S ok sdecs ` S0 ok 0 S = (sigid 1=sig 1,..., sigid n=sig n) (32) sdecs; S, unitid=S0 ok

Draft of June 6, 2006 11 2006/6/6