Predicate Dispatching: A Uni ed Theory of Dispatch

Michael Ernst Craig Kaplan Craig Chamb ers

Technical rep ort UW-CSE-98-01-0 2

Department of Computer Science and Engineering

UniversityofWashington

Seattle, WA, USA 98195-2350

fmernst;csk;[email protected]

http://www.cs.washington.edu/research/projects/cecil/

12 January 1998

Abstract

Predicate dispatching generalizes previous metho d dispatch mechanisms by p ermitting arbitrary predicates

to control metho d applicability and by using logical implication b etween predicates as the overriding relation-

ship. The metho d selected to handle a message send can dep end not just on the classes of the arguments, as

in ordinary ob ject-oriented dispatch, but also on the classes of sub comp onents, on an argument's state, and

on relationships b etween ob jects. This simple mechanism subsumes and extends ob ject-oriented single and

, ML-style pattern matching, predicate classes, and classi ers, which can all b e regarded

as syntactic sugar for predicate dispatching. This pap er intro duces predicate dispatching, gives motivating

examples adapted from a prototyp e implementation, and presents its static and dynamic semantics.

1 Intro duction

Many programming languages supp ort some mechanism for dividing the b o dy of a generic function into

a set of cases, with a declarative mechanism for selecting the right case for each dynamic invo cation of the

. Case selection can b e broken down into tests for applicability a case is a candidate for

invo cation if its guard is satis ed and overriding which selects one of the applicable cases for invo cation.

Ob ject-oriented languages use overloaded metho ds as the cases. A metho d is applicable if the run-time

class of the receiver argument is the same as or a sub class of the class on which the receiver is sp ecialized.

+

Multiple dispatching [BKK 86, Cha92] enables testing the classes of all of the arguments. One metho d over-

rides another if its sp ecializer classes are sub classes of the other's, using either lexicographic CLOS [Ste90]

or p ointwise Cecil [Cha93a] ordering.

Predicate classes [Cha93b] automatically classify an ob ject of class A as an instance of virtual sub class

B a sub class of A whenever B 's predicate an arbitrary expression typically testing the runtime state of an

ob ject is true. This creation of virtual class hierarchies makes metho d dispatching applicable even in cases

where the e ective class of an ob ject maychange over time. Classi ers [HHM90b] and mo des [Tai93] are

similar mechanisms for reclassifying an ob ject into one of a numb er of sub classes based on a case-statement-

like test of arbitrary b o olean conditions.

Pattern matching as in ML [MTH90] bases applicability tests on the run-time datatyp e constructor

tags of the arguments and their sub comp onents. As with classi ers and mo des, textual ordering determines

+

overriding. Some languages, such as Haskell [HJW 92], allow arbitrary b o olean guards to accompany pat-

terns, restricting applicability. Views [Wad87] extend pattern matching to abstract data typ es by enabling

them to o er various concrete datatyp e-likeinterfaces.

Predicate dispatching integrates, generalizes, and provides a uniform interface to these similar but previ-

ously incomparable mechanisms. A metho d declaration sp eci es its applicability via a predicate expression, 1

E 2 expr The set of expressions in the underlying programming language

T 2 typ e The set of typ es in the underlying programming language

c 2 class-id The namespace of classes

m; f 2 metho d-id The namespace of metho ds and elds

p 2 pred-id The namespace of predicate abstractions

v; w 2 var-id The namespace of variables

Figure 1: Syntactic domains and variables

which is a logical formula over class tests i.e., tests that an ob ject is of a particular class or one of its sub-

classes and arbitrary b o olean-valued expressions from the underlying programming language. A metho d is

applicable when its predicate expression evaluates to true. Metho d m overrides metho d m when m 's pred-

1 2 1

icate logically implies that of m ; this relationship is computed at compile time. Static typ echecking veri es

2

that, for all p ossible combinations of arguments to a generic function, there is always a single most-sp eci c ap-

plicable metho d. This ensures that there are no message-not-understo o d errors called match-not-exhaustive

in ML or message-ambiguous errors at run-time.

Predicate expressions capture the basic primitive mechanisms underlying a wide range of declarative

dispatching mechanisms. Combining these primitives in an orthogonal and general manner enables new sorts

of dispatching that are not expressible by previous dispatch mechanisms. Predicate dispatching preserves

several desirable prop erties from its ob ject-oriented heritage, including that metho ds can b e declared in

any order and that new metho ds can b e added to existing generic functions without mo difying the existing

metho ds or clients; these prop erties are not shared by pattern-matching-based mechanisms.

Section 2 intro duces the syntax, semantics, and use of predicate dispatching through a series of examples.

Section 3 de nes its dynamic and static semantics formally. Section 4 discusses predicate tautology testing,

which is the key mechanism required by the dynamic and static semantics. Section 5 surveys related work,

and Section 6 concludes with a discussion of future directions for research.

2 Overview

This section demonstrates some of the capabilities of predicate dispatching byway of a series of examples. We

incrementally present a high-level syntax which app ears in full in Figure 5; Figure 1 lists supp orting syntactic

domains. Predicate dispatching is parameterized by the syntax and semantics of the host programming

language in which predicate dispatching is emb edded.

2.1

Each metho d implementation has an attached predicate expression which sp eci es when the metho d is ap-

plicable. Predicate expressions include class tests and negations, conjunctions, and disjunctions of predicate

expressions. An omitted predicate expression indicates that its metho d handles all typ e-correct arguments.

metho d-sig ::= signature m  h T i : T

metho d-decl ::= metho d m  h formal-pattern i  [ when pred-expr ] metho d-b o dy

pred-expr ::= expr @ c succeeds if expr evaluates to an instance or

sub class of class c

j not pred-expr negation

j pred-expr and pred-expr conjunction short-circuited

j pred-expr or pred-expr disjunction short-circuited

Metho d signature declarations give the typ e signature shared by a family of metho d implementations.

A message send expression need examine only the corresp onding metho d signature declaration to determine

its typ e-correctness, while a set of overloaded metho d implementations must completely and unambiguously

implement the corresp onding signature in order to b e typ e-correct. 2

Predicate dispatching can simulate b oth singly- and multiply-dispatched metho ds by sp ecializing formal

parameters on a class via the \@class" syntax. Sp ecialization limits the applicability of a metho d to ob jects

that are instances of the given class or one of its sub classes. ML-style pattern matching is mo deled by

considering each constructor of a datatyp e to b e a class and sp ecializing metho ds on the constructor classes.

More generally, predicate dispatching supp orts the construction of arbitrary conjunctions, disjunctions, and

negations of class tests. The following example uses predicate dispatching to implement the Zip function

1

which converts a pair of lists into a list of pairs:

type List;

class Cons subtypes List { head:Any, tail:List };

class Nil subtypes List;

signature ZipList, List:List;

method Zipl1, l2 when l1@Cons and l2@Cons {

return ConsPairl1.head, l2.head, Zipl1.tail, l2.tail; }

method Zipl1, l2 when l1@Nil or l2@Nil { return Nil; }

The rst Zip metho d tests the classes of b oth arguments, and it only applies when b oth are instances

of Cons or some sub class; this is an implicit conjunction of two class tests. The second Zip metho d uses

explicit disjunction to test whether either argument is an instance of Nil or some sub class. The typ e

checker can verify statically that the two implementations of Zip are mutually exclusive and exhaustiveover

all p ossible arguments that match the signature, ensuring that there will b e no \message not understo o d"

or \message ambiguous" errors at run-time, without requiring the cases to b e put in any particular order.

ML-style pattern matching requires all cases to b e written in one place and put in a particular total

order, resolving ambiguities in favor of the rst successfully matching pattern. In a traditional singly- or

multiply-dispatched ob ject-oriented language without the ability to order cases, either the base case of Zip

must b e written as the default case for all pairs of List ob jects unnaturally, and unsafely in the face of

future additions of new sub classes of the default typ e, or three separate but identical base metho ds must b e

written one for NilAny, one for AnyNil, and a third for NilNil to resolve the ambiguitybetween the

rst two. In our exp erience with ob ject-oriented languages using a p ointwise, not lexicographic, ordering,

these triplicate base metho ds for binary messages o ccur frequently.

As a syntactic convenience, class tests can b e written in the formal argument list:

formal-pattern ::= [ v ][@ c ] like v @ c in pred-expr

The rst Zip metho d ab ovewould then b e rewritten as

method Zipl1@Cons, l2@Cons {

return ConsPairl1.head, l2.head, Zipl1.tail, l2.tail; }

2.2 Pattern matching

Predicates can test the run-time classes of comp onents of an argument, just as pattern matching can query

substructures, by suxing the @class test with a record-like list of eld names and corresp onding class tests;

names can b e b ound to eld contents at the same time. The ability in pattern matching to test for particular

constants of built-in typ es is a simple extension of class tests.

pred-expr ::= . . .

expr @ sp ecializer

sp ecializer ::= c [ f h eld-pat i g ]

eld-pat ::= m [ = v ][@ sp ecializer ]

As with pattern matching, testing the representation of comp onents of an ob ject makes sense when the

ob ject and the tested comp onents together implement a single abstraction. We do not advo cate using pattern

matching to test comp onents of ob jects in a way that crosses natural abstraction b oundaries.

1

Any is the top class, sub classed by all other classes, and Pair returns an ob ject containing its two arguments. 3

Our syntax for pattern matching on records is analogous to that for creating a record: { x := 7, y :=

22 } creates a two-comp onent record, binding the x eld to 7 and the y eld to 22, while { x = xval }

pattern-matches against a record containing an x eld, binding the new variable xval to the contents of that

eld and ignoring any other elds that might b e present. The similaritybetween the record construction and

matching syntaxes follows ML. Our presentation syntax also uses braces for record typ e sp eci ers as in the

declaration of the Cons class, ab ove and to delimit co de blo cks as in the de nitions of the Zip metho ds,

ab ove.

The following example, adapted from our implementation of an optimizing compiler, shows howa

ConstantFold metho d can dispatch for binary op erators whose arguments are constants and whose op-

erator is integer addition:

type Expr;

signature ConstantFoldExpr:Expr;

-- default constant-fold optimization: do nothing

method ConstantFolde { return e; }

type AtomicExpr subtypes Expr;

class VarRef subtypes AtomicExpr { ... };

class IntConst subtypes AtomicExpr { value:int };

... -- other atomic expressions here

type Binop;

class IntPlus subtypes Binop { ... };

class IntMul subtypes Binop { ... };

... -- other binary operators here

class BinopExpr subtypes Expr { op:Binop, arg1:AtomicExpr, arg2:AtomicExpr, ... };

-- override default to constant-fold binops with constant arguments

method ConstantFolde@BinopExpr{ op@IntPlus, arg1@IntConst, arg2@IntConst } {

return new IntConst { value := arg1 + arg2 }; }

... -- many more similarly expressedcases for other operators here

class UnopExpr subtypes Expr { op:Unop, arg:AtomicExpr, ... };

...

2.3 Bo olean expressions

To increase the expressiveness of predicate dispatching, predicates may include arbitrary b o olean expressions

from the underlying programming language. Additionally, names may b e b ound to values, for use later in

the predicate expressions and in the metho d b o dy. Expressions from the underlying programming language

that app ear in predicate expressions should have no externally observable side e ects.

pred-expr ::= . . .

j test expr succeeds if expr evaluates to true

j let v := E bind v to E ; always succeeds

The following extension to the ConstantFold example illustrates these features.

-- Hand le case of adding zero to anything but don't be ambiguous

-- with existing method for zero plus a constant.

method ConstantFolde@BinopExpr{ op@IntPlus, arg1@IntConst{ value=v }, arg2=a2 }

when testv == 0 and nota2@IntConst {

return a2; }

method ConstantFolde@BinopExpr{ op@IntPlus, arg1=a1, arg2@IntConst{ value=v } }

when testv == 0 and nota1@IntConst { 4

return a1; }

... -- other special cases for operations on 0,1 here

2.4 Predicate abstractions

Named predicate abstractions can factor out recurring tests and give names to semantically meaningful

concepts in the application domain. To allow abstraction over b oth tests and variable bindings, predicate

abstractions can return a record-like list of bindings. These bindings resemble the elds of a record or

class, and similar supp ort is given to pattern matching against a subset of the results of a named predicate

invo cation. Predicate abstractions thus can act like views or virtual sub classes of some ob ject or tuple of

ob jects, with the results of predicate abstractions acting like the virtual elds of the virtual class. If the

prop erties of an ob ject tested by a collection of predicates are mutable, the ob ject may b e given di erent

virtual sub class bindings at di erent times in its life, providing the b ene ts of using classes to organize co de

even in situations where an ob ject's \class" is not xed.

Because ob ject identity is not a ected by these di erent views on an ob ject, named predicate abstractions

are more exible than co ercions in environments with side-e ects. A single ob ject can b e classi ed in

multiple indep endentways by di erent predicate abstractions without b eing forced to de ne all the p ossible

conjunctions of indep endent predicates as explicit classes, relieving some of the problems asso ciated with a

mix-in style of class organization [HHM90b, HHM90a].

pred-sig ::= predsignature p  h T i  return f h f : T i g

pred-decl ::= predicate p  h formal-pattern i 

[ when pred-expr ][return f h f := expr i g ]

pred-expr ::= . . .

j p  h expr i  [ => f h eld-pat i g ] test predicate abstraction p

sp ecializer ::= pred-sp ec [ f h eld-pat i g ]

pred-sp ec ::= c expr @ c is a class test

j p expr @ pf :::g is alternate syntax

for pexpr  => f :::g

A predicate abstraction takes a list of arguments and succeeds or fails as determined by its own predicate

expression. A succeeding predicate abstraction invo cation can return anyvalue computed in its predicate

expression, and the caller can retrieveany subset of the predicate abstraction's result bindings. Predicate

signatures sp ecify the typ e interface used in typ echecking predicate abstraction callers and implementations.

In this presentation, we prohibit recursive predicates.

Simple predicate abstractions are used just like ordinary classes:

predicate on_x_axisp@point

when p@cartesianPoint and testp.y == 0

or p@polarPoint and testp.theta == 0 or testp.theta == pi;

method drawp@point { ... } -- draw the point

method drawp@on_x_axis { ... } -- use a contrasting color so point is visible

In the following example, CFG_2succ is a CFG no de with two successors. Each successor is marked

with whether it is a lo op exit information which, in our implementation, is dynamically maintained when

the CFG is mo di ed and the greatest lo op it do es not exit. It is advantageous for an iterative data ow

algorithm to propagate values along the lo op exit only after reaching a xed p oint within the lo op; suchan

algorithm would dispatchontheLoopExit predicate. Similarly, the algorithm could switch from iterative

to non-iterative mo de when exiting the outermost lo op, as indicated by TopLevelLoopExit.

predsignature LoopExitCFGnode

return { loop:CFGloop };

predicate LoopExitn@CFG_2succ{ next_true: t, next_false: f }

when testt.is_loop_exit or test_f.is_loop_exit 5

return { loop := outermostt.containing_loop, f.containing_loop };

predicate TopLevelLoopExitn@LoopExit{ loop@TopLevelScope };

2.5 Classi ers

Classi ers are a convenient syntax for imp osing a linear ordering on a collection of predicates, ensuring

mutual exclusion. They combine the state testing of predicate classes and the total ordering of pattern

matching. An optional otherwise case, which executes if none of the predicates in the classi er evaluates to

true, adds the guarantee of exhaustion. Multiple indep endent classi cations of a particular class or ob ject

do not interfere with one another.

classi er-decl ::= classify  h formal-pattern i 

h as p when pred-expr [ return f h f := expr i g ] i

[ as p otherwise [ return f h f := expr i g ]]

Here is an example of the use of classi ers:

class Window { ... }

classifyw@Window

as Iconified when testw.iconified

as FullScreen when testw.area == RootWindow.area

as Big when testw.area > RootWindow.area/2

as Small otherwise;

method movew@FullScreen, x@int, y@int { } -- nothing to do

method movew@Big, x@int, y@int { ... } -- move a wireframe outline

method movew@Small, x@int, y@int { ... } -- move an opaque window

method movew@Iconified, x@int, y@int { ... } -- modify icon, not window, coordinates

-- resize, maximize, iconify similarly test these predicates

To force the classi cation to b e mutually exclusive, each case is transformed into a predicate which

includes the negation of the disjunction of all previous predicates. Therefore, an ob ject is classi ed by some

case only when it cannot b e classi ed byany earlier case.

3 Dynamic and static semantics

The rest of this pap er formalizes the dynamic and static semantics of a core predicate dispatching sublan-

guage. Figure 2 presents the abstract syntax of the core sublanguage. App endix A de nes desugaring rules

that translate the high-level syntax of Figure 5 into the core syntax.

In the sequel, we assume that all variables are distinct so that the semantic rules can ignore the details

of avoiding variable capture.

3.1 Dynamic semantics

This section explains how to select the most-sp eci c applicable metho d at each message send. This selection

relies on twokey tests on predicated metho ds: whether a metho d is applicable to a call, and whether one

metho d overrides another.

A metho d is applicable if its predicate evaluates to true; predicate evaluation also provides an extended

environment in which the metho d's b o dy is executed. Figure 3 de nes the execution mo del of predicate

0

evaluation in terms of the elab oration op erator  and several help er functions. Wesay hP; K ihb; K i

when the predicate P evaluates in the environment K to the b o olean result b, pro ducing the new environment

0 0

K . If the result b is false, then the resulting environment K is ignored. 6

metho d-sig ::= signature m  h T i :T

metho d-decl ::= metho d m  h v i  when pred-expr metho d-b o dy

pred-expr ::= true always applies

j test v applies if v is true

j v isa c applies if v is an instance of c or a sub class

j let v := E bind v to E ; always applies

j p  h v i => f h f = v i g test predicate abstraction p

j not pred-expr negation

j pred-expr and pred-expr conjunction short-circuited

j pred-expr or pred-expr disjunction short-circuited

pred-sig ::= predsignature p  h T i  return f h f : T i g

pred-decl ::= predicate p  h v i  when P return f h f := v i g

Figure 2: Abstract syntax of the core language. Words and symb ols in b oldface represent terminals. Angle

brackets denote zero or more comma-separated rep etitions of an item. Square brackets contain optional ex-

pressions. We freely use parentheses around pred-expr s to indicate order of op erations. Recursive predicates

are forbidden.

Predicate dispatching considers one metho d m to override another metho d m exactly when m 's pred-

1 2 1

icate implies m 's predicate and not vice versa. Section 4 describ es how to compute the overriding relation,

2

which can b e p erformed at compile time.

Given the evaluation mo del for predicate expressions and the ability to compare predicate expressions for

overriding, the execution of generic function invo cations is straightforward. Supp ose that generic function

m is de ned with the following cases:

metho d mv , :::, v  when P fB g

1 n 1 1

metho d mv , :::, v  when P fB g

1 n 2 2

.

.

.

metho d mv , :::, v  when P fB g

1 n k k

Toevaluate the invo cation mE , :::, E  in the environment K ,we rst obtain =evalE ;K for all

1 n i i

i =1;:::;n. Then, for j =1;:::;k,we obtain a truth value b and a new environment K through

j j

2

hP ;K[v := ;:::;v := ]i hb ;K i.

j 1 1 n n j j

Now let I b e the set of integers i such that b = true, and nd i 2 I such that P overrides all others

i 0 i

0

in fP g . The result of evaluating mE ;:::;E  is then the result of evaluating B in the environment

i i2I 1 n i

0

K , so that variables b ound in the predicate can b e referred to in the b o dy. If no such i exists, then an

i 0

0

exception is raised a \message not understo o d" error if I is empty, or a \message ambiguous" error if there

is no unique minimal elementofI .

A clever implementation can makea numb er of improvements to this base algorithm. Here we brie y

mention just a few such optimizations. First, common sub expression elimination over predicate expressions

can limit the computation done in evaluating guards. Second, precomputed implication relationships can

prevent the necessity for evaluating every predicate expression. If a more sp eci c one is true, then the less

sp eci c one is certain to b e satis ed; however, such satisfaction is irrelevant since the more sp eci c predicate

will b e chosen. Third, clauses and metho ds can b e reordered to succeed or fail more quickly.

3.2 Static semantics and typ echecking

The op erational mo del of predicate dispatch describ ed in Section 3.1 can raise a run-time exception at a

message send if no metho d is applicable or if no applicable metho d overrides all the others. We extend the

typ echecking rules of the underlying language to guarantee that no such exception o ccurs.

Figure 4 presents the static semantic domains, help er functions, and typ echecking rules for the core

predicate dispatching sublanguage.

2

Since we assume that all variables are distinct, we can safely use the dynamic environment at the call site instead of

preserving the static environment at the predicate abstraction's de nition p oint. 7

; 2 value Values in the underlying programming language

b 2ftrue; falseg Mathematical b o oleans

K 2 var-id ! value [ pred-id ! pred-decl  Environments mapping variables to values

and predicate names to predicate declarations

lo okupv; K  ! Lo ok up the value of variable v in the environment K , returning the value .

0

K [v := ] ! K Bind the name v to the value in the environment K , resulting in the new envi-

0

ronment K .Ifv is already b ound, the existing binding is overridden.

evalE; K  ! Evaluate the expression E in the environment K , returning the value .

instanceof ; c ! b Determine whether the value is an instance of c or any sub class of c.

accept   ! b Co erce arbitrary program values to true or false.

htrue;Kihtrue;Ki

lo okupv; K = accept  = b

hv; K ihb; K i

lo okupv; K = instanceof ; c= b

hv isa c; K ihb; K i

0

evalE; K = K [v := ]= K

0

hlet v := E; K ihtrue;K i

0

8i 2f1;:::;ng evalv ;K=

i

i

lo okupp; K = predicate pv ;:::;v  when P return ff := E , :::, f := E , :::g

1 n 1 1 m m

0

hP; K [v := ;:::;v := ]ihfalse;K i

1 1 n n

0 0

hpv , :::, v => ff = w , :::, f = w g;Kihfalse;Ki

1 1 m m

1 n

0

8i 2f1;:::;ng evalv ;K=

i

i

lo okupp; K = predicate pv ;:::;v  when P return ff := E , :::, f := E , :::g

1 n 1 1 m m

0

hP; K [v := ;:::;v := ] ihtrue;K i

1 1 n n

0

8i 2f1;:::;mg evalE ;K =

i i

00

K [w := ;:::;w := ]= K

1 1 m m

00 0 0

=> ff = w , :::, f = w g;Kihtrue;K i , :::, v hpv

1 1 m m

n 1

0

hP; K ihb; K i

hnot P; K ih:b; K i

0

hP; K ihfalse;K i

hP and Q; K ihfalse;Ki

0 0 00

hP; K ihtrue;K i hQ; K ihfalse;K i

hP and Q; K ihfalse;Ki

0 0 00

hP; K ihtrue;K i hQ; K ihtrue;K i

00

hP and Q; K ihtrue;K i

0

hP; K ihtrue;K i

hP or Q; K ihtrue;Ki

0 00

hP; K ihfalse;K i hQ; K ihtrue;K i

hP or Q; K ihtrue;Ki

0 00

hP; K ihfalse;K i hQ; K ihfalse;K i

hP or Q; K ihfalse;Ki

Figure 3: Dynamic semantic domains, help er functions, and evaluation rules 8

0 0

T  T Typ e T is a subtyp e of T .

0 0

conformant-typ e T; c Return the most-sp eci c typ e T such that every sub class c of c that conforms to T

0

also conforms to T . This help er function is supplied by the underlying programming

language.

0 00 0 0 0

+ = Overriding extension of typing environments. For each v 2 dom , if j= v : T ,

00 0 0

then j= v : T ; for each v 2 dom n domGamma , if j= v : T , then

00

j= v : T .

` signature mT , :::, T : T  +fm :T ;:::;T  ! T g

1 n r 1 n r

j= m :T ;:::;T  ! T

1 n r

0 0

+ fv : T ;:::;v : T g` P  j= metho d-b o dy : T T  T

1 1 n n b b r

` metho d mv , :::, v  when P metho d-b o dy 

1 n

r r r r

` predsignature pT , :::, T  return ff : T , :::, f : T g  +fp :T ;:::;T  !ff : T ;:::;f : T gg

1 n 1 m 1 n 1 m

1 m 1 m

r r

j= p :T ;:::;T  !ff : T ;:::;f : T ;:::g

1 n 1 m

1 m

0

+ fv : T ;:::;v : T g` P 

1 1 n n

0 0 0 0 r

8i 2f1;:::;mg j= v : T ^ T  T

i i i i

0 0

` predicate pv , :::, v  when P return ff := v , :::, f := v g 

1 n 1 m

1 m

` true 

j= v : B ool

` v 

0

j= v : T conformant-typ e c; T = T

0

` v isa c  + fv : T g

j= expr : T

` let v := expr  +fv : T g

r r

j= p :T ;:::;T  !ff : T ;:::;f : T ;:::g

1 n 1 m

m

1

0 0 0 0

j= v : T ::: j= v : T T  T ::: T  T

1 n 1 n

1 n 1 n

r 0 r 0 0 0

g : T ;:::;v : T g  + fv , :::, f = v ` pv , :::, v => ff = v

m 1 n 1

m m 1 1 m 1

0

` P 

` not P 

0 0 00

` P  ` P 

1 2

00

` P and P 

1 2

0 00

` P  ` P 

1 2

` P or P 

1 2

Figure 4: Typ echecking rules. The hyp othesis j= expr : T indicates that typ echecking in typing environ-

0

ment assigns typ e T to expr. The judgment ` P  represents extension of typ echecking environments:

0

given typ e environment, P typ echecks and pro duces new typ echecking environment. The return typ e

for a predicate invo cation is an unordered record. 9

We can separate typ echecking into two parts: client-side, which handles all checking of expressions in the

underlying language and uses metho d signatures to typ echeck message sends, and implementation-side, which

checks metho d and predicate implementations against their corresp onding signatures. Only implementation-

side checking is a ected by predicate dispatching.

Implementation-side typ echecking must guarantee completeness and uniqueness. Completeness guaran-

tees that no \message not understo o d" error is raised: for every p ossible set of arguments at each call site,

some metho d is applicable. Let P b e the disjunction of the predicates of all of m's implementations, and let

m

P b e a predicate expressing the set of argument classes that conform to the typ es in the metho d signature.

s

See b elow for the details of predicate P ; a class c conforms to a typ e T if every ob ject which is an instance

s

of that class has typ e T or a subtyp e of T . If P implies P , then some metho d is always applicable.

s m

Uniqueness guarantees that no \message ambiguous" error is raised: for no p ossible set of arguments at any

call site are there multiple most-sp eci c metho ds. Uniqueness is guaranteed if, for each pair of predicates P

and Q attached to two di erent implementations, either P and Q are disjoint so their asso ciated metho ds

can never b e simultaneously applicable or one of the predicates implies the other so one of the metho ds

overrides the other. Section 4 presents implication and disjointness tests over predicate expressions.

Completeness checking requires a predicate P that expresses the set of tuples of values v ;:::;v con-

s 1 n

forming to some signature's argumenttyp es T ;:::;T ; this predicate dep ends on the host language's mo del

1 n

of classes and typing. If classes and typ es are the same, and all classes are concrete, then the corresp onding

predicate is simply v isa T and ::: and v isa T . If abstract classes are allowed, then each v isa T is

1 1 n n i i

replaced with v isa T or :::or v isa T , where the T are the top concrete sub classes of T . If inheritance

i i1 i im ij i

and are separate notions, then the predicates b ecome more complex.

Our typ echecking need not test that metho ds conform to signatures, unlike previous work on typ echecking

multimetho ds [CL95]. In predicate dispatching, a metho d's formal argument has two distinct typ es: the

\external" typ e derived from the signature declaration, and the p ossibly ner \internal" typ e guaranteed by

successful evaluation of the metho d's predicate. The individual isa tests narrow the typ e of the tested value

to the most-sp eci c typ e to which all classes passing the test conform, in a host-language-sp eci c manner,

using conformant-typ e . The conformant-typ e function replaces the more complicated conformance test of

earlier work.

4 Comparing predicate expressions

The static and dynamic semantics of predicate dispatching require compile-time tests of implication b etween

predicates to determine the metho d overriding relationship. The static semantics also requires tests of

completeness and uniqueness to ensure the absence of message-not-understo o d errors and message-ambiguous

errors, resp ectively. All of these tests reduce to tautology tests over predicates. Metho d m overrides metho d

1

m i m 's predicate implies that of m | that is, if not m  or m is true. A set of metho ds is complete

2 1 2 1 2

if the disjunction of their predicates is true. Uniqueness for a set of metho ds requires that for any pair

of metho ds, either one overrides the other, or the two are logically exclusive. Two formulas are mutually

exclusive exactly if one implies the negation of the other.

Section 4.1 presents a simple, sound, complete tautology test over predicate expressions. Because deter-

mining logical tautology is NP-complete, in the worst case an algorithm takes exp onential time in the size

of the predicate expressions. For ob ject-oriented dispatch, this is the numb er of arguments to a metho d a

small constant. Simple optimizations Section 4.2 make the tests fast in many practical situations. This

cost is incurred only at compile time; at run time, precomputed overriding relations among metho ds are

simply lo oked up.

We treat expressions from the underlying programming language as blackboxes but do identify those

which p erform the same computation. Tests involving the run-time values of arbitrary host language

expressions are undecidable. The algorithm presented here also do es not address recursive predicates. While

wehave a set of heuristics that succeed in many common, practical cases, we do not yet have a complete,

sound, ecient algorithm. 10

4.1 The base algorithm

The base algorithm for testing predicate tautology has three comp onents. First, the predicate expression is

canonicalized to macro-expand predicate abstractions, eliminate variable bindings, and use canonical names

for formal arguments. This transformation prevents di erent names for the same value from b eing considered

distinct. Second, implication relations are computed among the atomic predicates for instance, x isa int

implies x isa num. Finally, the canonicalized predicate is tested for every assignment of atomic predicates

to truth values which is consistent with the atomic predicate implications. The predicate is a tautology i

evaluating it in every consistent truth assignment yields true.

4.1.1 Canonicalization

Canonicalization p erforms the following transformations:

 Expand predicate calls inline, replacing the => clause by a series of let bindings.

 Replace let-b ound variables by the expressions to which they are b ound, and replace let expressions

by true.

 Canonically rename formal parameters according to their p osition in the formal list.

After canonicalization, each predicate expression is a logical formula over the following atoms with con-

nectives and, or, and not.

pred-atom ::= true

j test E

j E isa c

Canonicalized predicates are a compile-time construct used only for predicate comparison; they are never

executed. Canonicalized predicates bind no variables, and they use only global variables and formal param-

eters.

In the worst case, canonicalization exp onentially blows up expression sizes. For instance, in

let x = x + x and let x = x + x and let x = x + x and ::: and test x = y;

1 2 1 1 3 2 2 n

n

the nal x is replaced by an expression containing 2 instances of x. Inline expansion of predicate abstrac-

n

tions similarly contributes to this blowup. As with ML typ echecking [KM89], which is exp onential in the

worst case but linear in practice, weanticipate that predicates leading to exp onential b ehavior will b e rare.

In the sequel we will consider two expressions identical if, after canonicalization, they have the same

abstract syntax tree.

Omitting this step prevents some equivalent expressions from b eing recognized as such, but do es not

prevent the remainder of the algorithm from succeeding when results are named and reused rather than the

computation rep eated.

4.1.2 Truth assignmentchecking

This section presents a simple exp onential-time algorithm to check logical tautology; b ecause the problem

is NP-complete, any algorithm takes exp onential time in the worst case. Let there b e n distinct predicate

n

atoms in the predicate; there are 2 di erent truth assignments for those atoms. Not all of those truth

assignments are consistent with the implications over predicate atoms: for instance, it is not sensible to set

a isa int to true but a isa num to false, b ecause a isa int implies a isa num.Ifevery consistent truth

assignment satis es the predicate, then the predicate is a tautology. Eachcheck of a single truth assignment

n

takes time linear in the size of the predicate expressions, for a total time of O n2 .

The following rules sp ecify implication over p ossibly negated canonical predicate atoms.

 E isa c  E isa c i E E  and c is a sub class of c 

1 1 2 2 1 2 1 2

 E isa c  notE isa c  i E E  and c is disjoint from c 

1 1 2 2 1 2 1 2

 a  a i not a  not a

1 2 2 1

 a  not a i a  not a

1 2 2 1

Two classes are disjoint if they have no common descendant. As is usual, not not a = a. 11

4.2 Optimizations

The worst-case exp onential-time cost to check predicate tautology need not prevent its use in practice.

Satis abilityischecked only at compile time. When computing overriding relationships, the predicates tend

to b e small linear in the numb er of arguments to a metho d. We present heuristics that reduce the costs

even further.

Logical simpli cation | such as eliminating uses of true, not not a, and a and not a | can b e p erformed

as part of canonicalization to reduce the size of predicate expressions.

Unrelated atomic predicates can b e treated separately.To determine whether metho d m f @c ;f @c f:::g

1 1 1 2 2

overrides metho d m f @c ;f @c f:::g it is sucient to indep endently determine the relationship b etween

1 1 3 2 4

c and c and that b etween c and c .Two tests with a smaller exp onent replace one with a larger one,

1 3 2 4

substantially reducing the overall cost. This technique always solves ordinary single and multiple dispatching

overriding in time constant and linear in the numb er of formals, resp ectively,by examining each formal p o-

sition indep endently. The technique also applies to more complicated cases, by examining subsets of formal

parameters which app ear together in tests from the underlying programming language.

It is not always necessary to completely expand predicate abstraction calls as part of canonicalization. If

relations b etween predicate abstractions or other predicate expressions are known, then the tautology test

can use them directly. As one example, no complicated test is required in order to determine that di erent

cases of a classi er are mutually exclusive, as that prop erty is satis ed by de nition.

The side conditions on atomic predicate values their implication relationships usually prevent the need

n

to check all 2 di erent truth assignments for a predicate containing n atomic predicates. When a isa int

is set to true, then all truth assignments which set a isa num to false can b e skipp ed without further

consideration.

Finally,itmay b e p ossible to achieve faster results in some cases by recasting the tautology test. Rather

than attempting to prove that every truth assignment satis es a predicate expression, it may b e advantageous

to search for a single truth assignment that satis es its negation.

5 Related work

5.1 Ob ject-oriented approaches

In the mo del of predicate dispatching, traditional ob ject-oriented dispatching translates to either a single

class test on the receiver argument or, for multiple dispatching, a conjunction of class tests over several

arguments. Full predicate dispatching additionally enables testing arbitrary b o olean expressions from the

underlying language; accessing and naming sub comp onents of the arguments; p erforming tests over multiple

arguments; and arbitrarily combining tests via conjunction, disjunction, and negation. Also, named predicate

abstractions e ectively intro duce new virtual classes and corresp onding sub classing links into the program

inheritance hierarchy. Predicate dispatching preserves the ability in ob ject-oriented languages to statically

determine when one metho d overrides another and when no message lo okup errors can o ccur. Singly-

dispatched ob ject-oriented languages have ecient metho d lo okup algorithms and separate typ echecking,

which dep end crucially on the absence of any separate mo dules that dispatch on other argument p ositions.

Multiply-dispatched ob ject-oriented languages have more challenging problems in implementation [KR89,

CTK94, AGS94] and typ echecking [CL95], and predicate dispatching in its unrestricted form shares these

challenges.

Predicate classes [Cha93b] are an earlier extension of ob ject-oriented dispatching to include arbitrary

b o olean predicates. A predicate class which inherits from some class A and has an asso ciated predicate

expression g uar d would b e mo deled as a named predicate abstraction that tests @A and g uar d. Predicate

dispatching is more general, for example by b eing able to de ne predicates over multiple arguments. Predicate

dispatching exploits the structure of and, or, and not to automatically determine when no message lo okup

errors can o ccur, while predicate classes rely on uncheckable user assertions ab out the relations b etween the

predicate classes' guard expressions in order to do typ echecking.

Classi ers in Kea [HHM90b, HHM90a, MHH91] let an instance of a class b e dynamically reclassi ed as

b eing of a sub class. A classi er for a class is comp osed of a sequence of arbitrary-predicate/sub class pairs,

with an ob ject of the input class automatically classi ed as b eing of the sub class with the rst successful 12

predicate. Because the sequence of predicates is totally ordered and the rst successful predicate takes

precedence over all later predicates, a classi er provides a concise syntax for a set of mutually exclusive,

exhaustive predicate abstractions. Predicate abstractions are more general than classi ers in manyofthe

ways discussed ab ove, but they also provide syntactic supp ort for this imp ortant idiom. Kea is a purely func-

tional language, so classi ers do not need to consider the semantics of reclassifying ob jects when the values

of predicates change; predicate dispatching addresses this issue by conceptually p erforming reclassi cation

as needed as part of message dispatching.

Mo des [Tai93] are another mechanism for adding dynamic reclassi cation of a class into a sub class.

Unlike predicate classes and classi ers, the mo des of a class are not rst-class sub classes but rather internal

comp onents of a class that cannot b e extended externally and that cannot exploit inheritance to factor

shared co de. Mo de reselection can b e done either explicitly at the end of each metho d or implicitly after

each assignment using a declaratively sp eci ed classi cation.

5.2 Pattern matching approaches

Predicate dispatching supp orts many of the facilities found in pattern matching as in ML [MTH90] and

+

Haskell [HJW 92], including tests over arbitrary nested structure, binding of names to sub comp onents, and

arbitrary b o olean guard expressions. Predicate dispatching additionally supp orts inheritance its class tests

are more general than datatyp e constructor patterns, disjunctions and negations of tests and conjunctions

of tests on the same ob ject, and named predicate abstractions to factor out common patterns of tests and to

o er conditional views of ob jects extended with virtual elds. The patterns in a function are totally ordered,

while predicate dispatching computes a partial order over predicates and warns when two patterns mightbe

ambiguous. Finally, new metho ds can b e added to existing generic functions without changing any existing

co de, while new patterns can b e added to a function only by mo difying it.

Views [Wad87] extend pattern matching to abstract data typ es by allowing an abstract data typ e to

o er a numb er of views of itself as a concrete datatyp e, over which pattern matching is de ned. Predicate

dispatching supp orts \pattern matching" over the results of metho ds by let-binding their results to names

and then testing those names, just as eld contents are b ound and tested, and those metho ds can serveas

accessor functions to a virtual view of the ob ject, for instance rho and theta metho ds presenting a p olar

view of a cartesian p oint. Views must b e isomorphisms, which enables equational reasoning over them; by

contrast, named predicate abstractions provide conditional views of an ob ject without requiring the presence

of b oth in and out views.

Pizza [OW97] supp orts b oth algebraic datatyp es and asso ciated pattern matching and ob ject-oriented

dispatching, but the two mechanisms are largely distinct. The authors argue that datatyp es are go o d for xed

numb ers of representations with extensible op erations, while classes are go o d for a xed set of op erations

with extensible representations. By integrating pattern matching and dispatching, including multimetho ds,

predicate dispatching achieves extensibility in b oth dimensions along with the syntactic convenience of

pattern matching. Predicate dispatching faces more dicult implementation and separate typ echecking

challenges with the shift to multimetho d-like dispatching.

6 Conclusions

Many language features express the concept of selecting a most-sp eci c applicable metho d from a collection

of candidates, including ob ject-oriented dispatch, pattern matching, views, predicate classes, and classi ers.

Predicate dispatching integrates and generalizes these mechanisms in a single framework, based on a core

language of b o olean expressions over class tests and arbitrary expressions, explicit binding forms to generalize

features of pattern matching, and named predicate abstractions with result bindings. By providing a single

integrated mechanism, programs can then take advantage of various styles of dispatch and even combine

them to create applicability conditions that were previously imp ossible or inconvenient to express.

Wehave implemented predicate dispatching in the context of Dubious, a simple core multiply-dispatched

ob ject-oriented programming language. The implementation supp orts all the examples presented in this

pap er, though for clarity this pap er uses a slightly di erent presentation syntax. The implementation

includes the complete, sound satis ability test of Section 4 and some of the optimizations of Section 3.1,

but few optimizations from Section 4.2. This implementationwas helpful in verifying our base design. We 13

exp ect that it will also provide insightinto the advantages and disadvantages of programming with predicate

dispatching, as well as help us to evaluate optimization strategies.

So far, wehave fo cused on developing the static and dynamic semantics for predicate dispatching. Two

unresolved practical issues that we will address in the future are ecient implementation techniques and

separate typ echecking supp ort for predicate dispatching. Weanticipate that ecient implementations of un-

restricted predicate dispatching will build up on work on ecient implementation of multimetho d dispatching

and on predicate classes. In addition, static analyses that factor a collection of predicates to avoid redundant

tests and side-e ect analyses that determine when predicates need not b e re-evaluated app ear to b e promis-

ing lines for future research. Similarly, separate typ echecking of collections of predicated metho ds will build

up on currentwork to develop mo dular and incremental metho ds for typ echecking multimetho ds [CL95].

Acknowledgments

We thank To dd Millstein, Vassily Litvinov, and Wilson Hsieh for their comments on a draft of this pap er.

This research is supp orted in part by an NSF grantnumb er CCR-9503741, an NSF Young Investigator

Award numb er CCR-9457767, a grant from the Oce of Naval Research contract numb er N00014-94-1-

1136, and gifts from Sun Microsystems, IBM, XeroxPARC, Pure Software, and Edison Design Group.

References

[AGS94] Eric Amiel, Olivier Grub er, and Eric Simon. Optimizing multi-metho d dispatch using compressed dispatch

tables. In Proceedings OOPSLA '94, pages 244{258, Portland, OR, Octob er 1994.

+

[BKK 86] Daniel G. Bobrow, Ken Kahn, Gregor Kiczales, Larry Masinter, Mark Ste k, and Frank Zdyb el. Com-

monlo ops: Merging lisp and ob ject-oriented programming. In Proceedings OOPSLA '86, pages 17{29,

Novemb er 1986. Published as ACM SIGPLAN Notices, volume 21, numb er 11.

[Cha92] Craig Chamb ers. Ob ject-oriented multi-metho ds in Cecil. In O. Lehrmann Madsen, editor, Proceedings

ECOOP '92, LNCS 615, pages 33{56, Utrecht, The Netherlands, June 1992. Springer-Verlag.

[Cha93a] Craig Chamb ers. The Cecil language: Sp eci cation and rationale. Technical Rep ort TR-93-03-05, De-

partment of Computer Science and Engineering. UniversityofWashington, March 1993.

[Cha93b] Craig Chamb ers. Predicate classes. In O. Nierstrasz, editor, Proceedings ECOOP '93, LNCS 707, pages

268{296, Kaiserslautern, Germany, July 1993. Springer-Verlag.

[CL95] Craig Chamb ers and Gary T. Leavens. Typ echecking and mo dules for multi-metho ds. ACM Transactions

on Programming Languages and Systems, 176:805{843, Novemb er 1995.

[CTK94] Weimin Chen, Volker Turau, and Wolfgang Klas. Ecient dynamic lo ok-up strategy for multi-metho ds.

In M. Tokoro and R. Pareschi, editors, Proceedings ECOOP '94, LNCS 821, pages 408{431, Bologna,

Italy, July 1994. Springer-Verlag.

[HHM90a] J. Hamer, J.G. Hosking, and W.B. Mugridge. A metho d for integrating classi cation within an ob ject-

oriented environment. Technical Rep ort Auckland Computer Science Rep ort No. 48, Departmentof

Computer Science, University of Auckland, Octob er 1990.

[HHM90b] J.G. Hosking, J. Hamer, and W.B. Mugridge. Integrating functional and ob ject-oriented programming.

In Technology of Object-OrientedLanguages and Systems TOOLS 3, pages 345{355, Sydney, 1990.

+

[HJW 92] Paul Hudak, Simon Peyton Jones, Philip Wadler, Brian Boutel, Jon Fairbairn, Joseph Fasel, Maria

Guzman, Kevin Hammond, John Hughes, Thomas Johnsson, Dick Kieburtz, Rishiyur Nikhil, Will Partain,

and John Peterson. Rep ort on the programming language Haskell, version 1.2. SIGPLAN Notices, 275,

May 1992.

[KM89] Paris C. Kanellakis and John C. Mitchell. Polymorphic uni cation and ML typing. In ACM-SIGPLAN

ACM-SIGACT, editor, ConferenceRecord of the 16th Annual ACM Symposium on Principles of Pro-

gramming Languages POPL '89, pages 105{115, Austin, TX, USA, January 1989. ACM Press.

[KR89] Gregor Kiczales and Luis Ro driguez. Ecient metho d dispatch in PCL. Technical Rep ort SSL 89-95,

XeroxPARC Systems Sciences Lab oratory, 1989.

[MHH91] Warwick B. Mugridge, John Hamer, and John G. Hosking. Multi-metho ds in a statically-typ ed pro-

gramming language. In P. America, editor, Proceedings ECOOP '91, LNCS 512, pages 307{324, Geneva,

Switzerland, July 15-19 1991. Springer-Verlag. 14

metho d-sig ::= signature m  h T i :T

metho d-decl ::= metho d m  h formal-pattern i  [ when pred-expr ] metho d-b o dy

pred-sig ::= predsignature p  h T i  return f h f : T i g

pred-decl ::= predicate p  h formal-pattern i 

[ when pred-expr ][ return f h f := expr i g ]

classi er-decl ::= classify  h formal-pattern i 

h as p when pred-expr [ return f h f := expr i g ] i

[ as p otherwise [ return f h f := expr i g ]]

pred-expr ::= true always succeeds

j false never succeeds

j expr @ sp ecializer succeeds if expr evaluates to an instance or

sub class of the sp eci ed class or predicate

j test expr succeeds if expr evaluates to true

j let v := E bind v to E ; always succeeds

j p  h expr i  [ => f h eld-pat i g ] test predicate abstraction p

j not pred-expr negation

j pred-expr and pred-expr conjunction short-circuited

j pred-expr or pred-expr disjunction short-circuited

formal-pattern ::= [ v ][@ sp ecializer ] like v isa sp ecializer in pred-expr

eld-pat ::= m [ = v ][@ sp ecializer ]

sp ecializer ::= pred-sp ec [ f h eld-pat i g ]

pred-sp ec ::= c expr @ c is a class test

j p expr @ pf :::g is alternate syntax

for pexpr  => f :::g

j not pred-sp ec succeeds if pred-expr do es not

j pred-sp ec & pred-sp ec succeeds if b oth pred-expr sdo

j pred-sp ec j pred-sp ec succeeds if either pred-expr do es

Figure 5: Full extended syntax for predicate dispatching. The notation is as for Figure 2. The syntax is as

presented incrementally in Section 2, with a few additions such as b o olean op erators in pred-sp ec s.

[MTH90] Robin Milner, Mads Tofte, and Rob ert Harp er. The De nition of StandardML. MIT Press, 1990.

[OW97] Martin Odersky and Philip Wadler. Pizza into Java: Translating theory into practice. In Conference

Record of the 24th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pages

146{159, January 1997.

[Ste90] Guy L. Steele Jr. Common Lisp: The Language. Digital Press, Bedford, MA, 1990. Second edition.

[Tai93] Antero Taivalsaari. Ob ject-oriented programming with mo des. Journal of Object-OrientedProgramming,

pages 25{32, June 1993.

[Wad87] Philip Wadler. Views: A way for pattern matching to cohabit with data abstraction. In Proceedings of the

Fourteenth Annual ACM Symposium on Principles of Programming Languages, pages 307{313, Munich,

Germany, January 1987.

A Desugaring rules

The following rewrite rules desugar the high-level syntax of Figure 5 into the core abstract syntax of Figure 2.

V

n

0

For brevity,we use fP g to stand for the conjunction of the terms: P and :::and P .Variables v and

i 1 n

i=1

0

are new variables which do not app ear elsewhere in the program. Ceiling braces de surround p otentially v

i

sugared expressions; application of the rewrite rules eliminates those braces.

For brevity,we omit the rewrite rules whichintro duce defaults for omitted optional program fragments:

dummyvariables for pattern variables, \@any " sp ecializers, empty eld pattern sets in sp ecializers, and

\when true" and \return fg" clauses. Additional rules maybeintro duced to simplify the resulting

formula, suchasconverting \v isa any "to\true" and p erforming logical simpli cation. 15

Declarations:move sp ecializers into when clause

dmetho d mv @ S , :::, v @ S  when P metho d-b o dye

1 1 n n

V

n

fdv isa S eg and dP e metho d-b o dy = metho d mv , :::, v  when

i i 1 n

i=1

dpredicate pv @ S , :::, v @ S  when P return ff := E , :::, f := E ge

1 1 n n 1 1 m m

V

n

fd v isa S eg and d P e and d return ff := E , :::, f := E ge = predicate pv , :::, v  when

i i 1 1 m m 1 n

i=1

Logic

dP and P e = dP e and dP e

1 2 1 2

dP or P e = dP e or d P e

1 2 1 2

dnot P e = not dP e

d falsee = not true

Name non-variable expressions

0 0

dE e = let v := E and v

0 0

d E isa S e = let v := E and d v isa S e

V

n

0

:= E g flet v dpE , :::, E => fFdpat , :::, Fdpat ge =

i 1 n

1 m

i

i=1

0 0

and dpv , :::, v => fFdpat , :::, Fdpat ge

1 m

1 n

V

m

0 0 0

flet v := E g return ff := v , :::, f := v g dreturn ff := E , :::, f := E ge = and

i 1 m 1 1 m m

i 1 m

i=1

Field bindings: A eld name is generated by Pname if Pname is a class containing the eld, if Pname is

a predicate name whose result contains the eld, if Pname is a disjunction b oth of whose disjuncts generate

the eld, if Pname is a conjunction either of whose conjuncts generates the eld, or if the eld name is

actually a single-argument metho d name.

dv isa c ff = v @ S , :::, f = v @ S ge

1 1 1 n n n

V

n

= v isa c and fdv:f isa S eg

i i

i=1

dv isa P fFdpat , :::, Fdpat , :::, Fdpat ge Fdpat is generated by P 6= c for 1  i  m

1 m n i

 

= dv isa P fFdpat , :::, Fdpat ge and v isa any fFdpat , :::, Fdpat g

1 m m+1 n

dv isa p => ff = v @ S , :::, f = v @ S ge

1 1 1 n n n

V

n

0 0

, :::, f = v g and = v isa p => ff = v fd v:f isa S eg

n 1 i i

1 n

i=1

dv isa p ff = v , :::, f = v ge

1 1 n n

= pv => ff = v , :::, f = v g

1 1 n n

Comp ound predicate abstractions

dv isa not PnamefFdpat , :::, Fdpat ge

1 m

= not dv isa PnamefFdpat , :::, Fdpat ge

1 m

dv isa Pname j Pname fFdpat , :::, Fdpat ge

1 2

1 m

= dv isa Pname fFdpat , :::, Fdpat ge or dv isa Pname fFdpat , :::, Fdpat ge

1 2

1 m 1 m

dv isa Pname & Pname fFdpat , :::, Fdpat , :::, Fdpat ge Fdpat ,1 i  m, is generated by Pname

1 2 1

1 m n i

 

= dv isa Pname fFdpat , :::, Fdpat ge and v isa Pname fFdpat , :::, Fdpat g

1 2

1 m m+1 n 16

Classi ers

2 3

classifyv @ S , :::, v @ S 

1 1 m m

6 7

as c when P return ff := w , :::, f := w g

1 1 1;1 1;1 1;m 1;m

1 1

6 7

6 7

.

.

6 7

.

6 7

6 7

as c when P return ff := w , :::, f := w g

n n n;1 n;1 n;m n;m

n n

6 7

6 7

g := w as c otherwise return ff := w , :::, f

n+1m n+1 n+1;1 n+1;1 n+1;m

n+1 n+1

 

predicate c v @ S , :::, v @ S  when P

1 1 1 m m 1

=

return ff := w , :::, f := w g;

1;1 1;1 1;m 1;m

1 1

d predicate d v @ S , :::, v @ S  when P ;e

1 1 1 m m 1

 

predicate c v @ S , :::, v @ S  when P and not d v , :::, v 

2 1 1 m m 2 1 1 m

return ff := w , :::, f := w g;

2;1 2;1 2;m 2;m

2 2

d predicate d v @ S , :::, v @ S  when d v , :::, v orP ;e

2 1 1 m m 1 1 m 2

:::

 

predicate c v @ S , :::, v @ S  when P and not d v , :::, v 

n 1 1 m m n n1 1 m

return ff := w , :::, f := w g;

n;1 n;1 n;m n;m

n n

d predicate d v @ S , :::, v @ S  when d v , :::, v orP ;e

n 1 1 m m n1 1 m n

 

predicate c v @ S , :::, v @ S  when not d v , :::, v 

n+1 1 1 m m n 1 m

return ff := w , :::, f := w g;

n+1;1 n+1;1 n+1;m n+1;m

n+1 n+1

B Bindings escaping \or"

In the static and dynamic semantics presented in Section 3, bindings never escap e from or predicate ex-

pressions. Relaxing this constraint provides extra convenience to the programmer and p ermits more values

to b e reused rather than recomputed. It is also equivalent to p ermitting overloaded predicates or multiple

predicate de nitions | so far wehave p ermitted only a single de nition of each predicate.

For example, the two ConstantFold metho ds of Section 2.3 can b e combined into a single metho d.

Eliminating co de duplication is a prime goal of ob ject-oriented programming, but the previous version

rep eated the b o dy twice.

-- hand le case of adding zero to anything but don't be ambiguous

-- with existing method for zero plus a constant

method ConstantFolde@BinopExpr{ op@IntPlus, arg1=a1, arg2=a2 }

when a1@IntConst{ value=v } and testv==0 and nota2@IntConst and let res := a2

or a2@IntConst{ value=v } and testv==0 and nota1@IntConst and let res := a1 {

... -- increment counter, or do other common work here

return res; }

As another example, the LoopExit example of Section 2.4 can b e extended to present a view which

indicates which branch of the CFG_2succ is the lo op exit and which the backward branch. When p erforming

iterative data ow, this is the only information of interest, and in our current implementation which uses

predicate classes [Cha93b]we generally recompute this information after discovering that an ob ject is a

LoopExit. Presenting a view which includes this information improves the co de's readability and eciency.

predsignature LoopExitCFGnode

return { loop:CFGloop, next_looping:CFGedge, next_exiting:CFGedge };

predicate LoopExitn@CFG_2succ{ next_true: t, next_false: f }

when testt.is_loop_exit and let nl := t and let ne := f

or testf.is_loop_exit and let nl := f and let ne := t

return { loop := nl.containing_loop, next_looping := nl, next_exiting := ne };

Permitting bindings which app ear on b oth sides of or to escap e requires the following changes to the

dynamic semantics of Figure 3: 17

0

hP; K ihtrue;K i

0

hP or Q; K ihtrue;K i

0 00

hP; K ihfalse;K i hQ; K ihtrue;K i

00

hP or Q; K ihtrue;K i

0 00

hP; K ihfalse;K i hQ; K ihfalse;K i

hP or Q; K ihfalse;Ki

The static semantics of Figure 4 must b e mo di ed to add a help er function and to replace a typ echecking

rule:

0 00 00 0

t ; = Pointwise lub over typing environments. For each v 2 dom  = dom \ dom ,

env

0 0 00 0

if j= v : T and j= v : T , then j= v : T t T .

0 00 0 00 000

` P  ` P  t  ; =

1 2 env

000

` P or P 

1 2

Finally, canonicalization must account for the new semantics of or. In order to p ermit replacementof

variables by their values, weintro duce a new compile-time-only ternary conditional op erator ?: for each

variable b ound on each side of the predicate. The rst argument is the predicate expression on the left-hand

side of the or expression; the second and third arguments are the values on each side of the or.

Canonicalizing this new ?: expression requires ordering the tests canonically; any ordering will do. This

may necessitate duplication of some expressions, such as transforming b?e :a?e :e into a?b?e :e :b?e :e 

1 2 3 1 2 1 3

so that those two expressions are not considered distinct. With these two mo di cations, the tautology test

is once again sound and complete. 18