core Java calculus intended to be a suitable starting point for investi- gations in the ... from the syntax and remove the (lock)/(unlock) rules from the semantics. For simplicity, we assume ...... http://www.cl.cam.ac.uk/research/pls/javasem/lj/. 11. Marko van ... Mandana Vaziri, Frank Tip, Julian Dolby, and Jan Vitek. Type-based ...
Welterweight Java ¨ Johan Ostlund, Tobias Wrigstad, and Jan Vitek Purdue University
Abstract This paper presents Welterweight Java (WJ), a new minimal core Java calculus intended to be a suitable starting point for investigations in the semantics of Java-like programs. To this end, WJ adds a few extra pounds to Featherweight Java. WJ is imperative and stateful, which is a frequent extension of Featherweight Java. To account for the importance of concurrency, WJ models Java’s thread-based concurrency and lock-based synchronisation. The design of WJ is distilled from recent work on concurrent Java-like systems. We believe that the calculus is a good starting point for extensions. We illustrate the potential of the calculus with a version of WJ extended with deep ownership. This serves two purposes—it is a minimal formalisation of ownership, interesting in its own right, and shows how easily WJ can be extended.
1
Introduction
Standard formalisms for Java-like languages greatly simplify formal investigations of novel programming constructs. Not only do they allow reuse of sound boilerplate definitions, but they greatly enhance readability and comparisons and combinations of different proposals. Featherweight Java (FJ) [7] is the currently most popular Java formalism and is both simple and concise due to careful selection of features. An interesting omission is mutable state, which is at the heart of most Java programs. In FJ objects are immutable and field updates result in new objects. While in many cases sufficient, it makes FJ a less suitable basis for formalising language constructs that interplay with aliasing. Moreover, FJ does not model threads and synchronisation, which is a significant omission in this day and age. This paper presents Welterweight Java (WJ) as an alternative core calculus to FJ when capturing Java’s imperative features is important. WJ models Javastyle threads and Java-style concurrency control, supports aliasing and threadlocal stack frames. WJ is based on statements rather than expressions and uses explicit casts in favour of implicit subsumption. The resulting calculus is small and managable and fits comfortably on less than five pages in LNCS format. WJ is distilled from two recent Java-like formalisms by the authors [14,12] that needed imperative features and thread support. As a result, the formalism is malleable and easily extensible, as illustrated in this paper by the extension of WJ into WOJ—a minimal deep ownership system. We are working continuously to improve the extensibility of WJ. This paper represents the current state of the system. It is based on internal needs and our
understanding of what most researchers want in a core formalism. To this end, we do not model access modifiers, final fields or generics. To facilitate widespread adoption, we are making WJ’s LATEX sources available on-line [9]. In the future, these will be accompanied by Ott sources and mechanised proofs. However, in our experience, having a spatially minimal formalism is important. While Ott is a great tool it often falls short in this respect.
2
Introducing Welterweight Java
WJ’s syntax is shown in Fig. 1. To simplify matters, WJ only has statements and every statement assigns to a field or variable. In WJ fields are not final. Local variables must be declared at the beginning of a method before any statements are executed. Fields and variables are initialised with null and there is no null literal in the syntax. The class Object is at the root of every class hierarchy. It is defined implicitly for every program P as class Object { }. For brevity, it is omitted from the static syntax. In the dynamic syntax, we include return y in s. Synchronisation blocks are modelled through lock and unlock statements. Removing locks from the formalism is as simple as removing lock and unlock from the syntax and remove the (lock)/(unlock) rules from the semantics. For simplicity, we assume that classes and fields have unique names. Class-Table For functions and relations g, g 0 , we define g • g 0 as: g(x) if g(x) is defined, otherwise g 0 (x). For tuples, (F , M ) • (F 0 , M 0 ) = (F • F 0 , M • M 0 ). For a program P , we define the class table CT as: CT (c) = (F , M ) • CT (d) when class c extends d { F M } ∈ P . For Object, we define CT (Object) = (, ) and (x) = ⊥. Now, lookup in combined tuples models lookup in inheritance hierarchies and lookups of non-existing elements return ⊥ and ⊥(x) = ⊥. We use a number of shorthands to access the class-table: fields(c) = fst(CT (c)), methods(c) = snd (CT (c)) and write ftype(c.f ) to mean fields(c)(f ). Where convenient, we sometimes use fields(c) to mean the set {c f } obtained by replacing • with ∪ in fst(CT (c)). Furthermore define mbody(c.m) as (x, x0 , s;return y)
P C F /V M s t
::= ::= ::= ::= ::= | ::=
C class c extends d { F M } tf /tx t m(t x) { V s; return y } s; s | skip | x = y.f | x = y | y.f = z | x = new t() x = (t) z | x = y.m(z) | x = start t() | lock z | unlock z c
program class field / locals method statement
Figure 1. WJ’s syntax. c,d are class names, f ,m are field and method names, and x , y, z are names of variables or parameters respectively, where x 6= this. By convention, y is always used in receiver position and z in argument position. For simplicity, we assume that names of classes and fields are unique. The special variable ret only appears in the dynamic syntax and deals with method return.
2
(wf-class)
` C for all C ∈ P
P (c) = class d · · · { F 0 M 0 } `F this : c ` M ∀m ∈ names(M ). mtype(c.m) = mtype(d.m) ∨ mtype(d.m) = ⊥
`P
` class c extends d { F M }
(wf-program)
(wf-method)
(wf-field) (wf-root-class)
`t
` class Object { }
`tf
(s-sequence)
E`s
`E
E0 ` s
E0 ` y : t
E ` t m(t x){ t0 x0 s; return y }
(s-skip)
E ` s0
E ` s; s0
E 0 = E, t x, t0 x0
(s-assign)
E`x:t
E ` skip
(s-new)
E`y:t
E`x=y
(s-select)
(s-update)
E`y:t E ` x : ftype(t.f )
E`y:t E ` z : ftype(t.f )
E ` x = y.f
E ` y.f = z
E`x:t E ` x = new t()
(s-fork)
(s-cast)
E ` z : t0 E`x:t
mtype(t, run) = → E`x:t E ` x = start t()
E ` x = (t) z
(s-call)
(s-lock)
(s-unlock)
(var)
E ` y : t mtype(t, m) = t → t0 E`z:t E ` x : t0
`E z ∈ dom(E)
`E z ∈ dom(E)
`E E(y) = t
E ` x = y.m(z)
E ` lock z
E ` unlock z
E`y:t
Figure 2. WJ’s static semantics. E is the standard type environment mapping variables to types. Following ClassicJava [6], we use · · · for “unimportant omissions.”
and mtype(c.m) as t → t when methods(c.m) = t m(t x){ c0 x0 s;return y } and ⊥ otherwise. Last, we also define a shorthand for retrieving the names of fields and methods of a class names(t f ) = f and names(t m( · · · ){ · · · }) = m. 2.1
Static Semantics
WJ’s static semantics are shown in Fig. 2. A program is a number of class declarations. Class hierarchies are rooted in Object. A program is well-formed (WF) if its classes are WF. A class is WF its fields and methods are WF and overriding methods preserve types. A method is WF if its body is WF under the store type E ::= [ ] | E[y : t] formed by the current this, the method’s parameters and local variable declarations. Note that E is WF by construction (var). WF statements can be sequenced in the standard fashion to form a WF compound statement. Without loss of generality, subsumption is replaced by explicit casts. Assignment to a field or variable is WF if the type of the RHS is the same as the declared type of the LHS. The type of a field is the field’s declared type in the receiver. A method call is WF if the arguments’ types are the same as the parameters’ types. The type of the method is obtained by looking it up in the declared type of the receiver, obtained from E. Forking a new thread is WF if the object has a run method that takes no arguments. Last, synchronising is 3
only allowed on defined variables. The helper rule (var) looks up a variable’s type in a WF E. 2.2
Dynamic Semantics
WJ’s dynamic semantics are formalised as a small-step reduction semantics. The l reduction relation −→ represents a step of evaluation. The label l describes the action. Basic thread-scheduling is modelled as a non-deterministic choice in (dschedule). Each step picks one of the threads for reduction and performs one action. Deadlocks is the only thing that can lead to reduction being stuck. A configuration consists of a heap H and an unordered collection of threads, T . A heap H ::= [ ] | H[ι 7→ (c, ρ, F )] is a map from locations ι to objects, triples of type, locking thread (possibly none, denoted ) and fields F . Fields, and also stack frames, F ::= [ ] | F [y 7→ v] are maps from field names f or variable names x, y, z to values v ::= ι | null. A thread consists of a stack S and a thread id ρ. A stack is an ordered list of frame and statement tuples hF, si. The last statement of each frame is a return. The reductions are mostly standard. Method calls are reduced to assignments from the special variable ret. Returns assign to ret of the stack-frame below. Reductions for null-pointer dereferencing and cast errors both reduce to ERR and can be found in Fig. 5. Reduction on an error is modelled in (d-dead) and notably removes the thread’s lock on all objects in the heap before the thread itself is descheduled. Taking a lock on an object that is already locked cannot be reduced. If all threads in the system are in this state, the system is deadlocked and the reduction is stuck, see second clause of Theorem 1 (Progress). Initial Configuration Rather than having trailing expressions in a program, we pick a run method in some class and call it. Effectively, the initial configuration is thus [ι 7→ (C, , [])] | hF [this 7→ ι], s; return yi where C is the name of the class whose run method we selected, and F , s and y are derived from run. 2.3
Meta-Theory
A configuration is WF under a Γ ::= [ ] | Γ [ι : c], a standard store-type and Ψ , the set of ids of all active threads. A thread is WF if its ρ is in Ψ , and each frame is WF under Γ and some local type environment E. A frame is WF if its locals are WF, the statement is WF and the returned variable is defined. Finally, a heap H is WF under Γ, Ψ if the types of all objects in H correspond to those in Γ , all locks are held by known threads (in Ψ ) and values in fields correspond to the declared types. We formulate the usual progress and preservation theorems. We omit the “scheduling reduction” in (d-schedule) as it follows trivially from the rest. Due to space restrictions, we only sketch the proofs here. Full proofs will be made available in a companion technical report on the WJ web pages [9]. 4
(sub-dir)
(sub-trans)
P (c) = class c extends d · · ·
` t ≤ t0
` t ≤ t00
`c≤d
(sub-ref)
(type)
`t
P (c) = class c · · ·
`t≤t
`c
` t0 ≤ t00
Figure 3. Types
(d-schedule)
(d-dead)
l
H | T,T ,T 0 −→ H | T 00,T ,T 0 H
| T, T,T 0
−→ H
(d-return)
| T 00,T ,T 0
F (y) = v fin
0
H|hF, return yi ρ, T −→ H 0 |T
H|ERR ρ, T −→ H |T F (y) = v ret
(d-select)
(d-update)
(d-call)
err
H 0 = unlock(ρ, H)
H | S hF 0 , si, hF, return yi ρ, T −→ H | S hF 0 [ret 7→ v], si ρ, T
(d-assign)
(d-new)
(d-finished)
H 0 = unlock(ρ, H)
F (y) = v asgn
H | S hF, x = y; si ρ, T −→ H | S hF [x 7→ v], si ρ, T F (y) = ι
H(ι.f ) = v sel
H | S hF, x = y.f ; si ρ, T −→ H | S hF [x 7→ v], si ρ, T
F (y) = ι
H 0 = H[ι 7→ (t, ρ, F [f 7→ v])
F (z) = v
up
H[ι 7→ (t, ρ, F ) | S hF, y.f = z; si ρ, T −→ H 0 | S hF, si ρ, T
F 0 = [f 7→ null | t0 f ∈ fields(t)]
H 0 = H[ι 7→ (t, , F 0 )]
ι is fresh
new
H | S hF, x = new t(); si ρ, T −→ H 0 | S hF [x 7→ ι], si ρ, T F (y) = ι H(ι) = (t, · · ·) mbody(t.m) = (x0 , x00 , s0 ; return y 0 ) 0 0 F (z) = v F = [this 7→ ι][x 7→ v][x00 7→ null] S 0 = S hF, x = ret; si call
H | S hF, x = y.m(z); si ρ, T −→ H | S 0 , hF 0 , s0 ; return y 0 i ρ, T
(d-cast)
(d-fork)
F (z) = null
∨
F (z) = ι
H(ι) = (t0 , · · ·)
` t0 ≤ t
cast
H | S hF, x = (t) z; si ρ, T −→ H | S hF [x 7→ F (z)], si ρ, T F 0 = [f 7→ null | t f ∈ fields(t)] H 0 = H[ι 7→ (t, , F 0 )] T = h[this 7→ ι][x 7→ null], s0 ; return y 0 i, ρ0 mbody(t.run) = (, x, s0 ; return y 0 ) ι and ρ0 are fresh fork
H | S hF, x0 = start t(); si ρ, T −→ H 0 | S hF [x 7→ ι], si ρ, T , T
(d-lock)
(d-unlock)
F (z) = ι
H = H 0 [ι 7→ (t, ρ0 , F 0 )] lock
0
ρ0 ∈ {, ρ} 0
H | S hF, lock z; si ρ, T −→ H [ι 7→ (t, ρ, F )] | S hF, si ρ, T H = H 0 [ι 7→ (t, ρ, F 0 )]
F (z) = ι
unlock
H | S hF, unlock z; si ρ, T −→ H 0 [ι 7→ (t, , F 0 )] | S hF, si ρ, T
unlock(ρ, []) = []
unlock(ρ, H[ι 7→ (t, ρ0 , F )]) = unlock(ρ, H)[ι 7→ (t, ρ0 [/ρ], F )] Figure 4. WJ’s dynamic semantics.
5
(d-skip)
(d-select-err)
(d-update-err)
(d-call-err)
skip
H; (S hF, skip; si, ρ); T −→ H; (S hF, si, ρ), T sel.err
H; (S hF [y 7→ null], x = y.f ; si, ρ); T −→ H; (ERR, ρ), T up.err
H; (S hF [y 7→ null], y.f = z; si, ρ); T −→ H; (ERR, ρ), T call.err
H; (S hF [y 7→ null], x = y.m(z); si, ρ); T −→ H; (ERR, ρ), T
(d-cast-err) (d-lock-err)
(d-unlock-err)
F (z) = ι
H(ι) = (t0 , · · ·)
` t0 6≤ t
cast.err
H | S hF, x = (t) z; si ρ, T −→ H; (ERR, ρ), T lock.err
H; (S hF [z 7→ null], lock z; si, ρ); T −→ H; (ERR, ρ), T
F (z) = null
∨
F (z) = ι
H; (S hF, unlock z; si, ρ); T
H(ι) = (t, ρ0 , F 0 )
ρ0 6= ρ
unlock.err
−→ H; (ERR, ρ), T
Figure 5. WJ’s dynamic semantics part II (error reductions and skip).
Theorem 1 (Progress). If Γ, Ψ ` H | T, T , then either l
1. ∃ l 6= lock s.t. H | T, T −→ H 0 | T 0 , T ; or lock 2. H | T, T −→ H 0 | T 0 , T where T = S hF [z 7→ v], lock z; s0 i, ρ and v = null or v = ι and H(ι) = ( , ρ0 , ) s.t. ρ0 ∈ {ρ, }. A non-locking reduction is always possible and a locking reduction is possible if the subject is not locked, or already locked by the current thread. Proof. The proof is straightforward by structural induction on the shape of T where most cases are trivial. Reductions which may err at run-time, (d-select), (d-update), (d-call), (d-cast), (d-lock) and (unlock), are all guarded by error versions (Fig. 5) of the rule that deal with null-dereferencing, invalid casts and attempts at releasing a lock that one does not own. By (wf-heap) and (wfframe), a well-formed object (t, ρ, F ) has all expected fields in F . t u l
Theorem 2 (Preservation). If Γ, Ψ ` H | T, T and H | T, T −→ H 0 | T 0 , T , then there exists Γ 0 , Ψ 0 s.t. Γ 0 , Ψ 0 ` H 0 | T 0 , T Since there are no expressions in WJ, preservation concerns preserving the types of fields and local variables. Proof. The proof is by structural induction on the shape of T . Reduction must preserve types in variables and fields, and method returns must correspond to the declared return type of the method. The existence of an E, s.t, Γ ; E ` F and E ` s, ensures that types of variables and fields will be WF and, furthermore, types of RHS’s and LHS’s will be equivalent as we do not model implicit subsumption. The proof relies heavily on Lemma 1 (Lookup). t u 6
(wf-E) (-E/-Γ )
`E
` []
`t
(wf-Γ )
y 6∈ dom(E)
`Γ
`t
` E[y : t]
Γ ; [ ]/{} ` [ ]
(wf-threads)
Γ;Ψ ` H
Γ;Ψ ` T
Γ;Ψ ` H |T
(wf-frame)
∃E. Γ ; E ` hF, si
Γ;E ` F
`E
(wf-locals/fields)
y ∈ dom(E)
Γ;E ` F
Γ ; E ` hF, return yi
`t
Γ ; fields(c) ` F
(-heap)
Γ `v:t
Γ ; E[y : t] ` F [y 7→ v]
(wf-heap)
Γ;Ψ ` H
E`s
Γ ; E ` hF, si
Γ ; Ψ, ρ ` hF, si ρ, T
(wf-return)
Γ;E ` F
`Γ
` Γ [ι : t]
(wf-config)
Γ;Ψ ` T
(-frame/∗)
ι 6∈ dom(Γ )
[ ]; Ψ ` [ ]
(wf-ptr)
ρ ∈ Ψ ∪ {}
∨
v = null
Γ [ι : t]; Ψ ` H[ι 7→ (t, ρ, F )]
` Γ (v) ≤ t
Γ `v:t
Figure 6. Well-Formedness Rules. ∗=(no-threads), i.e., when there are no threads in a system. In (wf-fields) y should be f .
Lemma 1 (Lookup). If Γ, Ψ ` H, Γ (ι) = c and fields(c.f ) = t, then H(ι.f ) = v s.t., v = null or Γ (v) = t. If Γ, Ψ ` H, Γ ; E ` F and E(y) = t, then F (x) = v s.t., v = null or Γ (v) = t. Proof. Follows by straightforward induction on the definition of (wf-heap) and (wf-locals) respectively. t u Lemma 2 (Live Locks). If Γ, Ψ ` H | T, T , then ∀ι ∈ H. H(ι) = ( , ρ, ) s.t. ρ ∈ {, Ψ } (Object are either unlocked or locked by an existing thread.) Proof. Follows by straightforward induction on (wf-config).
3
Introducing Welterweight Ownership Java
To demonstrate how easily WJ can be extended, we define “Welterweight Ownership Java,” WOJ, a minimal deep ownership system [3] similar to [4]. The syntactic differences to WJ are minimal: C ::= class chowner, pi extends d hαi { F M }
t ::= chpi
where p, α are owner parameters. Owner (parameters) are unique names, modulo the special owners this, owner, and world. In contrast to more complicated ownership systems (e.g., [2,8]), we nest all owner parameters outside owner. We often write types thus, chσi where sigma is a map, {p 7→ α} from owner parameters declared in class headers to actual owners α where the first p is always the special parameter owner. For example, for a class class C instantiated in the type Foo, we would write Foo where σ = {owner 7→ a, p 7→ 7
(o-wf-class)
owner 6∈ {p, α} E = this : chowner, pi E ` dhowner, αi E`F E`M ∀m ∈ names(M ). mtype(c.m) = mtype(d.m) ∨ mtype(d.m) = ⊥
(o-wf-field)
` class chowner, pi extends d hαi { F M }
E`tf
E`t
(o-s-cast)
(o-s-select)
(o-s-update)
E ` z : t0 E ` x : t E ` t0 ≤ t
E ` this : chσi E ` x : σ(ftype(c.f ))
E ` this : chσi E ` z : σ(ftype(c.f ))
E ` x = (t) z
E ` x = this.f
E ` this.f = z
(o-s-call)
E`z:t
E ` y : chσi E ` x : t0
(o-s-fork)
mtype(c, m) = t → t0 this ∈ owners(t0 , t) ⇒ y = this
E ` x = y.m(z)
mtype(c, run) = → E ` x : chσi E ` x = start chσi()
Figure 7. The differing type rules in WOJ. For simplicity, we only allow up-casts, and fields are no longer public. We define owners(chpi) to be {p}.
b, q 7→ c}. The σ is used frequently for “viewpoint adaptation,” [2,13,14], which is defined as straightforward substitution. F.ex., if a field in the class Foo above has type Bar, accessing the field via a variable typed Foo types the field to Bar, i.e., σ(Bar). Note that this is unchanged because there is no mapping from this in σ. Class-tables see a minimal change due to owner substitution. CT (c) when P (c) = class chpi extends d hσi { F M } is defined as (F , M ) • σ(CT (d)). Here, σ is the map from the owner parameters in d’s class header to the actual owners “passed to d” in the declaration of c. Fig. 7 shows the changes to the static semantics. New sub-rules are owner 6∈ {p, α} and E ` dhαi to make sure sufficient owner parameters are passed to the super class. For simplicity, we restrict casts to up-casts. Dealing with casts in ownership systems is tricky (see, e.g., [13]) and generally ignored. Rules (o-s-select), (o-s-update), and (o-s-call) use viewpoint adaptation and only private fields are allowed. Furthermore, calls to methods that have this in their type are only allowed on a this receiver. No changes to the dynamic semantics are necessary. As seen in Fig. 8, ownership types requires more complex type rules. A type is WF if all its owner parameters are outside the first owner parameter. As a simplification over all previous systems, we derive nesting from types in E rather than extend it with nesting information. This requires only one minimal change to ` E, allowing this’s type to define nestings, rather than be required to satisfy nestings already in E. The rules for deriving nestings and WF types under Γ are copy-and-patch (e.g., replacing y for ι in (inside)) from the static semantics and therefore omitted. As usual, this is nested inside all visible owners (inside) and world is the global outermost owner (world). 8
(o-type)
(o-sub-dir)
(o-sub-trans)
P (c) = class chpi · · · E ` α ≺∗ α |p| = |α, α|
E ` chαi σ = {p 7→ α} P (c) = class chpi extends dhα0 i · · ·
E ` t ≤ t00 E ` t00 ≤ t0
E ` chα, αi
E ` chαi ≤ dhσ(α0 )i
E ` t ≤ t0
(trans)
(inside)
E ` p ≺∗ p0 E ` p0 ≺∗ q
∃ y. E ` y : chα, αi q ∈ {y, α} q 0 ∈ {α, α}
E ` p ≺∗ q
E ` q ≺∗ q 0
(wf-owner) (world)
(reflex)
E`p
E`p
∃ y. E ` y : chαi p ∈ {y, α, world}
E ` p ≺∗world E ` p ≺∗ p
E`p
Figure 8. WOJ Types and Owners. For brevity, we omit the trivial (o-sub-refl). In (inside) and (wf-owner), we use y as a good owner when y = this.
(o--E)
(o-wf-E)
(o-wf-Γ )
(o-wf-heap)
P (c) = class chpi · · · |p| = |α|
E`t x 6∈ dom(E)
` Γ Γ ` chσi ι 6∈ dom(Γ )
ρ ∈ Ψ Γ ; Ψ ` H Γ ` chσi Γ ; σ(fields(c)) ` F t = chσi
` this : chαi
` E[x : t]
` Γ [ι : chσi]
Γ [ι : t]; Ψ ` H[ι 7→ (t, ρ, F )]
Figure 9. Updated WF rules in WOJ. E now always starts with this (to allow it to define basic nestings). For brevity, we omit the definitions of Γ ` t, Γ ` p, and Γ ` p ≺∗ q as they are copy-and-patch from the equivalent rules under E.
3.1
Meta-Theory
The changes to the well-formedness rules are minimal. The store type now maps locations to types with owner parameters and (o-wf-heap) applies viewpoint adaptation to translate owner names in declared field types to actual owners. As the rules for well-formed type, owner and owner nestings are equivalent under E and Γ , modulo minor syntactic differences, we omit the latter. Run-time owners are locations ι or the special world. The progress and preservation theorems are notably unchanged. Additionally, we formulate the standard owners-as-dominators theorem [3] thus: Theorem 3 (Owners-as-Dominators). If Γ ; Ψ ` H, then ∀ι, ι0 s.t. H(ι) = ( , , F ), ι0 ∈ rng(F ) and Γ (ι0 ) = dhα0 , i then Γ ` ι ≺∗ α0 . In plain English, an object ι that references another object ι0 in one of its fields, must be inside the owner of ι0 . As the inside relation is reflexive, this holds even when ι0 is in the rep of ι. Proof. (Sketch) The proof is reminiscent of [3]. Assume a class has owners this, world, owner and one class parameter p in its E. At run-time, ι has some type chσi s.t. σ = {p 7→ p0 } and thus, ι is inside {owner, σ(p), world} by (world) and (inside). By (o-wf-heap) and (o-wf-type), the outside nesting is upheld by objects in Γ . Thus, ι is inside all owners that can appear in the types of all fields in ι, so clearly Γ ` ι ≺∗ α0 . t u 9
4
Related Work
In addition to Featherweight Java [7] which has been discussed in the introduction, several core formalisms have been proposed over the years. Flatt, Krishnamurthi and Felleisen’s ClassicJava [6] is imperative and supports aliasing and mutable objects. Originally constructed to bootstrap a proposal for adding Mixins to Java, the clean and concise formalism has been extended several times (e.g., [5,11]). While relatively simple, ClassicJava defines no less than 27 different predicates and relations for its static semantics alone. WJ removes interfaces from the formalism, which simplifies type rules and wellformedness rules, but on the other hand add stack frames, local variables, threads and locks. Bierman, Parkinson and Pitts model Java’s imperative features in MJ, Middleweight Java, [1]. In this respect, WJ is similar to MJ, but the MJ formalism is much too detailed to be used as a core formalism. For example, MJ distinguishes between statements, expressions, and expressions that can be promoted to statements. While this closely and accurately reflects the way Java works, it is a level of detail that most Java-like formalisms do not concern themselves with. MJ also does not model threads. We believe that the level of detail in MJ is mostly in the way. Parkinson and Strniˇsa’s LJ [10] is an extensible minimal imperative fragment of Java and the closest one to WJ. It’s Ott definition and relatively accessible Isabelle/HOL proofs are available on-line and thus LJ serves a good starting point where mechanised proofs are desired. WJ and LJ are similar in that they both only have statements. LJ uses implicit subsumption instead of casts and does not have stack frames nor threads and synchronisation.
5
Conclusion
We have presented WJ, a minimal imperative Java formalism. We argue that WJ is a suitable core Java formalism for extensions to Java-like languages that need imperative features and threads. The core formalism has been extracted from recent work on Loci [14], a system for simple thread-locality in Java, and AtomicJava [12], adding type-based data-centric synchronisation to Java. Subsets of WJ has also been used in Mini-Thorn [15], adding a novel form of gradual typing to a Java-like language. The WJ formalism is very concise and easy to fit into even a short paper, as demonstrated here. Dealing with statements only and avoiding implicit subsumption simplifies proofs and reduces proof sizes. The full proofs for WJ will be made available on the WJ web site [9] along with the LATEX sources for easy inclusion into a paper. We are constantly improving WJ and hope to get valuable feedback on what is desirable in a core formalism at FTfJP from the formal-savvy community. Acknowledgements We thank Sylvain Lebresne for comments on the presentation. 10
References 1. Gavin M. Bierman, Matthew J. Parkinson, and Andrew M. Pitts. MJ: An imperative core calculus for Java and Java with effects. Technical report, University of Cambridge, 2003. 2. Dave Clarke and Tobias Wrigstad. External Uniqueness is Unique Enough. In ECOOP 2003 – Object-Oriented Programming, volume 2743/2003 of Lecture Notes in Computer Science, pages 59–67. Springer Berlin / Heidelberg, 2003. 3. David Clarke. Object Ownership and Containment. PhD thesis, School of Computer Science and Engineering, University of New South Wales, Sydney, Australia, 2001. 4. David Clarke and Sophia Drossopolou. Ownership, encapsulation and the disjointness of type and effect. In Proceedings of OOPSLA, November 2002. 5. Curtis Clifton and Gary T. Leavens. MiniMAO1 : Investigating the semantics of proceed. Science of Computer Programming, 63(3):321–374, 2006. 6. Matthew Flatt, Shriram Krishnamurthi, and Matthias Felleisen. A programmer’s reduction semantics for classes and mixins. 1523, 1999. 7. Atsushi Igarashi, Benjamin C. Pierce, and Philip Wadler. Featherweight Java: a minimal core calculus for Java and GJ. ACM TOPLAS, 23(3):396–450, 2001. ¨ 8. Johan Ostlund, Tobias Wrigstad, Dave Clarke, and Beatrice ˚ Akerblom. Ownership, Uniqueness, and Immutability. In Objects, Components, Models and Patterns (Proceedings of 46th International Conference on Objects, Models, Components, Patterns), volume 11 of Lecture Notes in Business Information Processing, pages 178–197. Springer Berlin Heidelberg, 2008. ¨ 9. Johan Ostlund, Tobias Wrigstad, and Jan Vitek. Welterweight Java, 2009. http: //www.cs.purdue.edu/homes/jostlund/wj. 10. Matthew Parkinson and Rok Strniˇsa. Lightweight Java web pages, 2008–2009. http://www.cl.cam.ac.uk/research/pls/javasem/lj/. 11. Marko van Dooren and Wouter Joosen. A modular type system for first-class composition inheritance. Technical Report Report CW 534, Department of Computer Science, K.U.Leuven, January 2009. 12. Mandana Vaziri, Frank Tip, Julian Dolby, and Jan Vitek. Type-based data-centric synchronization, 2009. Submitted. 13. Tobias Wrigstad and Dave Clarke. Existential owners for ownership types. Journal of Object Technology, 6(4), May/June 2007. 14. Tobias Wrigstad, Filip Pizlo Fadi Meawad, Lei Zhao, and Jan Vitek. Loci: Simple Thread-Locality for Java. To appear at ECOOP 2009. ¨ 15. Tobias Wrigstad, Francesco Zappa Nardelli, Sylvain Lebresne, Johan Ostlund, and Jan Vitek. Integration of Typed and Untyped Code in Thorn, 2009. Submitted.
11