<<

Iowa State University Capstones, Theses and Retrospective Theses and Dissertations Dissertations

2005 A design discipline and language features for modular reasoning in aspect-oriented programs Curtis Charles Clifton Iowa State University

Follow this and additional works at: https://lib.dr.iastate.edu/rtd Part of the Computer Sciences Commons

Recommended Citation Clifton, Curtis Charles, "A design discipline and language features for modular reasoning in aspect-oriented programs " (2005). Retrospective Theses and Dissertations. 1840. https://lib.dr.iastate.edu/rtd/1840

This Dissertation is brought to you for free and open access by the Iowa State University Capstones, Theses and Dissertations at Iowa State University Digital Repository. It has been accepted for inclusion in Retrospective Theses and Dissertations by an authorized administrator of Iowa State University Digital Repository. For more information, please contact [email protected]. A design discipline and language features for modular reasoning in aspect-oriented programs

by

Curtis Charles Clifton

A dissertation submitted to the graduate faculty

in partial fulfillment of the requirements for the degree of

DOCTOR OF PHILOSOPHY

Major: Computer Science

Program of Study Committee: Gary T. Leavens, Major Professor lien Morris Chang Markus Lumpe Robyn . Lutz lonathan . H. Smith

Iowa State University

Ames, Iowa

2005

Copyright © Curtis Charles Clifton, 2005. All rights reserved. UMI Number: 3184594

INFORMATION TO USERS

The quality of this reproduction is dependent upon the quality of the copy submitted. Broken or indistinct print, colored or poor quality illustrations and photographs, print bleed-through, substandard margins, and improper alignment can adversely affect reproduction. In the unlikely event that the author did not send a complete manuscript and there are missing pages, these will be noted. Also, if unauthorized copyright material had to be removed, a note will indicate the deletion.

UMI

UMI Microform 3184594 Copyright 2005 by ProQuest Information and Learning Company. All rights reserved. This microform edition is protected against unauthorized copying under Title 17, United States Code.

ProQuest Information and Learning Company 300 North Zeeb Road P.O. Box 1346 Ann Arbor, Ml 48106-1346 ii

Graduate College Iowa State University

This is to certify that the doctoral dissertation of

Curtis Charles Clifton has met the dissertation requirements of Iowa State University

Signature was redacted for privacy.

or Professor

Signature was redacted for privacy. For the Major Program iii

To Pastor Daniel Solomon, a model of perseverance and faithful dedication,

and a good friend iv

TABLE OF CONTENTS

LIST OF TABLES viii

LIST OF FIGURES ix

ACKNOWLEDGMENTS xii

ABSTRACT xiv

CHAPTER 1. INTRODUCTION 1

1.1 Aspect-oriented Programming 2

1.2 Practical Benefits 4

1.2.1 Applications of Aspect-Oriented Features 4

1.3 Theoretical Challenges 6

1.3.1 Object-Oriented Non-modularity 7

1.3.2 Behavioral Subtyping 8

1.3.3 Non-modularity in Aspect-Oriented Languages 9

1.3.4 Modular Aspect-oriented Reasoning 10

1.4 11

1.5 Statement of the Thesis 12

CHAPTER 2. THE MAO DISCIPLINE 13

2.1 The Discipline 14

2.2 Proposed Language Features 15

2.2.1 Assistants 15

2.2.2 Spectators 23

2.3 Evaluation 26

2.3.1 ATLAS Case Study 26

2.3.2 Impact of Restrictions 27

2.3.3 Summary of Evaluation 33 V

2.4 Specification and Reasoning 33

2.4.1 Specifying Around Advice 34

2.4.2 Specification Composition 39

2.5 Discussion 54

2.5.1 Language Issues 54

2.5.2 Specification Issues 57

2.5.3 Tool Support 57

2.6 Related Work 58

2.7 Conclusion 62

CHAPTERS. MINIMAOi : INVESTIGATING THE SEMANTICS OF PROCEED 64

3.1 MiniMAOo: A Core Object-Oriented Calculus with Classes 64

3.1.1 Syntax of MiniMAOo 65

3.1.2 Operational Semantics of MiniMAOo 66

3.1.3 Static Semantics of MiniMAOo 75

3.1.4 Meta-theory of MiniMAOo 78

3.2 MiniMAOi : Adding Aspects 88

3.2.1 Syntax of MiniMAOi 89

3.2.2 Operational Semantics of MiniMAOi 91

3.2.3 Static Semantics of MiniMAOi 112

3.2.4 Meta-theory of MiniMAOi 117

3.3 Related Work 144

3.4 Discussion 146

3.5 Conclusion 147

CHAPTER 4. MINIMA02: PARTITIONING THE HEAP BY CROSS-CUTTING CONCERNS 149

4.1 Intuition 150

4.2 Syntax 152

4.2.1 Public Concern Domain Declarations 153

4.2.2 Class and Aspect Instantiation 153

4.2.3 Refined Types 157

4.2.4 Effects Clauses 158

4.2.5 New Pointcut Descriptor 158

4.2.6 Concern Domain Dependencies 158 vi

4.3 Semantics 159

4.3.1 Operational Semantics 159

4.3.2 Static Semantics 169

4.4 Meta-theory 184

4.4.1 Auxiliary Definitions and Lemmas 185

4.4.2 Type Safety 217

4.4.3 Effects Properties 231

4.5 Related Work 242

4.6 Conclusion 247

CHAPTER 5. MiniMA03: SPECTATORS REALIZED 249

5.1 Differences Versus MiniMAOg 249

5.1.1 Syntax of MiniMAOg 250

5.1.2 Operational Semantics of MiniMAOs 252

5.1.3 Static Semantics of MiniMAOa 257

5.2 Meta-Theory of MiniMAOg 263

5.2.1 Supporting Definitions and Lemmas 264

5.2.2 Type Safety 273

5.2.3 Effects 280

5.3 Discussion 288

5.4 Related Work 288

5.5 Conclusion 289

CHAPTER 6. CONCLUSIONS AND FUTURE WORK 290

6.1 Support for the Thesis 290

6.2 Open Problems 292

6.2.1 Verification 292

6.2.2 MAO 295

6.3 Future Work 298

6.3.1 Alias Control 298

6.3.2 Late Binding and Aspect-Oriented Virtual Machines 298

6.3.3 Concurrent Aspect-oriented Programming 299

6.3.4 Subtype Matching in Around? Unsound! 299

6.3.5 Component-based Programming 301 6.4 Postscript

BIBLIOGRAPHY viii

LIST OF TABLES

2.1 Categorization of Examples from the Aspect] Programming Guide 28

2.2 Categorization of Examples from Kiselev's Text 30

4.1 Reach and Writable Reach for the Store, S, of Figure 4.24 235 ix

LIST OF FIGURES

1.1 Point Class 7

1.2 Sample Client Code 8

1.3 RightMovingPoint Class 8

1.4 O neWay Mov i rig Aspect 9

2.1 FigureElement Example (in Java with JML annotations) 16

2.2 MoveLimiting Example (in AspectJ) 17

2.3 Syntax of Concern Maps 21

2.4 Example Concern Map 21

2.5 Example Spectator Aspect 24

2.6 Example of JML Specification Cases 35

2.7 Example JML Specification Showing Overlapping Specification Cases 36

2.8 Around Advice Specification in AspectJML 37

2.9 Example Specification for Around Advice with Multiple proceed Expressions 38

2.10 Specification Composition Graph Construction, Stage Go 42

2.11 Specification Composition Graph Construction, Partially Complete Stage Gi 43

2.12 Specification Composition Graph Construction, Stage Gi 44

2.13 Unique Path through Specification Composition Graph, «-converted 46

2.14 General Form of the Effective Specification 51

2.15 Effective Specification for the Path Shown in Figure 2.13 53

2.16 Simplified Version of Effective Specification from Figure 2.15 54

2.17 Effective Specification Derived from the Specification Composition Graph in Figure 2.12 54

3.1 Syntax of MiniMAOo 65

3.2 Operational Semantics of MiniMAOo 67

3.3 Auxiliary Functions for MiniMAOo 70 X

3.4 Subtyping in MiniMAOo 71

3.5 Sample MiniMAOo Program 72

3.6 Static Semantics of MiniMAOo 76

3.7 Syntax Extensions for MiniMAOi 90

3.8 Join Point Stack 92

3.9 Additional Expression Forms for the Operational Semantics of MiniMAOi 93

3.10 Changes to the Operational Semantics for MiniMAOi 95

3.11 Additional Subtyping Rule for MiniMAOi 96

3.12 Auxiliary Functions for MiniMAOi Operational Semantics 97

3.13 Boolean Algebra over Binding Terms 101

3.14 Pointcut Descriptor Matching for MiniMAOi 102

3.15 Comparison of Evaluation in MiniMAOo and MiniMAOi 105

3.16 Sample Program Showing Advice Binding 106

3.17 Sample Derivation of Pointcut Descriptor Matching 107

3.18 Sample Program Showing Advice Chaining 108

3.19 Sample Program Contrasting this vs. target Binding and call vs. execution Advice .... 110

3.20 Additions to the Static Semantics for MiniMAOi 113

3.21 Binding for Type Environments 115

3.22 Static Semantics of Pointcuts in MiniMAOi 116

3.23 Meta-variables Used in the Proof of Lemma 3.15 122

4.1 Schematic View of a Store in MiniMAOg 151

4.2 Syntax of MiniMAO^ 154

4.3 Fragment of a MiniMAOi Program Illustrating New Syntax 155

4.4 Syntax Extensions for the Operational Semantics of MiniMA02 160

4.5 Join Point Stack in MiniMAO^ 161

4.6 Example of Advice Table Construction 162

4.7 Evaluation Relation for the Operational Semantics of MiniMA02 164

4.8 Evaluation Relation for the Operational Semantics of MiniMA02 (Exceptional Rules) ..165

4.9 Auxiliary Functions for Operational Semantics of MiniMA02 167

4.10 More Auxiliary Functions for MiniMA02 Operational Semantics 168

4.11 Subtyping in MMMAO2 169

4.12 Pointcut Descriptor Matching for MiniMAOa 170 xi

4.13 Bindings in MiniMA02 171

4.14 Static Semantics of Declarations in MiniMA02 174

4.15 Auxiliary Functions for Static Semantics of MiniMA02 176

4.16 Auxiliary Typing Judgments for Declarations in MiniMA02 176

4.17 Static Semantics of Expressions in MiniMA02 179

4.18 Sample Expression Type Errors in MiniMAÛ2 180

4.19 Binding for Type Environments 182

4.20 Static Semantics of Pointcuts in MiniMAÛ2 183

4.21 Venn Diagram Illustrating Lemma 4.6 187

4.22 Setup and Common Meta-variable Bindings Used in the Proof of Lemma 4.14 200

4.23 Auxiliary Functions for the Meta-theory of MiniMA02 234

4.24 Schematic View of a Sample Store, S 235

4.25 Recursive Definition of the Locations Included in an Expression 236

5.1 Differences in Syntax of MiniMAOg vs. MiniMAÛ2 251

5.2 Differences in the Operational Semantics of MMMAO3 vs. MiniMAÛ2 252

5.3 Pointcut Descriptor Matching for Surround Advice 256

5.4 Example Illustrating Relaxed Pointcut Matching for Surround Advice 258

5.5 Auxiliary Functions for the Static Semantics of MiniMAOa 259

5.6 Differences in the Static Semantics of MiniMAOg vs. MiniMAC>2 260

5.7 Static Semantics of Pointcuts for Surround Advice 262

5.8 Setup and Common Meta variable Bindings Used in the Proof of Lemma 5.6 268

5.9 Type Derivation for Result of SURROUND Rule in Subject Reduction Proof 276

6.1 Array Co- and Contravariance Problem in Java 300 xii

ACKNOWLEDGMENTS

I want to offer my sincerest thanks to several people and one dog for their contributions to this work, and to my reaching this milestone:

— to my wife Lisa Laxson, whose financial support made this feasible, and whose love, patience, dedication,

and confidence in me made this possible;

— to our beagle Molly, who can always make me smile and who sleeps enough to make up for my lack of

the same;

— to Gary Leavens, for his guidance, support, encouragement, patience and confidence in me, and for his

extreme dedication during my sprint to the finish;

— to my parents, Jim and Connie Clifton, for their love and encouragement and for teaching me the value

of hard work, striving for perfection, and service to others;

— to Janet (Lamont) Leonard, for putting an Apple II in front of a scrawny eleven-year-old boy and

changing his path in life forever;

— to the faculty, staff, and most especially the students in the Dept. of Computer Science and Software

Engineering at the Rose-Hulman Institute of Technology, whose enthusiasm gave me the push to

complete this work;

— to Morris Chang, Markus Lumpe, Robyn Lutz, and Jonathan Smith for their contributions on my

committee, and for not groaning too loudly when they saw the thickness of the final draft;

— to Jerry Anderson, for keeping me grounded and Atanasoff Hall spotless;

— to Linda Dutton, for help in clearing the administrative hurdles and for providing interesting conversa­

tion and a ready supply of Altoids Sours; xiii

— to the friendly staff of Taraccino Coffee in Ames, especially Laurie, Rigel, Kelsey, and Jeremiah, for

"proudly serving legal addictive stimulants since 1997" and getting me started with my writing most

every morning;

— to Gerben Wierda for his outstanding EïïgX distribution and to the BibDesk team, in particular Michael

McCracken, Adam Maxwell, and Christiaan Hofman, for their volunteer efforts to making Mac OS X an

outstanding platform for mathematical typesetting; and

— to God for His many gifts, including the people who have nurtured me along the way, strength for the

final push, and Jesus Christ, the perfect example of compassion and loving service. xiv

ABSTRACT

Aspect-oriented programming lets programmers modularize concerns that are orthogonal to the main decomposition of a program. To do this, aspect-oriented programming includes modules called aspects that may modify the behavior, or advise, code in the main decomposition. Aspect-oriented programming also allows aspects to declaratively specify what code should be advised. This means that a whole-program search is required to find all the aspects that might advise a given piece of code. The problems this causes are somewhat analogous to overriding methods and polymorphic method dispatch in traditional object-oriented programming.

In object-oriented programming, the discipline of behavioral subtyping permits reasoning about polymor­ phic methods even when overriding methods remain unseen. The discipline gives guidance to the author of an overriding method: the overriding method must satisfy the specification of the overridden, superclass method.

If the author follows the discipline, then other programmers can reason about a method invocation based on the specification of the superclass method, even if an unseen overriding method might actually be executed.

This dissertation describes an analogous discipline for aspect-oriented programming. The basic premise is that modular reasoning about aspect-oriented programs requires shared responsibility between the aspect author and the client programmer, whose code might be advised by the aspect.

To mediate this sharing, this dissertation proposes that aspects be categorized into two sorts: "spectators" and "assistants". Spectators are statically restricted to not modify the behavior of the code that they advise.

Because of their restricted behavior, spectators may remain unseen by the client programmer. The burden is on the aspect programmer to ensure that spectators satisfy their restrictions. Unlike spectators, assistants are not restricted in their behavior. The burden of reasoning about their effects falls to the client programmer.

To do this, the client programmer must be able to identify all applicable assistants. Thus, assistants must be explicitly accepted by the advised code. This discipline allows modular reasoning, permits the use of existing aspect-oriented idioms, and appears to be practical and statically verifiable. A formal study demonstrates that the restrictions on spectators may be statically checked. 1

CHAPTER 1. INTRODUCTION

Aspect-oriented programming [81] deals with the problem of modularizing "cross-cutting concerns". Cross- cutting concerns are features of a program that are orthogonal to its main decomposition [153]. Because of their orthogonality, cross-cutting concerns inherently result in the scattering of code across various modules in the main decomposition of the program. From the perspective of the main decomposition, such cross- cutting code is said to be tangled. Aspect-oriented programming addresses this problem by allowing software engineers to write code for cross-cutting concerns in separate modules, called aspects, and to declaratively specify how that code is to be associated with events in the main decomposition at run time.

The declarative association of aspects with the code for the main decomposition is a powerful technique for eliminating the scattering of code. It can result in modules that are more focused and concise. However, the technique can also be used to write code that is difficult to understand and maintain. For example, the declarative manner in which aspects are introduced means that a programmer must, in general, have whole-program knowledge to reason about any operation in the main decomposition.

In the early years of object-oriented programming, similar concerns were raised about polymorphic method invocations. The discipline of behavioral subtyping [11, 12, 50, 92, 105,109] evolved to address these concerns. Behavioral subtyping places a constraint on subtype programmers: overriding methods in a subtype must satisfy the specification of the overridden supertype methods. In exchange for programming within this constraint, clients of the supertype may reason about invocations of supertype methods without worrying about the effects of overriding methods in unseen subtypes. Behavioral subtyping provides both practical guidance to programmers and formal soundness for theorists.

Despite the theoretically increased complexity in reasoning introduced by aspect-oriented languages, programmers are putting them to use in a wide variety of projects [20, 86,147]. This indicates that there are practical mechanisms for controlling aspect-oriented complexity. In fact, as Laddad [86, §1.3.3] points out, well-written aspects consolidate code for a common concern that would be scattered in an object-oriented implementation. Thus, although a whole program analysis is needed with an aspect-oriented program, such an analysis would also be needed to find the scattered code in an object-oriented implementation. 2

In the subsequent section I present more background information on aspect-oriented programming, including terms and history. Then I discuss how the practical benefits of aspect-oriented programming are drawing a growing user community and consider how the members of that community are applying aspect- oriented techniques. Next I describe modular reasoning, give more detail on how behavioral subtyping allows modular reasoning in object-oriented programming, and consider the theoretical challenges presented by aspect-oriented programming. I conclude the introduction by defining the scope of my work, stating my thesis, and outlining the rest of this dissertation.

1.1 Aspect-oriented Programming

Separation of concerns is the well-known software engineering concept that code for different subdomains, or aspects, of a problem should be made as independent as possible to encourage comprehensibility and efficiency (in both re-use and parallel development) [132, 133]. Object-oriented languages encourage the into code representing individual objects in a model of the problem domain. However, there are some aspects which cross-cut the decomposition of a problem domain into objects [68, 81, 153].

Common examples of such cross-cutting concerns are logging, tracing, persistence, and what Filman et al. [60] call ilities: reliability, availability, and manageability among others. The subfield that arose to deal with this problem was known as advanced separation of concerns.

Harrison and Ossher [68] describe a that they call subject-oriented programming.

Subject-oriented programming generalizes the object-oriented paradigm. A subject is roughly equivalent to an entire program in an object-oriented language in that all code within that subject shares the same set of class and type hierarchies, operations, and object state. What makes subject-oriented programming unique is that disparate subjects—with distinct class and type hierarchies, operations, and object state—can share access to the same set of objects. The only necessarily shared by subjects on a given object is object identity.

Various composition rules are used to combine subjects into programs. These rules specify mappings between class and type hierarchies in the composed subjects and describe how method dispatch from within one subject impacts the other subjects in the composition. For example, suppose several subjects each declared an operation with the same name and arguments for a given object. A composition rule might specify that an invocation of this operation in one subject should also execute the code for this operation in the other subjects. More complex composition rules can be imagined that map between operations of different names and parameters and specify compositions of return types of the methods.

Subject-oriented programming has been realized in the Hyper/J language [129, 153] and the Concern

Manipulation Environment [72]. 3

The term aspect-oriented programming was coined by Kiczales et al. [81]. Aspect-oriented languages provide support for advanced separation of concerns via aspects. An aspect may specify additional code to be executed at "certain well-defined points in the execution of the program" [83, p. 329] known as join points.

The construct for declaring this additional code is called advice. A piece of advice defines the set of join points at which the advice should be executed, known as its pointcut. Advice includes a pointcut description, made up of primitive predicates called pointcut descriptors, that defines its pointcut. A piece of advice is sometimes said to advise the join points in its pointcut. (Later examples will illustrate these concepts.)

Advice provides support for a sort of pattern-based , allowing one to specify, for example, that a certain body of code should be executed whenever a method whose name begins with the string open is invoked. An aspect may also introduce new methods to existing classes without modifying those classes, thus supporting open classes [43,114]. The aspect-oriented approach to advanced separation of concerns is typified by the language Aspect! [14, 83].

In previous work on Multijava [38, 43,46], colleagues and I demonstrated how to extend Java [13, 64] with open classes and multimethods. Unlike AspectJ, Multijava supports lexical scoping of its open class extensions.

AspectJ weaves extensions into the extended class, where they will be visible to all clients of the extended class.

Instead in Multijava, extensions are only available to a client that explicitly imports them. This avoids polluting the of the extended class with extensions that are not needed by all clients. On the other hand, the explicit import of extensions in Multijava can represent code tangling (e.g., if the extension represents a cross-cutting concern).

AspectJ and Multijava can both be viewed as incremental approaches toward the more general subject- oriented philosophy. AspectJ maintains the central control structure of a single program, but allows additional operations and state to be in separate aspects. The dispatch flexibility of subject-oriented programming's composition rules is achieved through AspectJ s join points. To provide this flexibility AspectJ requires a whole program analysis. Multijava's open classes allow additional operations to be specified via its open classes while maintaining modular static typechecking and compilation, though its extension mechanisms are more limited than AspectJ's.

Beginning in 2002, the term aspect-oriented software development came into use to describe all of the various approaches for advanced separation of concerns [79]. In addition to Hyper/J and AspectJ, other languages for aspect-oriented software development include Composition Filters [17], DemeterJ [101], CaesarJ

[113] and a host of languages applying AspectJ-like enhancements to core languages other than Java [15,47,

149,154].

Filman and Friedman [59] have tried to identify the distinguishing features of languages for aspect-oriented 4 software development. They assert that such languages are characterized by two features:

— quantification, declarative specification of a set of points, in either the static code or the dynamic

graph of a program, where aspect-oriented code is to be added; and

— non-invasiveness^ the execution of additional aspect-oriented code at a program point, P, without

effort by the programmer of the code containing P.

These two characteristics can complicate reasoning about aspect-oriented programs. Non-invasiveness implies that a programmer may not be able to determine from local code what aspect-oriented code might be executed. Quantification implies that even a whole-program search may not definitively identify whether any aspect-oriented code might be executed—for example, if the quantification is over events in the program's dynamic call graph. Section 1.3 on page 6 discusses these complications in more detail. But first I discuss the practical benefits afforded by the aspect-oriented paradigm.

1.2 Practical Benefits

Despite the apparent complexity in reasoning about aspect-oriented programs, the paradigm is being widely adopted. This is evidenced by the volume of traffic on the AspectJ mailing lists, AspectJ development environment downloads exceeding 20,000 per month,2 and the variety of commercial software frameworks that include aspect-oriented features [21, 29,120,123]. No less an authority than Daniel Sabbah, IBM Vice

President of Strategy and Technology, Software Products Group, said, "Aspect-oriented programming is vital to the success of our business" [147].

1.2.1 Applications of Aspect-Oriented Features

Based on a review of code in the literature and discussions with programmers using aspect-oriented languages, it seems that the common applications of these languages may be classified in two ways:3

— Code Recycling: Aspects are used to transform the behavior or interface of an existing program without

modifying the source code of that program.

— Separation of Concerns: Aspects are used to separate the code for a program into syntactically distinct

modules, each dealing solely with a particularly concern.

Oilman and Friedman use the term "obliviousness"; however, non-invasiveness is becoming the more accepted term for this concept within the community, perhaps for obvious reasons. ^Download statistics posted to the aspectj-users mailing list, May 2005. 3Thanks to Arno Schmidmeier, Juri Memmert, Karl Lieberherr, Frank Sauer, and others for discussions at AOSD '02 on the ways they are using aspect-oriented programming. 5

I discuss each application briefly below.

1.2.1.1 Code Recycling

By virtue of their ability to insert code into an existing program, aspects can be used to transform both the behavior and interface of legacy software. Tzilla Elrad said, at FOAL 2004, that while object-oriented programming allows code re-use, aspect-oriented programming allows "code recycling".

For example, one might use an aspect to add authentication to an existing web server [84] [86, Ch. 10].

Kiselev's "runtime aspects" provide another example. A more elaborate application might involve using aspects to modify the application programming interface (API) of a program by introducing additional methods and redirecting existing calls to the new methods.

I consider program rewriting to be beyond the scope of this work and will instead focus on the second main application of aspect-oriented languages: separation of concerns.

1.2.1.2 Separation of Concerns

Experienced aspect-oriented programmers separate concerns into orthogonal aspects. For example, the base program might handle the functional concerns of the problem domain, while separate aspects might handle persistence, logging, and security. A persistence concern might be separated by writing an aspect that advises the main entry point of a program to establish a database connection. Additional advice could advise object factories in the main program to return instances from the database in response to requests and advise state-changing methods to store mutated objects back to the database [86, ch. 11] [142]. A logging concern might be separated from a base program by quantitatively specifying all the program points to be logged.

If the logging architecture should need to be changed, for example from using println calls to using a more sophisticated framework, all changes are localized in the logging aspect [86, §5.4.1]. Thus, properly separated concerns support evolution of code.

Also, by using different global configurations—combinations of aspects and classes—one can use the separation-of-concerns style to generate a variety of systems from a common code base. For example, a programmer might treat customer-specific requirements as a separate concern and then construct different implementations of that concern for each customer.

Application of aspects for separation of concerns is analogous to the use of behavioral subtypes in object- oriented languages; both techniques seek to enhance existing behavior without introducing surprising behavior.

Both rely on underspecification: A behavioral subtype can add behavior that is not reserved by the supertype's 6 specification; aspects can add behavior that deals with concerns that are orthogonal to those of the advised methods.

1.3 Theoretical Challenges

Properly written object-oriented code—code satisfying behavioral subtyping—makes reasoning easier, despite a theoretical increase in complexity of reasoning versus . Similarly, properly written aspect-oriented code should make reasoning easier, despite a theoretical increase in complexity of reasoning versus object-oriented programming. In this section I describe the increase in reasoning complexity that results from polymorphic method invocations in object-oriented languages. I then discuss how the discipline of behavioral subtyping makes reasoning easier in these languages. I use this as an analogy to consider reasoning in aspect-oriented languages. (The use of this analogy arose in work joint with Gary

Leavens [41].)

First I need to clarify my terminology. It is nebulous to say that reasoning is "easier" in one case versus another. To be concrete, I need a definition of modular reasoning. There are various definitions of modularity in the literature. The weakest definition might be that an analysis is modular if the portion of the program that must be considered to perform the analysis is a well-defined, proper subset of the whole program. At the other end of the spectrum, the definition might require that an analysis must consider only the code for a single compilation unit. Work that uses this definition, particularly in the area of component-based programming [63], typically requires a compilation unit to declare its expectations of external modules [152].

These expectations can then be verified during composition of the unit with external modules.

I will use a definition between these two extremes: a language allows modular reasoning if it is possible to reason about a compilation unit in that language based on the code of that compilation unit and the specifications of any modules (e.g., classes, interfaces, and packages) referred to by that compilation unit. A compilation unit refers to a module M if it explicitly names M, is lexically nested within M, or if M is a standard module in a fixed location (such as Object in Java). Java [13, 64] with JML [93, 95] and Eiffel [111] both satisfy this definition.

It is easier to program in languages that allow modular reasoning, since the cognitive burden on the programmer is reduced—the specifications of referenced modules serve as behavioral abstractions of all the code implementing those modules. 7

public class Point { private /*@ spec_public @*/ int pos; public final /*@ pure @*/ int getPosO { return pos; }

//@ requires true; //@ assignable pos; //@ ensures getPosO == dist + \old(getPos()); public void move(int dist) { pos = pos + dist; } }

Figure 1.1 Point Class

1.3.1 Object-Oriented Non-modularity

In typical (single-dispatch) object-oriented languages, the dynamic type of the receiver object is used to select the appropriate method to execute for a given invocation. Such dynamic selection of the target method can prevent modular reasoning. For example, consider the declaration of Point in Figure 1.1 and its method, move. The l/@-comments before move's declaration give its behavioral specification in JML [93,94].

— The clause "requires true" says that clients are not obliged to establish any precondition.

— The clause "assignable pos" says that the pos field of the object, but no other locations, may be changed

by the method.

— The clause "ensures..." says that, after move returns, the value returned by getPosO is equal to the sum

of the dist argument and the value returned by getPosO before move was called.

(Formal specifications as used here are not a necessary condition for modular reasoning. The behavior of a module can be thought of concretely as its code. Often programmers reason about modules using informal abstractions, e.g., "This method returns true if the given file exists". In a more expressive language, such as Eiffel [110] or Java annotated with JML as used here, the abstract behavior can be specified using pre- and postconditions, frame axioms, and invariants; such specifications serve as contracts that allow one to separately reason about the behavior and correctness of an implementation.)

Suppose an object of static type Point is passed to a method client, as in Figure 1.2 on the following page.

If modular reasoning is sound, then the programmer can reason about the invocation of move based on 8

public void client(Point p) {

assert p.getPos() == 0; p.move(-10); assert p.getPosO == -10; }

Figure 1.2 Sample Client Code

public class RightMovingPoint extends Point { public void move(int dist) { if (dist < 0) super.move(-dist); else super.move(dist); } }

Figure 1.3 RightMovingPoint Class its specification in Point. That is, if the first assertion in the figure holds, then the second assertion is valid based on the specification of Point's move method. The definition of modular reasoning requires that the programmer should not have to consider possible unseen subtypes of Point when reasoning, since they are not mentioned in the client code. But, by subsumption, an instance of just such an unseen subtype may be passed to client. What if (as in Figure 1.3) the subtype RightMovingPoint overrides method move, but does not satisfy the specification of move in Point? Then modular reasoning such as that described for client is not valid. If an instance of RightMovingPoint is passed to client, then after the invocation of p.move(-10), the assertion fails: p.getPosO returns 10, not -10.

1.3.2 Behavioral Subtyping

Modular reasoning is not an inherent property of object-oriented languages. However, the discipline of behavioral subtyping restores sound modular reasoning by imposing the specification of Point on all its subtypes [50, 92, 105]. RightMovingPoint does not correctly implement a behavioral subtype of Point, because its implementation does not satisfy the specification of move in Point. Behavioral subtyping is often described by saying that the behavior of a subtype should not be surprising with respect to the specified behavior of a supertype. Behavior is surprising if the (possibly unseen) code executed in response to a method invocation fails to satisfy the visible method's specification.

Two complementary notions of behavioral subtyping (for types with mutable objects) have been proposed. 9

public aspect OneWayMoving { void around(int dist): call(void *.move(int)) && args(dist) { if (dist < 0) proceed(-dist); else proceed(dist); } }

Figure 1.4 OneWayMoving Aspect

Liskov and Wing [105] propose a notion of behavioral subtyping that does not allow subtypes to mutate state inherited from immutable types. Their notion does not place restrictions on aliasing. Dhara and Leavens [50] propose weak behavioral subtyping4 that allows such mutation by subtypes but imposes some restrictions on object aliasing to avoid surprising behavior. Dhara and Leavens [51] also propose specification inheritance as a mechanism for enforcing weak behavioral subtyping. The same authors provide a review of the research on behavioral subtyping [91, §6.3] and a particularly clear characterization of modular reasoning (§6.1.3).

As pointed out by Filman and Friedman [59, §2.2], subtyping with subsumption, as in the Point example, is a form of non-invasiveness. Aspect-oriented programming languages allow programmers much greater latitude in defining behaviors with unseen code.

1.3.3 Non-modularity in Aspect-Oriented Languages

Just as modular reasoning is not a general property of object-oriented programming languages in the absence of behavioral subtyping, modular reasoning is not a general property of aspect-oriented languages. To show this, I present an aspect-oriented extension to the Point example.

Figure 1.4 gives an aspect, OneWayMoving, that modifies the behavior of Point instances in the same way as RightMovingPoint [39, 41]. OneWayMoving declares a piece of around advice. This advice intercepts calls to Point's move method. If the argument passed to the client is negative, then, just as in RightMovingPoint, control proceeds to Point's move method with the parameter set to the absolute value of the original parameter.

As with RightMovingPoint, the client programmer's reasoning in Figure 1.2 on the previous page is not correct in the presence of the OneWayMoving aspect.

In AspectJ the advice is applied by the without explicit reference to the aspect from either the

Point module or a client module. Instead the classes and aspect are simply passed as arguments to the same compiler invocation, perhaps under the control of an Integrated Development Environment (IDE) or build

4The "weak" in weak behavioral subtyping implies that this formulation is less restrictive than that of Liskov and Wing. 10 system. Thus, modular reasoning about the Point module or a client module has no way to detect that the behavior of the move method will be changed when the Point module and OneWayMoving are compiled together. In AspectJ the programmer must potentially consider all such aspects and the Point class together in order to reason about the Point module. Some potentially applicable aspects, such as OneWayMoving, may not even name Point directly, but instead may use wild card type patterns.

Therefore, just as in object-oriented programming without behavioral subtypes, the non-invasiveness of aspect-oriented languages can prevent modular reasoning.

1.3.4 Modular Aspect-oriented Reasoning

The OneWayMoving aspect represents poor aspect-oriented programming, just as the RightMovingPoint class in Figure 1.3 on page 8 represents poor object-oriented programming. This is because both examples change the behavior of move with regard to a Point's position; behavior that is, by virtue of move's strong specification, restricted to Point itself.

Behavioral subtyping serves to formalize the programming discipline that allows modular reasoning about object-oriented programs. This, in turn, provides useful insights into how best to harness the power of the object-oriented paradigm. In this work I provide the formal basis of a similar discipline for aspect-oriented programming. I do this by defining a small set of language extensions. I explicate the design as a series of core languages, each with a sound, static . I demonstrate the utility of the design for modular reasoning by proving some modularity properties that cannot be shown to hold in a core aspect-oriented language that omits the extensions (but closely models key features of AspectJ). Finally, I consider the implications of this formal work for future aspect-oriented programming language design and for aspect-oriented specification and verification.

We have seen that experienced aspect-oriented programmers separate concerns into orthogonal aspects.

Orthogonality of these aspects helps the reader of a program to understand it, provided she can find the applicable aspects. Specifically, if she wants to reason just about the functional behavior of a code fragment, she must just consider the base program code. If she is concerned with the persistence behavior of a code fragment in the base program, she must just consider the single aspect for persistence. Based on these observations, a detailed design discipline must have two key features:

— easy identification of applicable aspects, and

— orthogonality of the concerns expressed by those aspects.

The first feature is provided in some aspect-oriented languages, for example, in Hyper/J's module intercon­ 11 nect language and in Weave.NET's XML-encoded aspect bindings [87]. In Aspect}, the first feature is generally provided by tool support, though this limits the possible analyses to those supported by the tool. I demonstrate that the easy identification of applicable aspects can be more generally accommodated at the language level.

The second feature is possible in existing aspect-oriented languages (indeed, this is largely what makes them aspect-oriented). However, I am not aware of any languages that explicitly help software engineers to statically verify such orthogonality.

1.4 Scope

This dissertation focuses on what I call aspect-oriented languages with dynamic-context pointcut descrip­ tors. In such languages:

— join points in the program may be specified in terms of the run-time call stack. Such join points are

typified by Aspect]'s cflow, cflowbelow, call, and execute pointcut descriptors.

— aspect-oriented code specifies changes in the behavior of some base program. Filman and Friedman [59]

characterize this as asymmetric aspect-oriented programming. Aspect! is the prototypical asymmetric

aspect-oriented language. Asymmetry stands in contrast to symmetric aspect-oriented languages, like

Hyper/J, where the code for various concerns has equal standing and is composed to produce the final

program. (In unpublished work, colleagues and I demonstrate that an asymmetric aspect-oriented

programming language with names can model symmetric aspect-oriented programming [44,45].)

By aspect-oriented languages with dynamic-context pointcut descriptors, I specifically do not include those languages that support the run-time insertion and removal of aspect-oriented code, so called "dynamic weaving" [57,112,113,135,138,151]. I only consider the use of aspect-oriented code for separation of concerns

(as discussed in Section 1.2.1 on page 4), not for "code recycling", and I assume that any base program can be refactored as needed. 1 also do not consider concurrency issues or "per" aspects, thus focusing on sequential aspect-oriented programs.

To keep the problem tractable, I do not consider aspect-oriented modeling and design [36, 37, 66, 150] and the various framework-based approaches to aspect-orientation [21, 29,120,123]. I choose to focus on programming language design instead. I also do not consider the decomposition of existing systems into cross-cutting modules as provided by Hyper/J and the Concern Manipulation Environment. 12

1.5 Statement of the Thesis

My thesis is that there exists a discipline for programming in aspect-oriented languages with dynamic- context pointcut descriptors that (1) allows modular reasoning, (2) permits the use of existing aspect-oriented idioms for separation of concerns, (3) can be verified by a combination of static typechecking and simple verifi­ cation conditions, and (4) can be incorporated into a practical, aspect-oriented language.

I support my thesis in this dissertation by:

— describing such a discipline, which I call the "MAO discipline";

— presenting a small set of language features, as an extension to Aspect) (version 1.2), designed to facilitate

the discipline;

— developing extensions to the Java Modeling Language for specifying features of aspect-oriented pro­

grams;

— sketching an algorithm for calculating the effective specification of an expression in my AspectJ exten­

sion, given the specifications for any potentially applicable advice;

— presenting MiniMAOj, a core calculus that models AspectJ;

— designing an extended core calculus, MiniMAOg, that includes concern domains, a type system for

statically enforcing the separation of concerns; and

— formalizing my proposed extensions to AspectJ in another extended core calculus, MiniMAOg.

For each of the core calculi, I describe, and prove sound, a static type system. I also prove key meta-theoretic properties of the extended calculi. These properties demonstrate the effectiveness of the MAO discipline and my proposed language features for modular aspect-oriented reasoning.

This dissertation is primarily formal in nature. However, in Chapter 2,1 begin by informally describing the

MAO discipline and my proposed language extensions, to both AspectJ and J ML. Later chapters are dedicated to developing the formal machinery that supports the claims I make informally in the next one. 13

CHAPTER 2. THE MAO DISCIPLINE

I described, in Chapter 1, how object-oriented programming and aspect-oriented programming both

present problems for modular reasoning. Polymorphic method calls in object-oriented programs allow unseen

code (overriding methods) to affect a computation. Advice binding in aspect-oriented programs allows unseen

code (the advice) to affect a computation. Both are examples of non-invasiveness.

The discipline of behavioral subtyping [11, 12, 50, 92, 105, 109] restores modular reasoning to object-

oriented programming languages. It does this by requiring that an overriding method satisfy the specification

that it inherits from the superclass method [51]. This discipline is enabled by the fact that the superclass method

is visible from the declaration of the overriding method. This is a crucial fact. A class declares its superclass.

The declaration allows the class to inherit or override methods from the superclass. So the class declaration

containing an overriding method provides a reference to the overridden method.

Thus, the non-invasiveness in object-oriented programming only cuts one way. From a method call site, the

actual code to be executed may be in an unseen, overriding method. However, from the declaration site of the

overriding method, the superclass method is visible. Thus, the overriding method can satisfy the specification

of the superclass method.

The non-invasiveness in aspect-oriented programming cuts both ways. From a method call site, the actual

code to be executed may be in an unseen aspect. And from the declaration site of an aspect, because of

quantification, the code to be advised may also be unseen. For example, the aspect might only advise code

that implements some interface, and the code implementing that interface might not be known or even exist

when the aspect is written. Thus, with aspect-oriented languages one cannot adopt the solution of behavioral

subtyping: it is not enough to simply require that advice satisfy the specification of the code it augments.

This, then, is the core challenge in developing a programming discipline that allows modular reasoning

about aspect-oriented programs. If reasoning is to be modular, then how can one reason about potentially

advised code when (1) unseen aspects may apply to the code, and (2) aspects may be developed without

(complete) knowledge of the code that will be advised? 14

2.1 The Discipline

A simple categorization of aspects lies at the heart of the MAO discipline for modular, aspect-oriented rea­ soning. In the MAO discipline, I divide aspects into two sorts: those whose advice might introduce "surprising" behavior into a program, and those whose advice is "benign".1

In the discipline of behavioral subtyping all the burden of ensuring modular reasoning is placed on the author of an overriding method. A "client" programmer—that is, a programmer writing code that calls the method—may reason about a call without seeing the overriding method. The specification of the superclass method is normally sufficient for reasoning.

However, in the MAO discipline, the burden is shared. For benign advice, the advice author must satisfy the restrictions. Having done so, the client programmer can remain safely oblivious to the benign advice when reasoning about advised code. On the other hand, for advice that might introduce surprising behavior, the client programmer must be able to modularly identify what advice may apply. The programming language must allow this identification of surprising advice. Having identified this advice, the client programmer must compose the specifications of the advice and the advised code, thus finding the effective specification of the code in the presence of the advice.

The MAO discipline overcomes the two problems identified at the end of the previous section. (1) Aspects that would be unseen in regular AspectJ are divided into two kinds. Those with benign advice remain unseen, but do not affect the behavior of the code. Those with surprising advice must be made visible so that their effects can be considered. (2) For aspect development, the programmer of benign advice must satisfy a set of restrictions, but having done so, she does not need to consider the specific behavior of the code that will be advised. For surprising advice, she must simply satisfy the specification of the advice. The responsibility of reasoning about the interaction of the surprising advice and the advised code falls to the client programmer.

In this chapter I describe a small set of language features that allow a programmer to modularly identify all of the "surprising" advice that may apply to a given join point. The features also enable the static verification of the benignity of other advice. Section 2.2 describes my proposed language features. Because these features change the semantics of AspectJ, it is reasonable to wonder what effect they have on the expressiveness of the language. Section 2.3 evaluates my proposal against published examples of AspectJ code. This evaluation shows that my features do not result in any practical loss of expressiveness. To demonstrate the reasoning process in the MAO discipline, Section 2.4 proposes some simple extensions to JML (the Java Modeling Language [93,95])

*In the subsequent section I will clarify what it means for advice to be benign, and propose statically verifiable restrictions to ensure that benign advice actually is so. Subsequent chapters of this dissertation focus on the formalization and proof of soundness for these restrictions. 15 for giving behavioral specifications of advice, and formalizes specification composition. Section 2.5 discusses some additional issues related to AspectJ, specification, and tool support. Section 2.6 outlines related work,

and Section 2.7 concludes. The basic ideas discussed in this chapter originated in a paper co-authored with

Gary Leavens for the 2002 Foundations Of Aspect-oriented Languages workshop (FOAL '02) [39].

2.2 Proposed Language Features

In this section I describe some language features that are sufficient to support the MAO discipline. For

concreteness I describe these features as extensions to AspectJ. I use a running example, introduced in Fig­

ure 2.1 on the following page, that expands on the Point example from Chapter 1. FigureElements have a

two-dimensional position and include a move method that makes "self calls" to get and set the x and y position

fields. These self calls serve expository purposes later in the chapter.

The key feature to support modular reasoning in my proposal is to divide aspects into two sorts: spectators

and assistants. "Spectators" are limited in that they may not change the behavior of the modules they apply to

(in a way to be made more concrete later, and fully formalized in Chapter 5); their advice is benign. "Assistants"

are not limited in this way. Since spectators do not change behavior, they preserve modular reasoning even

when applied without explicit reference by the modules they view. Hence spectators preserve most of the

flexibility of the current version of AspectJ. Because assistants can change the behavior of the modules to

which they apply, to maintain modular reasoning they can only be applied in modules that reference them.

2.2.1 Assistants

Icall aspects that can change the behavior of a module assistants. The MoveLimiting aspect of Figure 2.2

on page 17 is an assistant; it changes the behavior of FigureElement's move, setX, and setY methods to limit the

maximum change in position from any single call. The term "assistant" is intended to connote a participatory

role for these aspects.

What information is needed to modularly reason about behavior when assistants are present? Quite simply,

a module must explicitly name those assistants that may change its behavior or the behavior of modules that it

uses. I say that a module accepts assistance when it names the assistants that are allowed to change its behavior

or the behavior of modules that it uses. Assistance may be accepted by either:

— the module to which the assistance applies (called the implementation module), or

— a client of that module. 16

package mao;

public class FigureElement {

5 private /*@ spec_public @*/ float x = 0;

6 private /*@ spec_public @*/ float y = 0;

7

8 H@ requires true;

9 H@ assignable x, y; 10 ll@ ensures (getX() == \old(getX()) + dx) && (getYQ == \old(getY()) + dy) //@ && \result == this; 12 public FigureElement move(float dx, float dy) {

13 this.setX(getX() + dx);

14 this.setY(getY() + dy); 15 return this; lù }

17 18 ll@ requires true;

19 //@ assignable \nothing;

20 //@ ensures \result == x;

21 public !*@ pure @*/ float getX() {

22 return x;

23 } 24

25 //@ requires true;

26 //@ assignable \nothing;

27 ll@ ensures \result == y;

28 public /*@ pure @*l float getY() {

29 return y;

30 }

31

32 //@ requires true;

33 //@ assignable this.x;

34 //@ ensures getX() == x;

35 public void setX(float x) {

36 this.x = x;

37 }

38

39 //@ requires true;

40 //@ assignable this.y;

41 //@ ensures getYQ == y;

42 public void setY(float y) {

43 this.y = y;

44 }

Figure 2.1 FigureElement Example (in Java with JML annotations) 17

public aspect MoveLimiting { private static float MAX_DISTANCE = 10.0; private static float distance(float x, float y) { ... }

/* Constrains distance of any single movement to MAXD1STANCE */

5 FigureElement around(float argX, float argY) :

6 execution(* mao.FigureElement.move(float, float)) && args(argX, argY)

7 {

8 float moveDistance = distance(argX, argY); if ( moveDistance > MAX_DISTANCE ) { float ratio = MAX_DISTANCE / moveDistance; return proceed( argX * ratio, argY * ratio ); } else { 7J return proceed( argX, argY ); /4 }

15 }

/* Constrains distance of any x-axis movement to MAX_DISTANCE */ void aroundfmao.FigureElement targFE, float x) : 18 execution!* mao.FigureElement.setX(float)) && target(targFE) && args(x)

19 {

20 float currentX = targFE.getXQ; 21 if (Math.abs(x - currentX) > MAX_DISTANCE) {

22 if (x > currentX) {

23 proceed! targFE, MAX_DISTANCE );

24 } else {

25 proceed! targFE, -MAX_DISTANCE );

26 }

27 } else {

28 proceed! targFE, x );

29 }

30 }

31 /* Constrains distance ofanyy-axis movement to MAX_DISTANCE */

32 void around(mao.FigureElementtargFE, floaty) : 33 execution!* mao.FigureElement.setY(float)) && target(targFE) && args(y)

34 { float currentY = targFE.getYO; if (Math.abs(y - currentY) > MAX_DISTANCE) { if (y > currentY) { 34 proceed! targFE, MAX_DISTANCE );

39 } else {

40 proceed! targFE, -MAX_DISTANCE ); }

42 } else { proceed! targFE, y ); } } }

Figure 2.2 MoveLimiting Example (in AspectJ) 18

2.2.1.1 Explicit Acceptance of Assistance

AspectJ does not currently include syntax for explicitly accepting assistance. Explicit acceptance of assis­ tance can, however, be roughly simulated by the "hyper-cutting" pattern in AspectJ. In this pattern, one creates a marker interface, and the pointcuts of assistants would only apply to types that implement that interface [84, pp. 214-216]. An implementation module can then implement the marker interface, and thus indirectly accept the advice of the assistant. However, if a single client declares that the implementation module is a subtype of the marker interface (using the declare parent syntax of AspectJ), then the change affects all clients of the implementation module, but no trace appears in the implementation module; hence such changes are not modular.2

To automate this hyper-cutting pattern, and to avoid these non-modular uses of it, I propose a simple syntax extension for accepting assistance:

accept TypeName;

where TypeName must be the name of an assistant respecting Java's usual rules for packages and imports [64, §6.5]. Multiple accept clauses may appear in a single module, following any import clauses. For example, the FigureElement module could accept the MoveLimiting assistant by declaring:

accept MoveLimiting;

I will generalize this idea with concern maps below.

When an implementation module accepts assistance, that assistance is applied to every applicable join point within the implementation module, regardless of the client making the call.

On the other hand, if the assistance is accepted by a client module, then that assistance is only applied to applicable join points in that client. Other clients that did not accept the assistance would not have it applied to their join points.

AspectJ includes two pointcut descriptors that roughly simulate this behavior. Advice on join points described via call pointcuts is woven into all client code. Advice on join points described via execution pointcuts is woven into the implementation code. Unfortunately, clients of such an implementation module have no (modular) way to know that such advice will be applied to their calls to the implementation module.

2 An upcoming version of AspectJ will take advantage of the annotation syntax of Java 5 [65]. Annotations on types could then be used in place of the marker interface approach. However, the modularity problem will likely remain, because the new version of AspectJ is planned to include annotation introductions. 19

In my proposal clients of such an implementation module would know about the advice; this is an example of how explicitly accepted assistance allows modular reasoning.

In general a module may accept assistance from multiple assistants and both a client and an implemen­ tation module may accept assistance. The composition of assistant and implementation code is formed respecting the following symmetric order at each join point:

— Client Assistance

1. Apply any before advice accepted by the client module in the order that it is accepted.3

2. Apply the "before part" (i.e., the code preceding a proceed expression) of any around advice

accepted by the client module in the order that it is accepted.

— Implementation Assistance

3. Apply any before advice accepted by the implementation module in the order that it is accepted.

4. Apply the before part of any around advice accepted by the implementation module in the order

that it is accepted.

— Implementation

5. Execute the implementation module code.

— Implementation Assistance

6. Apply the "after part" (i.e., the code following a proceed expression) of any around advice accepted

by the implementation module in the reverse order from which it is accepted.

7. Apply any after advice accepted by the implementation in the reverse order from which it is

accepted.4

— Client Assistance

8. Apply the after part of any around advice accepted by the client module in the reverse order from

which it is accepted.

3 In AspectJ, before advice is a variety of advice that executes prior to the execution of the advised code. Before advice does not use proceed and is primarily evaluated for its side effects, though it may throw exceptions. 4 Like before advice, after advice in AspectJ is evaluated primarily for its side effects. After advice executes following the completion of the code it advises. AspectJ includes three sorts of after advice: after returning, after throwing, and general after advice. The first two execute when the advised code completes normally or completes abruptly, respectively [64, §14.1]. The third sort of after advice always executes. 20

9. Apply any after advice accepted by the client module in the reverse order from which it is accepted.

This ordering ensures that the first assistance accepted by the client is "nearest" to the client and that the last assistance accepted by the implementation is nearest to the implementation on any control flow path. Multiple applicable advice bodies in a single assistant are accepted in the order given in the assistant's declaration, or in the reverse order for after advice and the after part of around advice. Inherited advice is considered to appear at the end of the inheriting aspects; this respects the ordering for inherited advice defined for Aspect] [83, §3.5]. The ordering of advice is underspecified in Aspect]. My symmetric, total ordering differs from the asymmetric ordering of advice implemented in the current version of Aspect] [84, p. 182]. I believe that the symmetric ordering is more intuitive. But it is the total ordering that is most important. Because assistants may modify behavior, a total ordering helps in reasoning about the composition of these modifications. I discuss this more in Section 2.4.

For simplicity and modularity I propose to confine acceptance of assistance to the module in which it is explicitly accepted. For example, suppose there was a Rectangle subclass of FigureElement that overrode the move method. Assistance, like MoveLimiting, accepted by FigureElement would not automatically be applied to executions of Rectangle's move method. On the other hand, if Rectangle did not override FigureEle- ment's implementation of setX, then the inherited method would carry with it the assistance accepted by

FigureElement. This approach also provides flexibility since the programmer can always add an accept clause to the subclass module or override a superclass method; this gains assistance in the first case and "shadows" assistance acceptance in the second. Also for simplicity I propose not allowing interfaces to accept assistance.

Experience with a working implementation may prompt réévaluation of these ideas.

Finally, I propose that nested aspects—aspects declared inside another module—be considered implicitly accepted by the containing module. This enables some useful idioms. For example, suppose a client module is a subclass of some generic class. That generic class might be designed to interface with modules that conform to a certain implementation interface. Now suppose some module exists that does not so conform.

The subclass might use a nested aspect to modularize adapter code between the expected implementation interface and that actually provided.

2.2.1.2 Concern Maps

Modular reasoning in aspect-oriented programming languages can be achieved if modules explicitly accept assistance. But some assistants are applicable to code throughout an entire package or program, for example, a common exception handler. It would be inconvenient (to say the least) to include accept clauses for these 21

AspectMap :: = PackageDecl ImportDeclsop[ MappingListopt

PackageDecl:: = package Identifier;

MappingList :: - Mapping MappingListopt

Mapping :: = TypePat { AcceptListopt}

AcceptList :: = AcceptClause AcceptListopt AcceptClause :: = accept Identifier;

where TypePat refers to type patterns in the AspectJ Programming Guide [14, Appendix A], and ImportDecls refers to regular Java import declarations [64, §7.5].

Figure 2.3 Syntax of Concern Maps

i package mao;

3 M 4 accept MoveLimiting; 5 }

6 7 Rectangle { s accept AreaStretching; » }

Figure 2.4 Example Concern Map assistants in every module, and error prone to have to remember to add accept clauses for these assistants to every new module.5

I propose concern maps to avoid these problems. A concern map is a source code construct that specifies a mapping from modules in a package, or set of packages, to the assistance that is accepted by those modules. In my initial design, each package may contain at most one concern map. In file-system-based implementations, the concern map for a package would be given in a file named package,map stored in the directory containing the package source code. The syntax for concern maps is given in Figure 2.3. Figure 2.4 gives an example concern map for the package named mao.

The type pattern "*", in line 3 of Figure 2.4, says that all types in the mao package accept the MoveLimiting assistant. (I do not allow concern maps to specify fully qualified names in type patterns; instead I implicitly concatenate the name of the map's package with the given pattern. Thus the pattern in the example, signifies the pattern mao.* in the global namespace. I do this because the map should only be able to specify acceptance

5 Such accept clauses would also represent code tangling. 22 of assistance for local types and types in subpackages.) The Rectangle pattern in line 7 of the example says that, in addition to the MoveLimiting assistant, the mao.Rectangle class also accepts the AreaStretching assistant.6

As with accept clauses in modules, the identifier in an accept clause of a concern map is subject to Java's usual namespace rules for packages and imports.

One can think of concern maps as like an AspectJ "introduction"; they add accepts clauses to modules in the local package and subpackages. It would defeat the purpose of accepts clauses to allow their global introduction. So unlike AspectJ introductions, concern maps are lexically scoped.

The assistance accepted via concern maps still allows modular reasoning. To wit, the package clause at the beginning of a module names all the possible locations where a concern map naming that module might appear. The programmer, or a tool, must only look in that package, or possibly any outer packages, to find the applicable concern map. More specifically, the assistance accepted by a given module consists of:

1. all assistants named in accept clauses in the module,

2. all assistants to which the module is mapped by the package.map file for the module's package, and

3. all assistants to which the module is mapped by any package, map files in outer packages (i.e., packages

surrounding the module's package).

To accommodate concern maps I extend the ordering of accepted assistance discussed in Section 2.2.1.1 by letting the search order described here define the ordering of acceptance.

This recursive search for acceptance of assistance in the module's package and outer packages allows the programmer to specify widely-applied assistance in the root of a package hierarchy, package-specific assistance in the concern map of the package it applies to, and module-specific assistance in the modules it applies to.

(Strictly speaking, packages in Java and AspectJ are not hierarchical. They merely provide a hierarchical namespace. For example, code in an inner-package in Java does not have access to package-privileged code from any outer packages. My treatment of concern maps reflects the namespace hierarchy of packages, while still respecting their non-hierarchical encapsulation properties.)

2.2.1.3 Prototype Implementation

I have developed a prototype implementation of concern maps and accepts clauses. The prototype is based on the Polyglot compiler framework [122],7 The prototype translates modules written in AspectJ with

6Both Rectangle and AreaStretching are elided in the current work. 7Were I developing the prototype today, I would instead use the AspectBench compiler [54], itself a Polyglot extension, to avoid the work of developing a full AspectJ front-end. 23 concern maps and accepts clauses into intermediate code that is pure AspectJ. Then the AspectJ compiler is used to generate bytecode. This compilation is modular without having to rely on the global dependency tracking that the AspectJ Development Toolkit (AJDT) inside ECLIPSE uses for its "modular" compilation.8

(Because of the global nature of advice application in AspectJ without my extensions, the AJDT maintains a global, two-way mapping between advice and join points. When any code is changed in a program, this mapping is used to calculate the possibly affected code. Only that code is then re-compiled. This results in more efficient compilation, solving some of the practical problems of whole-program compilation. However, the need for the global mapping illustrates that whole-program reasoning is still required.)

Future work on concern maps will evaluate inheritance mechanisms that might allow finer grained control than the simple unioning of maps from outer packages presented above. Another simple, but useful extension to concern maps would be to allow multiple concern maps in a given package, each with a different name.

So in addition to the default package.map, a programmer could include (for example) customer! .map and customer2.map, with each file activating some customer-specific code. These additional maps could be activated on a project-wide basis. So the programmer could choose to use all of the default concern maps, plus any customer! concern maps that appear in the code base. In this case, modular reasoning would require knowledge of which set of concern maps was being used.

2.2.2 Spectators

Explicitly accepted assistance supports modular reasoning. Concern maps give the programmer flexibility in accepting assistance. But what about "development aspects"[82, p. 61], like tracing or debugging code, that are only sometimes included in an executing program? In a language that just supported explicitly accepted assistance, a programmer would need to edit concern maps or source code modules to control the application of development aspects.

To resolve this I propose that an aspect-oriented programming language should also support a category of aspects that I call spectators. A spectator is an aspect that does not change the behavior of any other module.

Because it does not change the behavior, I will say that a spectator views (rather than "advises") methods.

In concrete terms, a spectator may only mutate the state that it owns (in the sense of alias control systems like [9, 10,25, 35,116,117,118,121]) and it must not change the control flow to or from a viewed method. In addition to mutating owned state it seems reasonable to allow spectators to change accessible, global state as well, since a lava module cannot rely on that state not changing during an invocation (modulo synchronization

8The Aspect! Development Toolkit is available from http://www.eclipse.org/aspectj, URL valid as ofluly 17, 2005. 24

i package mao;

3 spectator DistanceTracking {

5 /** Tracks total distance moved by all figure elements. *! 6 private double distance;

s before(float dx, float dy): 9 execution!* FigureElement.move(float, float)) && args(dx, dy)

10 {

h distance += Math.sqrt( dx*dx + dy*dy ); i2 System.err.println("Total: " + distance); }

14 }

Figure 2.5 Example Spectator Aspect mechanisms).9 The term "spectator" is intended to connote the hands-off role of these aspects.

For example, Figure 2.5 gives a spectator called DistanceTracking. The spectator declaration (in line 3) declares that this aspect does not change the behavior of any other module. This spectator mutates its own state by incrementing distance (in line 11) and mutates the global state by printing to System.err (in line

12). However, it does not change the behavior of FigureElement's move method. DistanceTracking merely views the arguments to the move method. The arguments are passed on to the method unchanged and the method's result is unchanged. In addition to cross-cutting concerns like this tracking example, spectators would also be useful for logging, tracing, and as the observer in the observer design pattern [62, pp. 293-

303]. For example, one can imagine a traffic simulation program that uses spectators for visualization, thus separating the visualization and simulation concerns.

Because spectators do not change the behavior of the methods they view, code outside an existing program can apply a spectator to any join point in the original program without loss of modular reasoning. In reasoning about the client and implementation code for a method, a maintainer of the original program does not need any information from the spectator.

The primary challenge of implementing this part of my proposal lies in determining whether a given aspect is really a spectator. I envision a static analysis that conservatively verifies this. This analysis has two parts—verifying control flow and verifying that only appropriate locations are mutated.

In general the problem of verifying that a spectator does not disrupt control flow is undecidable (by

9It may be that experience with a practical implementation of this proposal would indicate that spectators not be allowed to mutate global state. My formalism, introduced in subsequent chapters, does not include global state. So the current work does not address this issue in detail. 25 reduction to the halting problem); however, one can restrict the sort of control flow allowed in spectators to achieve an approximate solution. I propose that in spectators:

— before advice must not throw a checked exception and must not explicitly throw an unchecked exception

on any control flow path,

— around advice must proceed, exactly once, to the advised method on all control flow paths, and

— after advice must not throw a checked exception and must not explicitly throw an unchecked exception

on any control flow path.

This solution is approximate because it still allows advice in spectators to include (possibly infinite) looping

constructs and to call other (possibly non-terminating) methods, provided any checked exceptions declared

by those methods are caught and handled. These conditions correspond to partial correctness (ignoring

termination) and ignore Java Errors, which I treat as outside the scope of specification.10

A more conservative solution to control flow might disallow loops, method calls, and synchronized code within a spectator's advice. A completely conservative solution is not possible in a Java-like language since

executing any advice in a spectator requires more memory than just executing the viewed method. This

additional memory usage could result in an OutOfMemoryError that prevents control flow from continuing

to the advised method. Because of this, and the draconian nature of the more conservative solution, my

approximate solution that disallows all explicitly thrown exceptions in the advice and handles any checked

exceptions in methods called by the advice seems reasonable.11 (I contend that this solution is also "Java-like"

in only requiring the programmer to deal with checked exceptions.)

In addition to these control flow checks, the checks for "spectatorhood" must also verify that the proceed

expression in around advice passes all arguments to the advised method in their original positions and without

mutation. Any value returned from the advised method (or exception thrown) must be passed on by the advice without mutation.

The requirement that around advice in spectators proceeds exactly once, and with the same arguments,

can be solved syntactically. The language can just separate the advice into before and after parts separated by

an implicit proceed using the original arguments. The problem of returning the value of the advised code can

also be solved through language design, by designing the semantics of advice in spectators to do that.

The mutation analysis for spectators is more challenging. It is closely related to the problem of verifying

frame axioms [221. In fact one can think of spectators as having an implicit frame axiom that prevents modifi-

10This also corresponds to JML's treatment of Errors. 111 imagine that, in many cases, program verification techniques could be used to prove termination and that no unchecked exceptions are thrown. 26 cation of locations that are relevant to the receiver, the arguments, or the value returned or exception thrown by the viewed method. (Intuitively the relevant locations are those that, if changed, would change the abstract state of the object [116,118].)

The main difficulty with statically verifying this lack of relevant mutations is how to deal with aliasing. For example, suppose a logging spectator uses an array to track the elements added to some Set object. Suppose

Set uses an array for its representation. If the spectator's array and the Set's array are aliased, the program might add an element to this array twice—possibly violating Set's invariant and changing its behavior. In this dissertation I introduce, and prove sound, mechanisms for statically ensuring spectatorhood, even in the presence of aliasing.

2.3 Evaluation

This section evaluates the expressiveness of my proposal. My evaluation is limited to a review of existing programs. I first consider the programming guidelines suggested in the ATLAS case study [77]. Then I survey the example aspects from the AspectJ Programming Guide [14] and the books by Kiselev [84] and Laddad [86].

2.3.1 ATLAS Case Study

In the ATLAS case study [77], the authors propose several guidelines to make working with aspects easier.

These are proposed since they had discovered that (p. 346):

[the] extra flexibility provided by aspects is not always an advantage. If too much functionality is

introduced from an aspect it may be difficult for the next developer—or the same developer a

few months later—to read through and understand the code base.

One of Kersten and Murphy's suggestions is to limit coupling between aspects and classes to promote reuse. Specifically, they suggest that one should avoid the case where an aspect explicitly references a class and that class explicitly references the aspect, since then the class and aspect are mutually dependent. Such mutual dependencies prevent independent reuse. Is this suggestion problematic for my proposal that modules explicitly accept assistance? No, because explicit acceptance does not necessarily imply mutual dependence between aspects and classes. Suppose an implementation module, M, accepts assistance from an assistant, A, and A is applicable to M. If A explicitly references M, then the modules are mutually dependent. However, if

A only applies to M because of pattern matching and does not explicitly reference M, then the modules are not mutually dependent. Another option when A references M is to include A as a nested aspect of M (i.e., an aspect declared inside M), confining their dependence to a single file. 27

Client acceptance provides another way to avoid mutual dependence. Suppose a client module, , accepts assistance from an assistant, A', and A' only changes the behavior of modules referenced by C, but does not change C's behavior. In this case A' and C are not mutually dependent. In sum, programmers can reduce mutual dependency by having clients accept assistance, by limiting explicit references to classes from assistants, and by using nested aspects.

Kersten and Murphy also suggest using aspects as factories by having them provide only after-returning advice on constructors. This after-returning advice mutates the state of every object instantiated to change its default behavior. Limiting the aspects in this way restricts the scope of object-aspect interaction. In my proposal a simple assistant can fill the role of such a factory aspect.

For aspects that do not act as factories, Kersten and Murphy propose three style rules that restrict the use of aspects (pp. 349-350):

Rule #1: Exceptions introduced by a weave must be handled in the code comprising the weave.

... Rule #2: Advise [sic] weaves must maintain the pre- and postconditions of a method— Rule

#3: Before advise [sic] weaves must not include a return statement.

These rules are very similar to my definition of spectators in that they prevent aspects from changing the behavior of the viewed method. However, I propose elevating these style rules to the level of statically checked restrictions.

2.3.2 Impact of Restrictions

To better understand how my proposed restrictions might limit the practical expressiveness of AspectJ, I review several examples from three separate sources.

2.3.2.1 AspectJ Programming Guide

I use the examples in the AspectJ Programming Guide to see if my restrictions prohibit any recommended idioms. The programming guide's examples can serve this purpose since they "not only show the features [of

AspectJ] being used, but also try to illustrate recommended practice" [14] (from the Preface). I separate the example aspects into categories based on how I would implement them with my restrictions. Table 2.1 on the following page lists the examples by category; I describe the categories here.12

12The examples listed in the table are from the examples directory of the Version 1.0.6 release of AspectJ, available from http://www.eclipse.org/aspectj. 28

Table 2.1 Categorization of Examples from the AspectJ Programming Guide

Example Category

telecom/TimerLog spectator tjp/Getlnfo spectator tracing/lib/AbstractTrace spectator tracing/lib/TraceMyClasses spectator tracing/versionl/TraceMyClasses spectator tracing/version2/Trace spectator tracing/version2/TraceMyClasses spectator tracing/version3/Trace spectator tracing/versionB/TraceMyClasses spectator bean/BoundPoint client utility introduction/CloneablePoint client utility introduction/ComparablePoint client utility introduction/HashablePoint client utility observer/SubjectObserverProtocol client utility observer/SubjectObserverProtocollmpI client utility spacewar/Display.DisplayAspect client utility spacewar/Displayl .SpaceObject Painting client utility spacewar/Display2.SpaceObject Painting client utility telecom/Billing client utility telecom/Timing client utility spacewar/EnsureShiplsAlive impl. utility spacewar/GameSynchronization impl. utility" spacewar/RegistrySynchronization impl. utility0 spacewar/Registry.RegistrationProtection impl. utility coordination/Coordinator assistant6 spacewar/Debug combined "Extends the abstract coordination/Coordinator assistant. ^Refers only to abstract pointcuts. 29

SPECTATORS Many of the example aspects clearly meet my definition of spectator. To satisfy my restric­

tions these would only require the spectator syntax.

ASSISTANTS Aspects in the examples that could be implemented as assistants can be divided into two

kinds. Client utilities are used by client modules to change the effective behavior of objects whose types are

declared in other modules. The changes in effective behavior do not affect the representation of those objects.

To satisfy my restrictions, client utilities' assistance would have to be explicitly accepted by the clients. In

fact, some of the client utility assistants are declared as nested aspects. These are similar in spirit to explicitly

excepted assistance and would be implicitly accepted under my proposal.

Other example aspects that could be implemented as assistants might be considered implementation

utilities. These assistants encapsulate some unit of cross-cutting concern related to a single module, for

example, enforcing a common precondition across the methods of a class. In my proposal each implementation

utility would be accepted by the module that it advises, creating a mutual dependency. However, in all the

examples this mutual dependency could be fixed by nesting the implementation utility inside the advised

module. I would also require that the call join points in these aspects be changed to execution join points.

The Coordinator aspect of the coordination package is abstract. This abstract aspect modifies the behavior

of the modules to which it refers, making it an assistant in my terminology. However, Coordinator only refers

to abstract pointcuts. Thus, for the advice in Coordinator to be applicable to any module a concrete aspect

extending Coordinator would have to be declared. This concrete aspect would be an assistant and would need

to be accepted per my design. In fact, the two "synchronization" implementation utilities listed in Table 2.1 on

the previous page are concrete assistants extending Coordinator.

COMBINED TO satisfy my restrictions, one example aspect, the Debug aspect of the spacewar example,

would require a combination of spectators and assistants. This aspect would be a spectator, except that it

provides after advice to a GUI frame's constructor, to add debugging options to the frame's menu bar. To

support this pattern with my restrictions, the GUI frame would have to accept assistance from an assistant, say

AdditionalMenuConcern. This assistant would provide methods allowing other code to add to the GUI frame's

menu bar. The debugging aspect would become a spectator viewing the program and using the methods

provided by AdditionalMenuConcern to display the debugging menus.

To summarize, even with my proposal's restrictions it is easy to express AspectJ's recommended idioms. 30

Table 2.2 Categorization of Examples from Kiselev's Text

Example Category

Development Aspects" Logger spectator Tracer spectator Profiler spectator6 CodeSegregation not defined6 Production Aspects Authentication client utility^ Exceptions client utility NullChecker spectator6 Runtime Aspects OutputStreamBuffering impl. utility Pooling impl. utility ConnectionChecking impl. utility ReadCache impl. utility not categorized NewLogging client utility PaidStories spectator "Subheadings give Kiselev's categorization. ^Requires minor changes to be a spectator. ^Introduces warnings and errors. ^Includes parent declarations.

2.3.2.2 Kiselev

While the Aspect] Programming Guide provides many small examples demonstrating recommended idioms, Kiselev's book Aspect-Oriented Programming with AspectJ [84] provides an extensive case study. The aspects given in the book in chapters 5-8 are all related to this case study, which concerns a web service that is supposed to store and retrieve users' stories. Table 2.2 gives a summary of these aspects and how they relate to my categories.

Kiselev categorizes his examples as "development", "production", or "runtime" aspects [84, Chapter 9). It is useful to discuss how these categories relate to my division of aspects into spectators and assistants.

The development aspects (Logger, Tracer, Profiler and CodeSegregation) are "used as development aids"

(p. 115), but are not useful during production use of the system. Since these are optional aspects one would hope that they are spectators in my categorization. This is clearly the case for Logger and Tracer.

The Profiler aspect would be considered a spectator in my categorization—except for one issue. Profiler 31 declares before and after advice that can change the control flow by explicitly throwing an exception when an I/O error occurs while writing profiling data to disk. I could categorize Profiler as an assistant and use a root-level concern map to apply it to the entire project. However, Profiler is a development aspect; one would like to be able to switch it off and on without editing the source code. I can resolve this difficulty by using a non-default concern map, which could be included or excluded from the configuration. Alternatively, one could simply change Profiler to swallow any I/O exceptions and report the problem to the developer

(via System.err, for example) or to convert I/O exceptions into unchecked Errors. This would make Profilera spectator, as intended.

CodeSegregation uses AspectJ's declare error and declare warning constructs to introduce additional compile-time checks. These constructs are outside the scope of the current work, but are discussed in Sec­ tion 2.5.

The production aspects (Authentication, Exceptions, and NullChecker) are "absolutely essential to the application" [84, p. 115]. Since they are absolutely essential it is reasonable to include them in the appropriate concern maps knowing that these references will not have to be changed. These aspects do have some interesting properties vis-à-vis my categorization. The Authentication aspect is, at its core, a client utility.13 It is applied to objects that render web pages and manage the current user session to ensure that the user of the session is validated. I say that this is a client utility because it may be the case that some client code of these objects should allow unauthenticated access to some pages. In Kiselev's example the Authentication aspect is applied broadly. This is easily implemented using a root-level aspect map. The Authentication aspect also uses introduction, via AspectJ's declare parents construct, to add additional methods to the classes it assists.

Introductions are also beyond the scope of the current work, but are discussed in Section 2.5.

The Exceptions aspect is a client utility in my categorization, a fact emphasized by Kiselev when he argues for using a call join point instead of an execution join point by saying that, with the execution join point,

"some other application would not be able to utilize this class without the Exceptions aspect attached to it"

(p. 76).

I would argue that Kiselev's third production aspect, NullChecker, should actually be considered a devel­ opment aspect, since it is an aid to contract enforcement that might not be included in a production system. In

Kiselev's code NullChecker throws an exception and so would need to be modified in a similar way as Profiler, for example to throw an Error, to be a spectator in my categorization.14

13 Despite discussing a web application, I am still using "client" here in the sense of some code which uses another module, not in the sense of a web client or browser. 14The Runtime Assertion Checker in the JML tools suite uses this Error technique for signaling specification violations in a way that is unlikely to be caught and suppressed by the code being checked [32,33]. 32

Kiselev's runtime aspects (ConnectionChecking, Pooling, OutputStream Buffering, and ReadCache) are

all "useful but not critical" [84, p. 115]. These are units of cross-cutting concern that might not be part of

an initial implementation. But once added to the system they are likely to remain part of it. They are all

implementation utilities that apply to a single class. Under my proposal, as these aspects were written and

added to the application, an accept clause would be added to the advised class. To use this approach the call

join points in each of these aspects would be changed to execution join points.

The last two aspects in the table (NewLogging and PaidStories) are not categorized by Kiselev, but should

be considered production aspects. The are used to change the behavior of the application without invasive

editing. Under my proposal these aspects could be accepted using a root-level concern map. (PaidStories is an

example of code that qualifies as a spectator but would likely be named in a concern map so as to make its

functionality visible to all maintainers of the program.)

To summarize, except for the CodeSegregation aspect and a portion of the Authentication aspect, both of

which use AspectJ features that are outside the scope of the current work, all the aspects in Kiselev's case study

can be easily implemented under my proposal.

2.3.2.3 Laddad

I have also reviewed the examples in Laddad's text [86]. Except for ones that use features outside the scope

of the current work—introductions, declare error/warning, declare soft, precedence declarations, and the

"worker object creation pattern", discussed below—the previous categorizations apply. Having discussed most

of the interesting issues in the preceding, I will not belabor them here. However, a few unique points bear

mentioning.

Laddad's ThreadPool ingAspect (Listing 7.13 on p. 228) uses both call and execution pointcuts in a single

aspect. Nevertheless, this aspect is a client utility. The aspect allows clients of Java's thread API to use a thread

pool, instead of using a new Thread object for each thread needed (and relying on the garbage collector to

dispose of old Thread objects). The aspect uses call pointcuts to intercept calls to the Thread API. In particular,

the aspect intercepts calls to Thread's constructor and returns a custom DelegatingThread object taken from

the thread pool (or newly instantiated if the pool is empty). The DelegatingThread class is part of the thread

pool implementation. The aspect uses execution advice on this class to detect when the thread has completed

execution and can be placed back in the thread pool for reuse. In effect, the client utility Threa dPoo I ing Aspect

includes a small implementation utility within it to manage it's implementation of pool-able threads. Thus, the

DelegatingThread class in the thread pool implementation would have to accept the ThreadPoolingAspect.

Laddad's worker object creation pattern (§8.1) uses proceed closures. In this pattern, advice captures a 33

proceed expression inside an instance of an anonymous Runnable class. He gives the template for such capture as:

1 void aroundO : { 2 Runnable worker = new RunnableO { 3 public void run() { 4 proceedQ; } }

8 }

When the worker object is run, the advised code will resume, but in a new thread! The elided code in line

7 might place worker in a queue, or might call its run method immediately and let Java manage the multi­ threading. Such use of proceed is fascinating, but is outside the scope of my work which focuses on sequential aspect-oriented programs.

Laddad's participant pattern (§8.4) is another variation on hyper-cutting discussed in Section 2.2.1.1. Rather than using marker interfaces to allow a class to accept assistance from an aspect, in the participant pattern a class declares a nested aspect that extends some pre-defined abstract aspect. This nested aspect declares a concrete pointcut, overriding one from the abstract aspect. The concrete pointcut allows the class to specify which of its methods should be advised by advice in the abstract aspect. Thus the class "participates" in the decision about where advice should apply. Such an abstract aspect is clearly an example of an implementation utility and would be an (implicitly accepted) assistant in my categorization.

2.3.3 Summary of Evaluation

My proposed language features add restrictions to AspectJ. But my evaluation shows that these restrictions do not restrict the expressiveness of the language. In fact, most of the examples studied fall neatly into three categories: spectators, implementation utilities, and client utilities. The latter two are assistants with natural locations for explicit acceptance. This supports my contention (in Section 1.3.4) that experienced aspect-oriented programmers are already following disciplines, like the MAO discipline, that enable modular reasoning.

2.4 Specification and Reasoning

When a client invokes a method for which either the client or implementation module has accepted assistance, the behavior of that invocation is based on the sequential composition of the code along a par­ ticular control flow path. Similarly, one can reason abstractly about the possible behavior of the invocation 34 by considering specifications for the method and the advice that might be triggered. To do so, one needs specifications for advice and some means for sequentially composing them.

In this section, I sketch some specification constructs that might be added to JML to allow specification of programs written in AspectJ with my proposed language extensions. I refer to the extended JML as AspectJML.

I describe how the specifications from aspects and the base program may be composed to yield an effective specification for any code.

The discussion in this section ignores spectator advice. The static checks for spectatorhood, sketched above and formalized in Chapter 5, ensure the validity of this approach.

In order to focus on the most interesting issues, I just consider around advice with pre- and postconditions and frame axioms. I do not treat exceptions, or before and after advice.15 I also concentrate on advice on method call and execution. The handling of advice for other join points in AspectJ would be similar, with the specification of the method implementation in my formalism replaced with the semantics of the advised oper­ ations. For example, accessing a field named beans of an object coffee can be represented by a specification like:

requires true; assignable \nothing; ensures \result = coffee.beans;

2.4.1 Specifying Around Advice

Several interesting issues arise in the specification of around advice. The concept of specification cases, from the specification of methods in JML, provides some useful insight. Consider Figure 2.6 on the next page, showing a method with its JML specification. This specification includes two specification cases, separated by the also on line 6. The behavior of the method is the conjunction of the behavior defined by these two cases.

Whenever the precondition of a specification case, given by the requires clause, is satisfied, then the frame axiom (assignable clause) of that case must be satisfied by the method, and the postcondition (ensures clause) of that case must hold when the method terminates [90,158].

For example, suppose the method in Figure 2.6 were called with its first argument not equal to null, such that invoking isBottom() on the argument yielded false. In that case only the ignoredRight field could be mutated and the result of the method, denoted by the \result keyword, would have to be the first argument.

But what if the method were called with null as the first argument? In that case, neither specification case would apply. The behavior of the method is undefined (by the specification) in that case. It is also possible

15The specification constructs discussed in this section, and their composition, is based on joint work with Gary Leavens [39]. In that work we formally treat before and after advice, including exceptions; we do not provide a formal treatment for around advice. 35

, /*@ 2 @ public behavior 3 @ requires left != null && left.isBottomQ; 4 @ assignable \nothing; s @ ensures \result == right; 6 @ also z @ public behavior s @ requires left != null && Meft.isBottomO; 9 @ assignable ignoredRight; JO @ ensures \result == left; @*/

m } else { is ignoredRight = true; it, return left; }

18 }

Figure 2.6 Example of JML Specification Cases that the requires clauses for multiple specification cases may be satisfied. In that case the conditions of all the matching cases must be satisfied. Thus, we could rewrite the above specification, separating out the requirement on left != null, as shown in Figure 2.7 on the following page. This conjoining of specification cases with also is a form of parallel composition. I will take advantage of this to describe specification composition for aspects. Raghavan and Leavens [140] give the technical details on composing specification cases in JML.

The key problems in specifying around advice arise because of proceed expressions. In AspectJ, around advice might not proceed to the advised code, or it might proceed more than once. So in addition to specifying pre- and postconditions and frame axioms, specifications for around advice must be able to express the pattern of proceeds used in the advice. For modular verification of advice, the specification must also give the conditions that hold when proceeding and the conditions expected when the proceeded-to code terminates.

Finally, around advice can use the result of the proceeded-to code. Similar to the \ resu It keyword for specifying the return value of a method, specifications for around advice need some way to discuss the result of the proceeded-to code.

To solve these problems, I propose a new specification clause for AspectJML. This proceed clause has the same syntax as proceed expressions in AspectJ, but uses JML specification expressions for its arguments. (JML specification expressions are side-effect free, and include keywords like \old for referring to the pre-state value of a reference.) A proceed clause in a specification case converts that case into a compound specification case, 36

/*@ @ public behavior @ requires left != null; @ assignable ignoredRight; @ ensures true; @ also @ public behavior @ requires left.isBottomO; @ assignable \ nothing; @ ensures \result == right; @ also @ public behavior @ requires !left.isBottom(); @ assignable ignoredRight; @ ensures \result == left; @*/

Figure 2.7 Example JML Specification Showing Overlapping Specification Cases each part of which has its own pre- and postcondition and frame axiom. In the case following a proceed clause, the specification may use the keyword \reply to refer to the result of the proceeded-to code. Figure 2.8 on the next page gives an AspectJML specification of one of the pieces of around advice from the MoveLimiting aspect of Figure 2.2.

The figure consists of two specification cases, one starting on line 2 and one starting on line 12. Each of these specification cases is a compound case, split by a proceed clause (see lines 6 and 16). Consider the first specification case. The precondition says that this case is applicable when the distance to be moved is greater than the maximum (line 3). The frame axiom says that no state may be mutated before proceeding to the advised code, and the postcondition of the case before proceeding (line 5) says that the advice makes no additional promises to the advised code, beyond those implied by the precondition and frame axiom. The proceed clause beginning in line 6 asserts that if the precondition of the specification case holds, then the advice will proceed to the advised code, using the given arguments. Finally, the case beginning in line 8, says that no expectations are placed on the advised code and no state is mutated after the advised code completes, but line 10 says that the result (\result) of the advice is the result of the advised code (\reply).

Because of the simplicity of this advice, and my wish to convey the details of the specification language, this specification is actually more verbose than the method it specifies. This is not always the case. Typically a spec­ ification would provide a more abstract description of the behavior of the advice. Also, pre- and postconditions with the default value of true may be omitted.

Three more details of the proposed specification language design bear mentioning. (1) If a specification 37

, /*@ 2 @ public behavior 3 @ requires distance(argX,argY) > MAX_DISTANCE; 4 @ assignable \nothing; s @ ensures true; 6 @ proceed(argX * MAX_DISTANCE / distance(argX,argY), 7 @ argY * MAX_DISTANCE / distance(argX,argY)); s @ requires true; s @ assignable \nothing; 10 @ ensures \result == \reply; 11 @ also 12 @ public behavior 13 @ requires distance(argX,argY) <= MAX_DISTANCE; u @ assignable \nothing; is @ ensures true; w @ proceed(argX,argY); i7 @ requires true <8 @ assignable \nothing; ii @ ensures \result == \reply; m @*/ 21 FigureElement around(float argX, float argY) : 22 execution!* mao.FigureElement.move(float, float)) && args(argX, argY)

23 { 24 float moveDistance = distance(argX, argY); 25 if ( moveDistance > MAX_DISTANCE ) { 26 float ratio = MAX_DISTANCE / moveDistance; 27 return proceed( argX * ratio, argY * ratio ); 2s } else { 29 return proceed( argX, argY );

Figure 2.8 Around Advice Specification in AspectJML case for a piece of around advice does not include a proceed clause, then the advice will not proceed when the precondition of that specification case is satisfied. (2) The \old expression, for referring to pre-state values, always refers to the pre-state of the entire piece of advice, even when used after a proceed clause. (3) The \ reply expression for referring to the result of proceeded-to code, always refers to the immediately preceding proceed clause. JML includes mechanisms that would allow a specifier to refer to results from prior proceed clauses.

The code in Figure 2.9 on the following page illustrates these ideas, and also demonstrates the specification of code that proceeds more than once.

The advice in the figure applies to calls to the nextlnt(int) method of java.util.Random. The advice itself is rather silly, but serves to illustrate the ideas. The first specification case (lines 2 through 4) says that if the argument to the call is non-positive, then the advised method will not be executed and no state will be mutated. 38

/*@ @ public behavior @ requires max <= 0; @ assignable \nothing; @ also @ public behavior @ requires max > 0; @ assignable \nothing; H no values that exist in pre-state are modified @ . proceed(targ, \old(max) * 2); @ forall int firstResult; @ requires firstResult == \reply; @ assignable \nothing; @ proceed(targ, \old(max) * 4); @ assignable \nothing; @ ensures \result > (firstResult + \reply); @*/ int around( java.util.Random targ, int max ) : call(int nextlnt(int)) && target(targ) && args(max) { int maxStart = max; if (max <= 0) { return 0; } else { max = max * 2; int resultA = proceed(targ, max); max = max * 2; int resultB = proceed(targ, max); return maxStart + resultA + resultB;

Figure 2.9 Example Specification for Around Advice with Multiple proceed Ex­ pressions

The result value is unspecified in this case.

The other specification case, beginning in line 6 applies when the argument to the call is positive. Line 9 says that the advice proceeds to the method using an argument that is twice the original value. The implementation satisfies this specification because of the multiplication in line 24. Lines 10 and 11 demonstrate one way to capture values in a specification. The forall clause declares that the new variable firstResult may range over all possible int values. Then the requires clause restricts the variable to just that value that is the same as the result of the first execution of the advised code. Thus, when firstResult is used in line 15, it refers to the value of the first execution of the advised code, while \reply in that line refers to the second.

This technique of explicitly describing the control-flow structure of the advice relative to its use of proceed handles most advice. However, some advice is still outside the scope of the technique. For example, an aspect 39

Insistent might declare advice on a method for opening a network connection so that the method is just repeatedly proceeded to until it succeeds. I leave to future work the specification of such advice that proceeds an indefinite number of times.

The specification of before and after advice is much simpler than around advice. Before advice implicitly proceeds to the advised code. So specifications for before advice look like regular method specifications in

JML, but the postcondition of the specification gives the promises made to the advised code. After advice in

Aspect! includes mechanisms for binding the result of the advised code to formal parameters, so \ reply is not needed there. The precondition of a specification for after advice gives the conditions expected of the advised code, while the postcondition gives the conditions promised to the calling code.

2.4.2 Specification Composition

Having proposed extensions to JML for specifying around advice (and sketched their extension to before and after advice), I next describe how the effective specification of a piece of code may be determined from the specification of that code plus the specifications of any accepted assistants.

When reasoning about a call to an advised method from the client's perspective, one would like to use an effective specification that abstracts away the details of the control flow and intermediate state transformations.

That is, the effective specification from the client's perspective should just concern the preconditions as control flow leaves the client and the postconditions as control flow returns to the client, along with the relevant frame axioms. With explicitly accepted assistance, the effective specification may also need to refer to assistant instances, for example if the effective specification depends on assistant state.

I describe effective specifications in terms of paths. In a running program, the effective behavior is the sequential composition of the code executed along a control flow path. Similarly, the effective specification is formed by a kind of sequential composition of the specifications along an abstract path. When a set of paths are in parallel, then the effective specification of the set is a kind of parallel composition of the parallel paths' specifications.

I present my model in two stages. I first describe how to construct a specification composition graph, from the specifications of the implementation module and those of any assistants accepted by that module or the client module. I then describe how the graph is used to determine the effective specification of the invocation.

2.4.2.J Constructing a Specification Composition Graph

The specification composition graph is an abstraction of the control flow graph for the corresponding code.

The specification composition graph is based on the proceed clauses in the specification cases of applicable 40 advice. The graph is used to determine the possible paths through the advice and method specifications (and hence the code if the implementation is correct). These paths are used to calculate the effective specification.

The nodes of a specification composition graph come in two flavors. Some nodes represent simple (i.e., not compound) specification cases. Other nodes represent parameter binding events. The edges of a specification composition graph also come in two flavors, representing abstract arguments and formal parameters. The nodes and edges alternate so that a specification-case node is connected to a parameter-binding node by an abstract-argument edge, and the parameter-binding node is connected to a subsequent specification-case node by a formal-parameter edge. The idea is that specification-case nodes along any path will give the conditions that must hold on that path, while the edges and parameter-binding nodes will allow the formal parameters used in any specification cases to be connected to each other, and ultimately to formal parameter names that make sense from the client's perspective. An example below will, hopefully, make this clear.

The parameter-binding nodes in a graph are denoted by start and end labels representing the passing of arguments and the return of results respectively. Each graph includes one start node of degree 1, representing the call site in client code, and one end node of degree 1, representing the return site in client code.16

For formalizing specification composition,I use a desugared form for simple specification cases [140].I assume that methods referenced within the specification (which JML requires to be pure, i.e., side-effect free) are replaced with the value of \result from their postconditions, with appropriate substitution of actuals for formais [49]. Thus the requires clause

requires distance(argX,argY) > MAX_DISTANCE; from line 3 of Figure 2.8, would be desugared to:

requires Math.sqrt(argX*argX + argY*argY) > MAX_DISTANCE; assuming a reasonable specification for the distance method (and Euclidean space).I assume that the quan­ tification and binding technique, used in lines 10 and 11 of Figure 2.9 on page 38, is used for recording any pre-state values used in the specification case. Thus, no \old expressions appear in the desugared cases.

Because field references in specifications may use an implicit this target, and because this refers to dif­ ferent objects in the specification of a method versus that of advice, ambiguities might arise. So in a method specification, I make explicit all field references with an implicit target. And in a specification for advice,I replace all implicit or explicit this targets with a special variable \aspect_z. The special variables \aspect_l

16This formulation of the specification composition graph exchanges the meaning of nodes and edges from our original formulation [39]. I believe the present formulation is more satisfactory for dealing with around advice. 41 through \aspect_q1 are used consistently to represent the assistant aspects, accepted by either the client or implementation module, that are in scope at the call site.

With this desugaring, all simple specification cases have the form:

forall Q; where Q is a set of variable names with types

requires r; where r is a predicate

assignable /; where / is a set of variables

ensures e; where e is a predicate

In the specification composition graph, the specification-case nodes correspond to such desugared specifica­ tion cases. I also have to deal with the fact that the program state may change along a path because of allowed mutations. To handle this, I treat the predicates, r and e, as functions of the program state.

Let I represent the set of all possible program states. Then each specification-case node in the graph can be represented by a 5-tuple, v = (Q',r,,e, a), where Q' is Q along with \result and/or \reply if these keywords may appear in the specification case; the predicates r and e each have the type I —» Bool; and o el. represents the pre-state of the specification case.

A recursive procedure builds the specification composition graph for a given method call. As an example,

I will consider a call to FigureElement's move method, with FigureElement accepting the assistance of the

MoveLimiting aspect.I will use the specification of the around advice from Figure 2.8 on page 37.

In general a module may accept assistance from multiple assistants and both a client and an implementa­ tion module may accept assistance. The specification composition graph is formed respecting the ordering given in Section 2.2.1.1. (The composition could be relaxed to allow any ordering of advice, but then the specifications would have to built from cases that non-deterministically combined all possible orderings. If the aspects did not interfere with each other, then this combination might actually be deterministic. For clarity, I simply assume a total, symmetric ordering here.)

GRAPH CONSTRUCTION ALGORITHM The graph construction begins with one node for each specification case from the specification of the called method, plus nodes starto and endo- Add edges, labeled with the method's signature from starto to each of the specification-case nodes. Add edges, labeled "\ result" from each of the specification-case nodes to endo. Call the graph at this stage of construction GQ. Figure 2.10 shows GO for the example call, where the called method has but one specification case.

Next, a new graph is recursively generated for each piece of around advice, beginning with the one "nearest" to the actual method, according to the total, symmetric ordering of accepted advice. Number these pieces of advice from 1 to n in nearest-to-farthest order. 42

start.

public FigureElement move(float dx, float dy)

{float oldX, float oldY}, oldX == this.x && oldY == this.y, {this,x, this, y}, this.x == (oldX + dx) && this.y == (oldY + dy) && \result == this,

\ result

end,

Figure 2.10 Specification Composition Graph Construction, Stage Go

To construct graph G,, start with an empty graph. Create nodes start,- and end,-. Consider each top-level specification case (i.e., each case separated by an also) in the specification of advice i. For each simple specification case within the top-level case (i.e., each case separated by a proceed clause), create nodes vi through vm. Add an edge from start, to v\, labeled with the signature of the advice. For each node vj £

create a copy of graph G,_i. Add an edge from vj to start;-, of the copy. Add an edge, labeled

"\reply", fromend,_i of the copy to vj+\. Finally, add an edge, labeled "\result" from vm to end,.

Figure 2.11 on the next page shows a partially complete version of the graph G\ for the running example, after the construction for just the first top-level specification case from Figure 2.8 on page 37 has been com­ pleted. Notice the single copy of Go, representing the single proceed clause in the first top-level specification case. Figure 2.12 on page 44 shows the complete graph G\ for the running example, adding the nodes and edges for the other top-level specification case.

The final specification composition graph for a method call is Gn. Since there is only one piece of advice in the running example, Figure 2.12 shows a complete specification composition graph. 43

start

FigureElement aroundffloat argX, float argY) : args(argX, argY)

Math.sqrt(argX*argX + argY*argY) > \aspect_1,MAX_DISTANCE,

true, proceed(A,B)

{FigureElement \result, \reply FigureElement \reply}, true,

\ result == \ reply,

\result end

A = argX * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX*argX + argY*argY) B - argY * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX*argX + argY*argY)

Figure 2.11 Specification Composition Graph Construction, Partially Complete Stage Gi start

igureElement around(float argX, float argY) : args(argX, argY) FigureElement aroundffloat argX, float argY) : args(argX, argY)

Math.sqrt(argX*argX + argY*argY) Math.sqrt(argX*argX + argY*argY) > \aspect_1,MAX_DlSTANCE, <= \aspect_1.MAX_DISTANCE

true, true, proceed(A,B) proceed(argX,argY)

{FigureElement \result, {FigureElement \result, FigureElement \reply}, \reply FigureElement \reply}, true, true, \reply \ result == \reply, \ result == \ reply,

\ result \result end

A = argX * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX*argX + argY*argY) B = argY * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX*argX + argY*argY)

Figure 2.12 Specification Composition Graph Construction, Stage Gi 45

2.4.2.2 Composing Specifications Along A Path

The specification composition graph, Gn, contains all the information needed to calculate the effective specification of a method invocation. I first describe how to compose specifications along any single path in

Gn-

Consider a unique path from start to end in the graph. Because of top-level specification cases and around advice that does not proceed, this path may not visit every node in the graph. This path contains all the information necessary to (1) calculate the conditions that must hold if the corresponding path through the code is executed, and (2) map formal parameter names in one specification case to those in the adjoining ones.

«-CONVERTING SPECIFICATION CASES To prevent capture of locally bound variables when composing the specifications, I «-convert the specification cases and related advice signatures so that all bound variable names are unique. I reserve the method's formal parameter names for pre-state values of the effective specification.

This allows the effective specification to use formal parameter names that make sense from the client's perspective. However, this reservation means that I must «-convert the signature and specification cases of the method also. Similarly, I reserve the \result keyword for the post-state of the effective specification, so all instances of \result in the graph must also be «-converted. Figure 2.13 on the following page shows one such path through the specification control graph of Figure 2.12, after «-conversion. Compare this figure with

Figure 2.10 and Figure 2.11 to see the results of «-conversion. For clarity, I renumber the states, cr,-, in order.

I represent the «-converted path from the specification composition graph as a sequence of alternating nodes and edges

(starti.P], fi,J4i,...,startm,Pm, vm,Am,endm,...Pn, vn,An,er\dn), where n is number of specification-case nodes on the path, the Pi represent the labels on formal parameter edges, the vi = (Q'., r

CONNECTING BOUND VARIABLES If a given path is traversed in a program execution, then it must be the case that all the pre- and postconditions of specification cases along the path hold. This is the essential insight for constructing the effective specification. The abstract arguments and formal parameters given by edge 46

P^: FigureElement around(float argXI, float argYI) : args(argX1, argYI)

0, Math.sqrt(argX1 *argX1 + argYI *argYl ) > \aspect_1,MAX_DISTANCE, {}, true, A-,: proceed(A,B)

A = argXI * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX1 *argX1 + argYI *argY1) B = argYI * \aspect_1 ,MAX_DISTANCE /(Math.sqrt(argX1*argX1+argY1*argY1) p^publicFigureElementmove(floatdx2,floatdy2)

{float oldX, float oldY}, oldX == this.x && oldY == this.y, {this.x,this.y}, this.x == (oldX + dx2) && this.y == (oldY + dy2) && \result2 == this,

T A2: \result2

' L END2 ) {FigureElement \result], ' H FigureElement \reply]}, true, {}, P3: \reply] 1 \result] == \reply],

CT3 >

A3: \result3

Figure 2.13 Unique Path through Specification Composition Graph, a-converted 47 labels in the graph provide context for connecting the bound variables from each of the specification-case nodes. This ensures that the effective pre- and postconditions are sensible from the client's context.

For the sketch presented here, I assume the existence of a function bind that encodes the semantics of parameter passing in Aspect! and Java. So that this parameter passing can be represented in the effective specification, I further assume that bind generates a IML predicate for any given parameter passing operation.

Some examples follow:

Method call. For a direct method call, the effective specification should match that of the method. So for a

parameter-binding node with in-edge

A;_i = public FigureElement move(float dx, float dy),

and out-edge

Pi = public FigureElement move(float dx2, float dy2),

the predicate generated is bind{Ai-\,Pi) = (dx==dx2 && dy==dy2). This causes the «-converted

formal parameters of the method specification (dx2 and dy2) to match the formal parameters from the

client context (dx and dy).17

Initial advice execution. For the first piece of advice on a path, the predicate is generated according to As­

pect's pointcut binding semantics. For example:

MM(public FigureElement move(float dx, float dy),

FigureElement around(float argXI, float argYI) : args(argX1, argYI))

= (argXI ==dx && argYI ==dy).

This links the formal parameters in the «-converted advice specification (argXI and argYI) to the

formal parameters from the client code (dx and dy).

Proceed. For a parameter-binding node after a piece of advice proceeds, the predicate is generated according

17This case, where no advice is included, does not appear in the running example. 48

to Aspect's proceed binding semantics. For example:

Mn

public FigureElement move (float dx2, float dy2))

= (argX1==dx2 && argYI ==dy2).

This connects the formal parameters of the «-converted advice specification (argXI and argYI) to

those of the «-converted method specification (dx2 and dy2).

Return value. For an end parameter-binding node, connecting a specification case to subsequent around

advice,

bmd(\result2, \reply3) = (\result2==\reply3).

A full treatment of the bind predicate-generating function is beyond the scope of this work, though I formalize the parameter passing semantics of Java and a subset of AspectJ in Chapter 3. (For a full formalization of the bind function, I would have to include the signature of the relevant advice on each proceed(...)-labeled edge in the sketch presented here. This is because the semantics of proceed in AspectJ depends on the signature of the containing advice. Also, any information at a join point that is not bound by the advice passes unchanged to the called method. Thus a full formalization of bind would treat the data from the original join point as available throughout the graph.)

DEALING WITH INTERMEDIATE STATES I next describe the basic intuition for constructing the effective specification of the path. Recall that the path is

(starti.Pj, vi, Ai,...,startm,Pm, vm,Am,ertdm,...Pn, vn,An,er\dn).

The predicate generated in this initial construction is not the one that will ultimately be used. For example, it explicitly includes the entire program state at each stage along the path. I deal with that complication, and frame axioms, below.

1. Along a path, all the pre- and postconditions must hold, so conjoin the pre- and postconditions of each

specification-case node, vi, on the path:

(ri (CTi) A... Arn (an)) A (e\ (cr2) A...Ae„ {an+i)), 49

where the postconditions operate on the post-state,

2. Add conjuncts for each parameter-binding node of degree 2 on the path. This connects the proceed

arguments to formal parameters, and results to \reply variables:

(bind (AI,P2) A...A bind (A„_I, Pn))

A (n (CTi) A... A rn (£7nY) A (g] (£72) A ... AC„ (CT„+1)).

3. Add conjuncts for the start and end nodes of degree 1. This connects the abstract arguments from the

client's context to the starting formal parameters of any advice, and connects the ending result to the

client's \result variable.:

(.bind{Ao,Pi) A bind(An,\result))

A {bind(AI,P2)A...Abind(A„_I, P„)) (2.1)

A (n (<7l) A ... Ar„ (<7„)) A (ei (£72) A ... Aen (f7„+l)) ,

where AQ is signature of the called method.

Formula (2.1) gives the basic result of the effective specification, ignoring frame axioms. But, to reason about the effective specification from the client's perspective, I must eliminate the intermediate states from this formula. One way to do this would be to quantify over all the states, like:

Vf7,crn• X

where X stands for formula (2.1). However, in JML entire states are not directiy expressible, so this idea has to be used indirectly by quantifying over intermediate values of each of the free variables used in the predicates.

These intermediate values will also let me express the frame axioms.

For well-typed specifications, the only free variables are field references. The idea is this: for each field

18 reference var, introduce n+ 1 intermediate, quantified variables, uar\ varn+\, one for each state. So vari represents the value of the field reference var in state a. Then, based on the frame axioms, I include predicates that relate the value of var in one state to its value in the next. For example, if the frame axiom, /s, for the

18The field reference var will have the form this.name or aspect_i.name, because of the explicating of field references in the desugaring described in Section 2.4.2.1. The intermediate variables represent the entire reference form. 50 specification case 1/3, does not give permission to mutate var, then var$ var4. (This assumes that var has a non-reference type. If var has a reference type, then the predicate would be wzrj.equals( var4 ).)

To formalize this notion, let rnr stand for all the free variables in the path and let T be their types. For the sample path in Figure 2.13 on page 46, var = (this.x,this.y) and T - (float,float). I will write varL to

x represent all the intermediate variables in state a,. So for the example var2 = ( 2.y2)- (In general, appropriate

«-conversion may be needed to avoid collisions for like-named fields in different objects.) Now to remove intermediate state from the pre- and postconditions in formula (2.1), I substitute the intermediate variables for the free variables. I write {mfi / var\ for this capture-avoiding substitution. For example, the precondition,

r2, for a specification-case node, V2, is written r~i (02) in formula (2.1). With the notion of intermediate state variables, this precondition becomes ^ITwa/lw}. Because the intermediate state variables are quantified in

the effective specification, the resultant precondition contains no free variables. Thus the global state, <72, can

be dropped. A similar substitution applies for the postconditions, e,-.

ENCODING FRAME AXIOMS I have given enough machinery thus far to describe parameter passing and to

connect pre- and post-states of every specification case. I still need to address frame axioms. I also must show how to connect the pre-state of the client to the first intermediate state (the pre-state of the first specification

case), and similarly for the post-state. To this end, I define two more auxiliary functions, equal and notmod. Let

equal ( var,, varj) be the predicate denoting equality for the intermediate variable var in states i and j, using

the appropriate notion of equality, either == or .equalsQ. Let equal (varvarj) be the pointwise extension of

this function. For the running example,

equal{vâf],'vâf2) - (xi==X2 && y1==y2)>

indicating that no intermediate state variable changes between states 1 and 2.

Let notmod[f, var, i,j) stand for the predicate that says that all variables in var but not in the frame, f, are

unchanged between states i and j. That is,

notmod(f, var, i,j) = && equaUvar/, var;). vare.(mr\ f)

FORMING THE EFFECTIVE SPECIFICATION This machinery is now sufficient to state the effective specifi­

cation of a single path through the specification composition graph. Figure 2.14 on the following page gives

the general form of this single-path specification. A line-by-line description follows:

Line 1 declares all of the quantified, intermediate - state variables used in the pre- and postconditions, as 51

1 forall Tvâri; ...; forall Tmrn+\;

2 forall Qp forall Q'n; 3 requires 4 equal [var, var\ ) s && bind(Ao,Pi)

e && bind{A\,P2) && ... && bitid{An-\,Pn)

z && riflrâri/wzrt && ... && rn\UïïfnIUâr\ s && eilMrz/ïwt && ... && i/Trârf

9 && notmod[fi,Uâr, 1,2) && ... && notmod {fn-i,vâf,n-l,n);

10 assignable /iu...u/n; n ensures

i2 bind{Ao,Pi) && bind(An, \resuit)

n && bind{A\,P2) && ... && bind{An-i,Pn)

m && eifïw2/îw( && ... && en$vârn+ilvârl

iï && notmod (f\, var, 1,2) && ... && notmod[fn,vâr,n,n+l)

!» && equal[varn+\, var);

Figure 2.14 General Form of the Effective Specification for a Single Path in the Specification Composition Graph

discussed above.

Line 2 declares the quantified variables declared by all of the specification cases on the path.

Lines 3-9 give the preconditions for the effective specification. In general, the preconditions of the effective

specification include all of the conjuncts from formula (2.1) on page 49, except for the final postcondition

and the binding of the final result. The logic is this: to reach the final specification case on this path,

every precondition on the path must have been satisfied and, by the assumed correctness of the

implementation, every postcondition up to the last must also have been satisfied.

Line 4 constrains the first intermediate state, represented by vafi, to be the initial state of the effective

specification.

Line 5 connects the abstract arguments from the client's perspective to the «-converted parameters of

the first specification-case node.

Line 6 models the passing of parameters and results all the way through the execution up to the last

specification case.

Lines 7 and 8 conjoin all of the preconditions along the path, and all of the postconditions but the last,

as discussed above.

Line 9 constrains all of the intermediate states, except the last, to satisfy the frame axioms of the

specification cases along the path. 52

Line 10 gives the frame axiom of the effective specification. Any state that is declared assignable by any

specification case along the path must be considerable assignable for the effective specification.

Lines 11-16 give the postconditions for the effective specification. The postconditions include all of the

parameter passing constraints and all of the postconditions from formula (2.1) on page 49.

Line 12 maintains the constraint on the abstract arguments from the client's perspective. It also adds a

constraint mapping the result from the last specification case to the special \result variable.

Line 13 maintains the constraints on the passing of parameters and results through the execution.

Line 14 asserts that all of the postconditions of the specification cases along the path hold in the post-

state of those cases. The frame conditions may allow some of those postconditions to no longer

hold in the post-state of the effective specification.

Line 15 constrains all of the intermediate states, including the last, to satisfy the frame axioms of the

specification cases along the path. Compare this to line 9.

Line 16 constrains the final intermediate state, represented by varn+\, to be the post-state of the

effective specification. Compare this to line 4. Although these predicates constrain the first and last

intermediate states to the same variables, var, those variables in the requires clause represent the

pre-state, while in the ensures clause they represent the post-state. Thus, these two similar-looking

constraints do not force the pre- and post-states to be equal, as one might naively assume.

Each possible parallel path through the specification composition graph is represented by a single-path specification case like the one in Figure 2.14. To form the effective specification of the entire graph, I simply conjoin these single-path specifications using JML's also operator. This "parallel composition", alluded to earlier, allows the client programmer to abstractly reason about an invocation of a method in the presence of accepted assistance.

2.4.2.3 An Example Effective Specification

Although the general form of effective specifications presented in the previous section appears quite complex, in practice most of the detail cancels out. I demonstrate this for the running example.

Suppose a client program includes the following code:

FigureElement fe = ... fe.move(2,13); and suppose that FigureElement has accepted the MoveLimiting assistant. The specification composition graph for this method call is the one I have been using as a running example. Figure 2.15 on the next page 53

1 forall float x1, y1; forall float x2, y2; forall float x3, y3; forall float x4, y4; 2 forall float oldX, oldY; forall FigureElement \result3, \reply3; J requires 4 this.x =- x1 && this.y == y1 5 && argXI == dx && argYI == dy

6 && dx2 == argXI * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX1 *argX1 + argYI *argY1 )) && dy2 == argYI * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX1 *argX1 + argYI *argY1 )) && \result2 == \reply3 ? && Math.sqrt(argX1*argX1 + argYI *argY1 ) > \aspect_1 ,MAX_DISTANCE && oldX == x2 && oldY == y2 && true s && true && x3 -= (oldX + dx2) && y3 == (oldY + dy2) && \result2 == this g && x1 —= x2 && yl == y2; zo assignable this.x, this.y; a ensures i2 argXI == dx && argYI == dy && \result == \result3 n && dx2 == argXI * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX1 *argX1 + argYI *argY1)) && dy2 == argYI * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(argX1 *argX1 + argYI *argY1 )) && \result2 == \reply3

n && true && x3 == (oldX + dx2) && y3 == (oldY + dy2) && \result2 == this && \result3 == \reply3 n && x1 == x2 && y1 == y2 && x3 == x4 && y3 == y4

it, && this.x == x4 && this.y == y4;

Figure 2.15 Effective Specification for the Path Shown in Figure 2.13 gives the effective specification for one path through this specification composition graph, the path shown in

Figure 2.13.

The line numbers for this effective specification correspond to those in the earlier figure showing the general form. Thus the description of each of the lines, given in the previous subsection, can also be read in conjunction with this new figure. The reader may find it helpful to do so.

As mentioned above, much of the information in the effective specification can be suppressed. By using transitivity of equality (within clauses); the rules that false is the zero, and true is the identity, of conjunction; and dropping unused intermediate state variables, I reduce the effective specification in Figure 2.15 to the one shown in Figure 2.16 on the following page. "Resugaring" this specification case, and adding in the simplified and sweetened specification case for the other path in Figure 2.12, yields the effective specification shown in Figure 2.17. With the understanding that \aspect_l refers to the instance of MoveLimiting, this effective specification matches our intuition.

Thus, my proposed specification constructs for advice, with the specification composition algorithm sketched here, allow clients to abstractly reason about advised code. Furthermore, if the applicable advice can be modularly identified, as with my proposed language features, then this abstract reasoning is also modular. 54

forall float oldX, oldY; requires Math.sqrt(dx*dx + dy*dy) > \aspect_1 ,MAX_DISTANCE && oldX == this.x && oldY == this.Y assignable this.x, this.y; ensures this.x == (oldX + dx * \aspect_1 ,MAX_DISTANΠ/ (Math.sqrt(dx*dx + dy*dy))) && this.y == (oldY + dy * \aspect_1 ,MAX_DISTANCE / (Math.sqrt(dx*dx + dy*dy))) && \result == this;

Figure 2.16 Simplified Version of Effective Specification from Figure 2.15

requires \aspect_1 ,distance(dx,dy) > \aspect_1,MAX_DISTANCE assignable this.x, this.y; ensures x == (\old(x) + dx * \aspect_1 .MAX_DISTANCE / \aspect_1 ,distance(dx,dy)) && y == (\old(y) + dy * \aspect_1 ,MAX_DISTANCE / \aspect_1.distance(dx,dy)) && \result == this; also requires \aspect_1 .distance(dx,dy) <= \aspect_1.MAX_DISTANCE assignable this.x, this.y; ensures x == (\old(x) + dx) && y == (\old(y) + dy) && \result == this;

Figure 2.17 Effective Specification Derived from the Specification Composition Graph in Figure 2.12

2.5 Discussion

This section discusses several interesting issues raised by my proposed language features in regards to other features of AspectJ. I also consider some questions raised by my algorithm for generating effective specifications, and touch on issues of tool support

2.5.1 Language Issues

2.5.1.1 Call and Execution Join Points

Explicit acceptance of assistance interacts in interesting ways with call and execution pointcuts. Consider the MoveLimiting example from Figure 2.2 on page 17, but suppose instead of using execution pointcut descriptors, it used call ones. If FigureElement's module in Figure 2.1 on page 16 accepted this hypothetical, 55 call-based MoveLimiting assistant, but no client did, then the advice in the assistant would only apply to the calls to setX and setY within the body of the move method. Calls to any of the three methods from outside

FigureElement would not be advised. This is because the hypothetical assistant only uses call join points.

Invocations of FigureElement's setX, setY, or move methods from client code would not be advised because no client code accepts the assistance. The actual MoveLimiting assistant uses execution join points, rather than call ones. Thus, FigureElement's module can accept the assistance and the advice applies to invocations of setX, setY, or move from all client modules—MoveLimiting is an implementation utility.

One might suppose that I could change the semantics of call join points, and eliminate execution join points altogether, by relying on the explicit acceptance of assistance to determine when to execute the advice code. But where should such advice go if an assistant is accepted by both a client and an implementation module? The compiler cannot modularly know where all accept clauses in a program might appear, and so there is no modular answer to the question. Thus both call and execution join points are required in the language.

The call-execution distinction also affects the distinction between client and implementation utilities, discussed in Section 2.3.2. An assistant using call join points is not a viable implementation utility. Conversely, an assistant using execution join points is not a viable client utility. To write an assistant that could fill either role, one would have to write pointcuts that used a combination of call and execution pointcut descriptors, along with the dynamic-context pointcut descriptor cflowbelow to prevent duplicate application of the advice.

Something like

(call(S) || execution( S ) ) && !cflowbelow( call( S ) ) might suffice. This pointcut applies to any call or execution of the method matched by S, provided that the method does not already have a frame on the call stack (excepting the top frame). It may be reasonable to define a syntactic sugar for such pointcuts. However, the cflowbelow pointcut requires runtime checks whereas call and execution do not. The technique also suffers from the general AspectJ problem of avoiding binding on the first recursive call versus on all recursive calls, as is the case with cflowbelow. Thus, restricting a given assistant to being exclusively a client utility (using call) or an implementation utility (using execution) is likely to be more efficient, and is more likely to be correct.

2.5.1.2 Other Features of AspectJ

It seems that ordering advice based on the ordering of accept clauses might eliminate the need for Aspect's precedence declarations. While technically this seems to be the case, I are not claiming that relying on the ordering of accept clauses is any less error prone than relying on precedence declarations to control the order 56

of interacting aspects. On the one hand, it would be quite easy to accidentally misorder the acceptance of two

pieces of interacting advice in a concern map or the accept clauses for a module. Compared to precedence

declarations, the use of explicit acceptance also spreads out and makes less obvious the kind of decisions that

precedence declarations (may) record in one place. On the other hand, when writing an aspect, it is impossible

to know all the potential other aspects over which it should have precedence. And effective specifications allow

clients to determine that the actual order used might have the wrong behavior.

The current work does not address Aspect's introduction mechanisms and declare parents construct. An

aspect that used introduction to replace an inherited method of a class with an overriding method would

clearly change the behavior of that class and would therefore be an assistant. On the other hand, suppose an

aspect introduced a new, non-overriding method to a class. Since no other code could have called that new

method, this introduction should not change the behavior of existing code. So such an introduction could be

allowed in a spectator. (This case is similar to the introduction of external generic functions via MultiJava's

"open class" mechanism [38, 43, 46].) However, I leave this decision for future work, because introduction

involves subtle modularity issues, particularly for avoiding runtime ambiguities. These issues are made more

complex by the possibility that the newly introduced methods might be advised by existing aspects, or that a

change in the base program might make a previously "fresh" introduced method into an overriding one.

The current work also does not address Aspect's declare error and declare warning constructs. But these

constructs do not change the behavior of a program in any way. Instead they provide advice to the compiler

itself, telling the compiler that if certain join points are detected at compile-time, then an error or warning

should be issued. Thus, these constructs can be allowed in spectator aspects.

An aspect that used the declare soft construct, which converts checked exceptions to unchecked ones,

would clearly change the control flow of a program to which it was applied. Such an aspect is thus an assistant.

An alternative technique in regular AspectJ for implementing the hyper-cutting pattern (discussed in

Section 2.2.1.1) is to use within and withincode pointcut descriptors to statically limit the code to which

a particular piece of advice applies. Unlike accepts clauses and concern maps, this approach buries the

applicability of advice within pointcut descriptors. The within approach to hyper-cutting makes it even

harder to find applicable advice than with the (already non-modular) marker interface approach. The within

approach is a handy implementation technique, however. In my prototype implementation of accepts clauses

and concern maps, I use the within technique in the intermediate code. 57

2.5.2 Specification Issues

It seems that the construction of specification composition graphs could lead to a combinatorial explosion of paths, especially when multiple pieces of around advice advise a given join point. This seems unavoidable in general; however, in practice two things would mitigate this problem. First, it is unlikely that a particular piece of advice will proceed more than once. The most common idiom by far is proceeding exactly once, though some pieces of advice for optimizations, for example, do not proceed when a cached result is available.

Secondly, the conditions along some paths may be mutually exclusive, meaning that those paths cannot be taken in practice. The problem is also somewhat controlled by my insistence on a total ordering for advice execution.

There are also some interesting interactions between abstract module interfaces and implementation utilities. A module, M, accepting assistance from an implementation utility aspect, might give the effective specification of a method in its interface, rather than the specification ignoring advice. Then a facility could be provided to allow M to hide the acceptance of this assistance from client modules. Based on the ordering of advice presented in Section 2.2.1.1 and the specification composition graph algorithm given in Section 2.4.2.1, the programmer of a client module could calculate the effective specification of a method in M, by composing the specifications of any client-accepted assistance with the effective specification exposed by M.

Dynamic-context pointcut descriptors, like cflow, cflowbelow, and if, present challenges for specification composition. It is not possible, in general, to statically determine which join points such a pointcut will match.

A first approach to handling dynamic-context pointcuts is to construct an effective specification that non- deterministically assumes that the advice may or may not be executed. A better solution is probably to include the dynamic-context pointcut descriptors as predicates that may be used in preconditions of specification cases. The specification composition algorithm would still include cases assuming that the advice may or may not be executed, but the cases would be guarded with the dynamic-context predicates. Then a verifier, or the programmer, could eliminate some cases if he had knowledge of the dynamic context.

2.5.3 Tool Support

My algorithm for constructing effective specifications naturally raises the possibility of tool support for automatically generating effective specifications. This is somewhat related to the JMLdoc tool, in the JML tools suite [28]. JMLdoc will generate the specification of an overriding method by conjoining the method's specifica­ tion with that from any overridden superclass methods (through the entire class hierarchy). A documentation tool for AspectJML could similarly generate effective specifications for code that used implementation utilities.

Perhaps more interesting is the possibility of adding automatic generation of effective specifications to 58 an integrated development environment like the AJDT for ECLIPSE. The development environment could calculate the effective specification for a piece of code "on the fly". In the current AJDT, markers appear in the source code editor, indicating where aspects might apply. But with support for effective specifications, the development environment could provide a pop-up window describing the meaning of a particular piece of code, given the accepted assistance. One might even consider using a theorem-proving toolkit to see if the preconditions of the effective specification are mutually exclusive, indicating that the effective specification cannot be satisfied.

Although my proposed language extensions would make the generation of effective specifications more efficient, AJDT already maintains a global registry of aspect and base program interactions. Essentially the build configuration of the system acts as a root-level concern map. So support for effective-specification-based tools could be added to AJDT without extending the core AspectJ language.

With AJDT, the global interaction registry compensates for the lack of modularity. Such tool support is not, however, a complete solution to the problems with modular reasoning.

Integrated development environments for object-oriented languages also provide support for manipulating and reasoning about polymorphic method calls and overriding methods, but behavioral subtyping is still needed. Behavioral subtyping helps programmers to think about object-oriented code. It also helps them to design code that is easier to understand. This is reinforced by a wealth of articles on trade web sites that discuss the use of the "Liskov Substitution Principle" [103], the popular name for the property provided by behavioral subtyping.19 I contend that the discipline described here, and the enabling language features, provide similar benefits in guiding programmers' thinking and design efforts. I leave a thorough evaluation of this contention to future work, after the development of tools implementing my proposal.

2.6 Related Work

Kiczales and Mezini [80] argue that the modularity properties of aspect-oriented programs should be understood in terms of "aspect-aware interfaces". These interfaces are based on the global configuration of a system and essentially provide a bi-directional mapping from methods to associated advice, and advice to advised methods. Assuming the existence of such an aspect-aware interface, the authors then argue that reasoning about cross-cutting concerns is simpler in an aspect-oriented implementation than in a purely object-oriented implementation of the same program.

The arguments of the paper are purely rhetorical; the paper presents no formal analysis nor any case studies.

19A Google search for the quoted string "Liskov Substitution Principle" yielded over 7,000 results on June 19, 2005. 59

A single example is used to support the claims. That example examines the process necessary to refactor a

program written in an aspect-oriented style, versus the same program written in a pure object-oriented style.

In either program an implementation-level search is needed to understand the design. In the aspect-oriented

version, the change necessary to support the refactoring can be localized in a single module. However, it does

not seem that the localization of this change is because of the cross-cutting expressiveness of aspect-oriented

programming perse. Rather, the change can be localized because AspectJ provides predicates over the current

call stack: cflow and cflowbelow. The refactoring in their example could be done in a pure object-oriented

language that had such predicates.20

So essentially, their argument is that reasoning is no less modular in aspect-oriented programs than it is in

object-oriented programs where cross-cutting concerns are scattered and tangled. The objective of my work

is to demonstrate that, given the appropriate design discipline, reasoning in aspect-oriented programs can

actually be more modular.

Nevertheless, Kiczales and Mezini's argument that the understanding of cross-cutting concerns requires

some understanding of the global system configuration is compelling. For if there is no global system configura­

tion, there is no substrate for concerns to cut across. This idea of lifting concerns into the global configuration

was first proposed in my earlier work with Leavens [40] and is refined here. Most modern programming

languages offer module hierarchies (e.g., Java's system of classes, nested classes, and packages). It is natural to

generalize the acceptance of aspects to any level in such a hierarchy. This is what I have done with concern

maps.

The "aspectual collaborations" of Lieberherr et al. [102] are somewhat related to my concern maps (see also

Ovlinger's dissertation [130]). With aspectual collaborations, advice is declared within modules using abstract

representations of the pointcuts to be matched. Modules must be explicitly composed. This composition

reifies the pointcuts, making explicit the ways in which one module's advice might attach to another module's

methods. While aspectual collaborations offer some nice modularity properties, they require all composition

to be done at the top-level, instead of at any level of the module hierarchy as for concern maps. Aspectual

collaborations do not address the problem of reasoning about AspectJ programs, since aspectual collaborations

do not use AspectJ. Finally, it is unclear how anything with the flexibility of spectators could be expressed using

aspectual collaborations.

Katz and Gil [76] suggest that the body of work on "superimposition", for reasoning about distributed

algorithms, might provide a fertile ground for ideas in developing aspect-oriented programming. (Bougé

20The seed for this idea was planted by Christina Lopes in a post to the aosd-discuss mailing list, where she mentioned including call-stack predicates in a non-aspect-oriented language. 60 and Francez [24] give an approachable introduction to superimposition.) Katz and Gil briefly sketch three categories of aspects. Their "spectative" category matches my notion of spectators. The other two categories of aspects they mention map to my notion of assistants. However, they do not consider a language design that might help enforce and exploit these distinctions. Because of this they do not address anything like my concern maps and they do not talk about how one might enforce that declared spectators have no observable side effects. Their suggestion regarding mining the work on superimposition in developing aspect-oriented programming seems reasonable. Much of the work on superimposition is concerned with proving properties of distributed algorithms, or adding additional provable properties to distributed algorithms without disturbing other underlying properties. My work can be viewed as extending these more theoretical ideas into practical language designs.

Also attempting to make superimpositions more practical, Sihman and Katz [148] describe Super J, a

notation and preprocessor for superimpositions. Superimpositions in Super} are defined as sets of generic

parameterized aspects and singleton classes. When applying a superimposition to a given "basic program", an "activation" is used to bind the superimposition's parameters to classes and methods in the basic program.

Superimpositions have specifications, including requirements on the basic program and results assured if those

requirements are met. The specification language used is informal, though the authors note that a temporal logic could be used and suggest mapping to model checking systems for Java as a means of verification.

Verification conditions and a sketch of a soundness proof are given. The authors note that if a model of all basic

programs satisfying the superimposition's requirements can be built, then verification of the superimposition

against this model will independently prove the correctness of all applications of the superimposition.

The implementation of Super} is as a preprocessor that uses their "activations" to generate regular AspectJ

aspects from the generic aspects of a superimposition. Running these aspects and the basic program through

the regular AspectJ compiler yields the final program.

Superimpositions may be combined using merging (both merged superimpositions apply to the basic

program but not to each other) or sequencing (one superimposition applies to the basic program, the other to

the resultant combination).

SuperJ was designed to meet a different set of goals then the ones that I address. Sihman and Katz are

concerned with global properties of the basic program and superimposition, while my work is more about

detailed design and specification. The authors claim that AspectJ and other languages do not provide a

mechanism for specifying and reasoning about a collection of aspects, but this ignores the possibility of using

a single aspect with nested aspects to encapsulate a superimposition-like construct. The authors also neglect

to mention that they do not actually have a specification language. The authors do not address whether a 61 closed-world assumption is needed over their basic programs, though it seems to be. Thus, their system is not appropriate for specifying aspects to be applied to components, which themselves must be combined with other code to be useful. My spectators can be applied this way, as can implementation-utility assistants.

Krishnamurthi et al. [85] present an application of model checking to verifying that aspects do not violate properties verified of the base program. The technique is novel in that a base program interface may be calculated from the base program and a fixed set of pointcut descriptions (which may depend on dynamic properties). Once calculated, verification of aspects can be done without access to the base program (assuming that the base program interface and pointcut descriptions don't change). Another novel technique is to use the model checking machinery itself, applied to a "reversed machine", to calculate the aspect-aware interface.

The work assumes a fixed base program and pointcut descriptions, a state machine model of the program, specifications in the temporal logic CTL, and no access to the base program source after interface calculation.

Properties to be checked must be known when the aspect-aware interface is constructed, i.e., the technique "is designed to establish the preservation of program properties by aspects." Like the work of Sihman and Katz above, this work focuses on global properties rather than detailed design and specification.

Zhao and Rinard [162] implement the specification composition ideas described here, but based on

Leaven's and my earlier description of those ideas [39]. Our earlier work does not consider advice that can proceed more than once, nor does it include a mechanism like \reply for referring to the results of proceed in specifications; and so neither does theirs. Their implementation simply takes the specifications of aspect- oriented code, weaves them together based on our composition, and attaches the resulting specifications to woven Java code emitted by the Aspect! compiler. However, the current Aspect) compiler no longer emits

Java source code, so there is no longer a plain Java substrate to which woven specifications can be attached.

Also, their implementation of our ideas preceded our design of concern maps, so the implementation requires scattering of accepts clauses into every class that uses an assistant aspect. They do not treat spectators at all.

I discuss other related work on reasoning in aspect-oriented languages that is more formal in nature in subsequent chapters, where comparisons to my work can be made more readily [8,48,146].

Concern maps, especially at the root of a package hierarchy, bear a strong resemblance to configuration files in a build management system like ANT or MAVEN [69,106]. One consequence of my proposal is to elevate a portion of the build configuration into the implementation language. This standardizes the description of aspect and base code composition, allowing a variety of tools to use the same composition semantics. Using concern maps to specify this composition does not preclude the use of a build management system for other tasks in the build process. 62

2.7 Conclusion

In this chapter, I have presented the MAO discipline for modular aspect-oriented reasoning. The MAO discipline addresses the twin problems of modular reasoning in aspect-oriented languages: (1) unseen aspects may apply to the code, and (2) aspects may be developed without complete knowledge of the code that will be advised. The discipline addresses these problems by separating aspects into two sorts: benign spectators and surprising assistants. The discipline also requires that the aspect author and the programmer of advised code share the burden of ensuring modular reasoning.

I have argued that a few additional language features are sufficient to support the MAO discipline in a language like Aspect). My proposed features statically separate aspects into assistants and spectators. Assistants have the full power of Aspect)'s aspects, but to maintain modular reasoning I require that assistants be explicitly accepted. Spectators are constrained to not modify the behavior of the modules that they view. This allows modular reasoning about the advised code, even if spectators remain unseen.

My proposal introduces concern maps to allow acceptance of assistance, while avoiding the scattering of duplicate accept clauses throughout a program.

I have described an evaluation of the practical effect of my proposed language features. My evaluation looked at Aspect) style guidelines and three sets of Aspect) examples. The ATLAS case study identifies style rules that are equivalent to my definition of spectators. I studied the examples from the AspectJ Programming Guide, and Kiselev's and Laddad's books. For the Aspect) constructs considered in the current work, my language features can handle their examples with no changes in most cases, and minor changes otherwise. The ready identification of places to accept assistance from client or implementation utilities in these examples supports my contention that experienced aspect-oriented programmers are already using disciplines, like the MAO discipline, that enable modular reasoning.

I have described extensions to the )ava Modeling Language that allow one to write specifications for advice.

I have given a formal model for advice composition that allows one to determine the effective specification of a method in the presence of accepted assistance. This model also illustrates the reasoning a programmer must undertake even in the absence of formal specifications.

The major technical challenge for my proposal is checking that aspects declared as spectators meet my definition, as discussed in Section 2.2.2.1 have specified constraints on spectators that allow modular reasoning about their (lack of) effect on control flow. A type system that restricts aliasing and mutation allows modular reasoning about spectators (lack of) effect on the relevant state of the modules they view. The remainder of this dissertation presents: 63

— an aspect-oriented calculus for investigating these ideas in a formal setting, and

— a sound type-system for the calculus that statically enforces my proposed restrictions on spectators.

This formal foundation is essential to demonstrating the soundness of the reasoning techniques sketched here.

Aspect! possesses a rich semantics of advice binding and pointcuts. This means that even a core language

representing a small subset of the full language presents formidable obstacles to formalization. Through a

series of increasingly rich formalisms, I demonstrate that a firm foundation for studying reasoning in Aspect!

can be built. I use this foundation to prove that my proposed restrictions on spectators are indeed statically

verifiable. 64

CHAPTER 3. MiniMAOv INVESTIGATING THE SEMANTICS OF

PROCEED

This chapter describes a core aspect-oriented language, MiniMAOi. MiniMAOi is intended to provide a formal foundation for studying the spectators and assistants proposed in the preceding chapter. It is designed to formalize core features of Aspect). In particular, MiniMAOi models the ability of advice in Aspect] to:

— change the target object of an advised operation, possibly affecting dynamic method selection;

— change or capture the arguments to, or results from, an advised operation; and

— affect control flow to an advised operation, causing it to be executed once, multiple times, or not at all.

These abilities are central to advice that introduces "surprising" behavior into advised code. Thus, MiniMAOi provides the desired foundation for further study.1

MiniMAOi is sufficiently expressive to code key aspect-oriented idioms. But by minimizing the set of features, I arrive at a core language that is sufficiently small as to make tractable formal proofs of type safety and—in later extensions—proofs of desired modularity properties.

For clarity, I begin with a core object-oriented calculus with classes. I then extend this object-oriented calculus with aspects and advice binding.

3.1 MiniMAOo'. A Core Object-Oriented Calculus with Classes

In this section I introduce MiniMAOo, a core object-oriented calculus with classes. MiniMAOo is an impera­ tive calculus derived from Classic Java [61]. But, following the lightweight philosophy of Featherweight Java [73],

I eliminate interfaces, super calls, method overloading, and let expressions. Since eliminating let expressions eliminates implicit sequencing [1], I introduce explicit expression sequencing. I adopt Featherweight Java's

1Portions of this chapter appeared in a paper at Foundations of Aspect-Oriented Languages (FOAL) 2005, co-authored with Gary Leavens [42]. 65

P :: = decl* e

decl :: = class c extends c {field* meth* } field :: = t f; meth:: - t m(form* ) { e }

form :: = t var, where var # this

e::- new cQ \ var | null | e.m( e* ) | e.f | e.f = e | cast te \ e; e

c.de'té, the set of class names t,s,ue 3~, the set of types /e^, the set of field names m G M, the set of method names vare {this} uV, where Y is the set of variable names

Figure 3.1 Syntax of MiniMAOo technique of treating the current program and its declarations as global constants. This avoids burdening the formal semantics with excess notation—when MiniMAO is fully developed the notation is quite heavy enough.

One innovation of MiniMAOo is the separation of method call and method execution into two primitive operations in the calculus. This simplifies the modeling of AspectJ's method call and method execution join points in the aspect-oriented version of the calculus.

3.1.1 Syntax of MiniMAOo

The syntax for MiniMAOo is given in Figure 3.1. A MiniMAOo program consists of a sequence of declarations followed by a single expression. The expression represents the entry point for the program, like the execution of a program's main method in Java.

In MiniMAOo the declarations are all of classes; later calculi will add other sorts of declarations. A class declaration gives the name of the class, the name of its superclass, and a sequence of fields and methods. Mini­

MAOo does not include access modifiers; all methods and fields are globally accessible. For my purposes, access modifiers would be gratuitous complexity. MiniMAOo also omits constructors. All objects are instantiated with their fields set to null. Constructors can be modeled by defining methods that initialize the fields.

The set of types in MiniMAOo is denoted by 3~. MiniMAOo includes just one built-in type, that of Object, the top-most class in all class hierarchies. In MiniMAOo, I define Object to contain no fields or methods. For 66

MiniMAOo, ST , the set of valid class names. rf> is left unspecified, but for examples I will take it to be the set of all valid Java identifiers. I use a similar convention for the sets & of valid field names, Jl of valid method

names, and Y of valid variable names.

The field declarations within a class declaration just give a type and a field name. I omit field initializers

from the calculus.

Method declarations in MiniMAOo consist of a return type, the method name, a sequence of formal

parameters (which are similar in form to field declarations), and a method body expression. For simplicity I do

not include return statements in MiniMAOo; instead, the result of the method is just the result of evaluating

the body expression, with proper substitution for formal parameters and this.

MiniMAOo includes just a few different kinds of expressions. The expression new CO creates an instance of

the class named C, setting all of its fields to the default null value. Variable references and null expressions

have the usual meaning. Method invocations are written as in Java, as are field access and update. For syntactic

clarity, I follow Classic Java in using the syntax cast t e to represent the Java cast ( t ) e. Finally, I include an

expression for sequencing: e; e. One could simulate sequencing through a baroque combination of classes

and method calls, but the additional complexity of including an actual sequencing expression is small, so I

choose the direct approach.

3.1.2 Operational Semantics of MiniMAOo

I describe the dynamic semantics of MiniMAOo using a structured operational semantics [58,137,160].

The semantics is given in Figure 3.2 on the following page and is quite similar to that for Classic Java. There are

three main differences: a stack (which will be used for aspect binding in MiniMAOi), a primitive operation for

expression sequencing, and the separation of method call and execution into separate primitive operations.

I add two expressions for the operational semantics of MiniMAOo that do not appear in the static syntax.

To model state, I extend the set of expressions to include locations, loc e ££. One can think of locations as

addresses of object records in a global heap, but for the purposes of the calculus I just require that f£ is some

countable set. To model method execution independently from method calls, I add an application expression

form, where a (non-first-class) fun term represents a method and an operand tuple represents the actual

arguments after method dispatch but before substitution of actual arguments for formal parameters. The fun

term carries type information: a function type, T, mapping the target and argument types to the return type

of the method. This type information is not used in evaluation rules, but is helpful in the subject-reduction

proof. The use of the application expression form in the operational semantics is described in more detail in

the subsequent subsection. 67

Syntax extensions:

e:: =... | loc | ( / (e* ) )

I :: = fun m(var*).e: x

t :: -fx ... x t —- ? y :: = Zoc | null

loc e if, the set of store locations

Objects:

o :: = [f.F]

F:^ —7

Evaluation contexts:

IE:: = - I E.m( e... ) | v.m( v...Ee... ) | ( Z ( z;...Ee... )) |

cast t E I E.f I E; e I E./ = e I v.f = E

Evaluation relation:

:

^ (E [ Zoc],/, S E (Zoc— [ c.{/ — nu 11 •/ E dora [fieldsOfic))}])) NEW where loc t dom{S)

(E[loc.m( v\,...,vn )] ,/,S> — (E|( Z ( loc, v\ vn ))],/,S) CALL where S(Zoc) = [£. F] and methodBody(t,m) = Z

(E[(fun m{varQ,...,varn).e\T (vq,...,vn))],J,S)-— CAST where S(Zoc) = [s.F[ and s -< l (E[cast t null] ,/,S) —

(E[null.m( v],...,vn )},J,S) <— (NullPointerException,/,S) NCALL (E[null./],},S) — (NullPointerException,/,S) NGET (E[null./ = i/] ,/,S) <— (NullPointerException,/,S) NSET (E [cast f Zoc],/,S> <— (ClassCastException,/,S) XCAST where S(Zoc) = [s.F] and s ^ f

Figure 3.2 Operational Semantics of MiniMAOo 68

As is typical in an operational semantics, I consider a subset of the expressions to be irreducible values.

The values in MiniMAOo are the locations and null. Evaluation of a well-typed MiniMAOo program will either diverge or else produce a value or an exception; this safety property is proven later.

The evaluation context rules, denoted by E, serve as implicit congruence rules and give a non-constructive definition of evaluation order. The first rule, is the base case. The next two rules require that the target of a method call be evaluated before the arguments and that the arguments are evaluated in left-to-right order.

The rule for the application form only recurses on the arguments and not on the method body expression in the fun term. Evaluation of the method body does not take place until the substitution of actuals for formais has been done by the appropriate evaluation rule. The rules E./ and cast t E are simple congruence rules. The rule for sequencing requires that the left expression in a pair be evaluated first. The last two rules require that the target object for a field update be evaluated before the new value for the field is evaluated.

The relation, <—>, describes the steps in the evaluation of a MiniMAOo program. The relation takes an expression eeë (the set of all expressions), a stack, and a store and maps this to a new expression or an exception, plus a new stack and a new store. For MiniMAOo, the evaluation relation on the stack is identity, so I leave the set Stack undefined for now; the aspect-oriented calculus will manipulate the stack for advice binding. The set Store consists of a map from locations to object records, where an object record has the form

\t.{f—* v-fe dom [fieldsOf{ £))}]. That is, an object record consists of a type and a map from the fields of that type to their values. The exceptions in MiniMAOo are elements of the set

Excep= {NullPointerException,ClassCastException}.

Evaluation of a MiniMAOo program begins with the triple consisting of the main expression of the program, an empty stack, and an empty store. The <— relation is applied repeatedly until the resulting triple is not in the domain of the relation. This terminating condition can arise either because the resulting triple contains an irreducible value or it contains an exception. If the resulting triple contains an irreducible value, then that value, interpreted in the resulting store, is the result of the program. There is no guarantee that this evaluation terminates.

I write <-—* for the reflexive, transitive closure of the •— relation. (Because of exceptions, the range of •— does not equal its domain. So to be precise, <—* is actually the relation unioned with the reflexive, transitive closure of therelation restricted to the range S x Stack x Store.)

Although suppressed in the evaluation relation, the declarations of the program are used to populate a global class table, CT, that maps class names to their declarations. 69

The •— relation is defined by a set of mutually disjoint rules. In the subsequent subsections, I briefly describe the intuition behind each of the evaluation rules, and I give a small example program and trace its evaluation.

3.1.2.1 Intuition for Evaluation Rules

The NEW rule says that an expression new c() evaluates to a fresh location, where that location maps to an object record of the appropriate type with all of its fields initialized to null. This rule also uses two auxiliary functions, which are formally defined in Figure 3.3 on the next page. The ® operator represents map update; the fieldsOf(c) function returns a map from all the fields defined in c (and its supertypes) to the types of those fields.

The CALL rule says that a method call expression, where the target is a location bound in the store, is evaluated by looking up the body of the method (using the methodBody auxiliary function) and constructing an application form with a function term, Z, (recording the formal parameters and method body) and an argument tuple (recording the actual arguments). The separate EXEC rule evaluates this application form by replacing this and the formal parameters in the body with the appropriate values. (The notation e\e'! var\ denotes the standard capture-avoiding substitution of e' for var in e.) The rule, NCALL, says that if the target value of a method call expression is null, then the result of evaluation is a NullPointerException. (The evaluation rules which result in exceptions are grouped together at the bottom of Figure 3.2 on page 67.)

The GET and SET rules both lookup the object record for the target location in the store. The GET rule then looks up the value of the named field. The SET rule, on the other hand, updates the store with a new object record that is identical to the original object record except that the value of the named field is replaced with the new value. (This rule takes advantage of the definition of ®, which lets the right-hand argument replace bindings in the left-hand map.) The NGET and NSET rules handle the cases where the target value is null.

Three different rules deal with type casts. The CAST rule handles valid casts of non-null values. A cast is valid at evaluation time if the target type of the cast is a supertype of the actual type of the value. Figure 3.4 on page 71 gives the subtyping relation for MiniMAOo. The relation is just the reflexive, transitive closure of the syntactic extends relation. The NCAST rule handles casts of null. For both CAST and NCAST, the result of evaluation is just the value within the cast expression. The XCAST rule handles invalid casts of non-null values; in this case, the result of evaluation is a ClassCastException.

Finally, the SKIP rule says that a sequence expression, where the first expression is already reduced to a value, is evaluated to just the second expression. 70

Map update:

ffi : S" (C> >— ¥) x ( — ¥) —• 2? ( >-» *P), polymorphic in sets 0 and ¥

A©(—« y/) = {(p' >-> if/' -{(p' + (f> A A{' =

Field lookup:

CT[c) = class c extends d { t\ j]; tn /„; meth* } fieldsOf(d) - F' fleldsOf (Object) = 0 fieldsOfic) = {ft — tj • i E u F'

Method lookup:

CT[c) = class c extends d {field* meth\... methp }

3 i e {l..p} • methi = tm(t\ vari,...,tn varn ) { e } T = c x ti* ...xtn t

methodBody{c,m) =fun m (this, var\,...,varn).e:j

CT{c) = class c extends cZ {/zeZd* methi... methp }

3Z e {l..p} • methi — t m(t\ var\,...,tn varn ) { e } methodBodyid, m) = Z

methodBodyic, m) = Z

Method type lookup:

CT(c) = class c extends d {field* meth\... methp } 3Z e {l..p} • methi = t mi t,\ var\,...,tn var„ ) { e }

methodType(c, m) = t\ x... x tn — f

CT(c) = class c extends d {field* methi • • • methp }

3i e {l..p} • mefZz, = t m(ti var\ tn varn ) { e } methodType{d, m) = T

methodType{c, m) = r

Valid method overriding:

CT(d) = class d extends d' {/zeZd* mefZzi... methp }

3Z e {l..p} • methi -tm(ti vari,...,tn varn ) { e } override{m,d',T) override {m,d,r)

methodType(d, m) = ti* ...xtn t

override{m,d, ti x ... x tn — t) override[m,Object, x... x tn —« t)

Valid class:

CT{c) = class c extends d { ... }

isClass{c) isClass (Object)

Figure 3.3 Auxiliary Functions for MiniMAOo 71

t =4. s s^u CT(c) = class c extends d [ ... } M f t^u c=4d

Figure 3.4 Subtyping in MiniMAOo

3.1.2.2 Sample Evaluation

In this section I illustrate several of the evaluation rules with an example. Figure 3.5 on the following page gives the example program, which models the natural numbers. The program uses two classes: a general natural number class, Natural, and a special class to model Zero.

The figure includes javadoc-style comments describing all the methods, though a couple of these warrant further explanation.

— The Zero class overrides the pred method to just return this, because zero is considered to be its own

predecessor in this model of the natural numbers.

— The add method in Natural calculates the sum by adding the predecessor of the current number and

the successor of the argument (since t + n = [t -1) + [n +1)). The Zero class overrides the add method

to just return the argument, so the addition terminates.

The interpretation of instances of these classes is that the value of an instance of Zero is 0, and the value of an instance of Natural is 1 plus the value of its predecessor.

The last line in the sample program uses this model of the natural numbers to calculate 1 + 2. The listing below traces the evaluation of this expression in MiniMAOo. The current redex—the term to be evaluated next—is italicized at each stage. I omit type information on fun terms, because it is not used by the evaluation rules.

(new Zero().succ().add(new Zero().succ().succ()),/,0)

<—• (Ioc0.succ().add(new Zero().succ().succ()),/,So) (NEW)

where SQ = {locO — [Zero, {pred — null}]}

((fun succ(this).new Natural().setPred(this) (7ocOJJ.add(new Zero().succ().succ()),/,So) (CALL)

(new Natural().setPred(locO).add(new Zero().succ().succ()),/, So) (EXEC)

— (loci.setPred(locO).add(new Zero().succ().succ()),/,Si) (NEW)

locO — [Zero.{pred — null}], where Si = • loci — [Natural. {pred — null}] 72

class Natural extends Object { /*# Stores the predecessor o/this. */ Natural pred;

/** Initializes the predecessor o/this. */ Natural setPred(Natural pred) { this.pred = pred; this }

I** Returns the predecessor of this. */ Natural pred() { this.pred }

/** Returns the successor of this. */ Natural succQ { new Natural().setPred(this) }

/** Returns the sum o/this and n. */ Natural add(Natural n) { this.pred().add(n.succQ) }

class Zero extends Natural { Natural pred() { this }

Natural add(Natural n) { n } } new ZeroQ.succQ.add(new ZeroQ.succQ.succQ) //1 +2

Figure 3.5 Sample MiniMAOo Program 73

(Cfun setPred(this,pred).(this.pred = pred);this (loc1,locO)) ,add(new Zero().succ().succ()),/,Si}

(CALL)

({(loci.pred = locO); loci ).add(new Zero().succ().succQ),/,Si) (EXEC)

((locO; loc 7y).add(new Zero().succ().succ()),/, S2) (SET)

locO — [Zero.{pred —null}], where S2 = < loci — [Natural. {pred — locO}]

(loci ,add(new Zerof).succQ.succQ), /, % ) (SKIP)

(loci .add(loc2.succ().succ()),J, S3) (NEW)

locO — [Zero, {pred — null}],

where S3 = < loci — [Natural, {pred —locO}],

loc2 — [Zero, {pred — null}] (loci ,add(( fun succ(this).new Natural().setPred(this) f/oc2jJ.succQ),/,S3) (CALL)

(loci ,add(new A/atura/f/).setPred(loc2).succ()),/,S3) (EXEC)

(\oc1 ,add(loc3.setPred(loc2) .succQ), J, S4) (NEW)

locO — [Zero, {pred —null}],

loci — [Natural. {pred — locO}], where S4 - < loc2 — [Zero, {pred — null}],

loc3 — [Natural, {pred — null}]

(loci ,add(ffun setPred(this,pred).(this.pred = pred);this (loc3,loc2)).succQ),1,84) (CALL)

(loci .add(((loc3.pred = loc2); loc3).succQ),7,84) (EXEC)

(loci ,add(f/oc2; loc3).succQ),J, S5) (SET)

locO — [Zero, {pred — null}],

loci — [Natural.{pred — locO}], where S5 = < loc2 — [Zero.{pred — null}],

loc3 — [Natural, {pred — loc2}] (loci .add(/oc3.succfj),/,S5) (SKIP)

(loci ,add((fun succ{this).new Natural().setPred(this) (loc3))),J,S5) (CALL)

(loc! ,add(new Natural().setPred(\oc3)),J,Ss) (EXEC) 74

< loci.add(loc4.setPred(loc3)),J,Ss) (NEW)

locO — [Zero, {pred — null}],

loti — [Natural. {pred — locO}],

where % = { loc2 — [Zero, {pred null}],

loc3 — [Natural.{pred — loc2}],

loc4 — [Natural. {pred — null}]

(loci .add((fun setPred(this,pred).(this.pred = pred);this (loc4,loc3))),J,S§) (CALL)

(loci .add((loc4.pred = loc3); loc4),/,SE) (EXEC)

(loci .add(/oc3; loc4),J,Sj) (SET)

locO — [Zero.{pred — null}],

loci — [Natural.{pred — locO}],

where S7 = loc2 — [Zero.{pred — null}],

loc3 — [Natural. {pred — loc2}],

loc4 — [Natural, {pred — loc3}]

(loci ,add(loc4),J,S7) (SKIP)

((fun add{this/n).this.pred().add(n.succ) (loc1,loc4)),J,S^ (CALL)

(loci .pred ().add(\oc4.succQ), J, S7) (EXEC)

((fun pred(this).this.pred (loc I/)J.add(loc4.succ()),S7) (CALL)

(loc I .prec/.add(loc4.succ()), J, S7} (EXEC)

(\oc0.add(loc4.succ()),J,S7) (GET)

(loc0.add(ffun succ{this).new Natural().setPred(this) (loc4))),J,S7) (CALL)

(loc0.add(r>ew Natural().setPred(\oc4)),J,S7) (EXEC)

(locO.add(loc5.setPred(loc4 )),J,Sfi) (NEW)

locO — [Zero.{pred — null}],

loti — [Natural, {pred — locO}],

loc2 — [Zero, {pred — null}], where Sg = < loc3 — [Natural. {pred — loc2}],

loc4 — [Natural. {pred — loc3}],

loc5 — [Natural, {pred — null}]

(loc0.add((Yun setPred(this,pred).(this.pred = pred);this (loc5,loc4))),J,SB} (CALL) 75

— (locO.add((loc5.pred = loc4); locSX/.Sg) (EXEC)

— (locO.add(loc4; loc5),J,Sg) (SET)

locO — [Zero, {pred — null}],

loci — [Natural. {pred — locO}],

loc2 — [Zero, {pred — null}], where Sg = < • loc3 — [Natural, [pred — loc2}],

loc4 — [Natural. {pred — loc3}[,

loc5 — [Natural. {pred — loc4}[

•— (locO.add(loc5), J,Sg) (SKIP)

^ ((fun add{this,n).n (Ioc0,loc5)) ,J,Sg) (CALL)

-

To interpret this result, we count the predecessors of loc5 in Sg. From loc5, we must follow the pred field three times (first to loc4 then to loc3 then to loc2) to arrive at an instance of Zero. Thus, we see that 1 + 2 = 3.

3.1.3 Static Semantics of MiniMAOo

Figure 3.6 on the next page gives the static semantics for MiniMAOo- To avoid overburdening the typing rules, I make the following simplifying assumptions:

— All declared classes in a program have unique names.

— The extends relation on classes, generated by the declarations in a program, is acyclic. (Formally,

t=4u/\u^ t => t - u.)

— Field and method names are unique within a single declaration.

The typing rules for expressions use a simple type environment, F. The type environment F is a finite partial map from Vt^is to 3~, where ï%ls = Y u {this} and ST is the set of all types. Unlike the expression typing rules, the typing rules for programs, classes, and methods do not rely on a type environment.

The static semantics is standard, but a brief explanation of the typing rules is warranted.

The program typing rule, T-PROG, says that a program is well typed if all of its declarations are well typed and if its main expression is well typed in the empty type environment. (The effect of the declarations is implicit in the expression's typing through the global class table, for example see rule T-NEW.)

A class declaration is well typed, according to T-CLASS, if the declaration does not shadow any of its superclass fields; if its declared superclass is, in fact, a class; and if its methods are all well typed. 76

Program typing:

T-PROG Vz G {!..«}• h decli OK 0 h e: f

h decl i... decln e OK

Class typing:

T-CLASS Vz e {1..n}- fi t dom{fieldsOf {d)) isClass(d) V j G • h methj OK in c

h class c extends d { t\ fi; ...; /„; methi... methp } OK

Method typing:

T-MET

mri : ti,...,varn: ?n,this:ch e:u t

CT{c) = class c extends d { ... } override{m, d,ti x... x tn — t)

h t m(ti vari,..., tn varn ) { e } OK in c

Expression typing:

T-NEW T-OBJ T-VAR T-Loc T-NULL c G dom{CT) T{var) = t T{loc) - t

T (- new c() : c T h new ObjectO : Object r h var: t F h loc: t F H null : t

T-CALL F h eo : £q \/ie{l..n}-Th ei'.Ui

methodType(tQ, m) = ti x ... x tn t Vz E {!..»} • w,- =

T t- eo.m( ei,...,en):t

T-EXEC T, vara: to,...,var„ : tn \- e:s s^t T-GET

Vz G {0..«} -T h ei : Ui Vz G {0..n] • wz- 4 f; t = tgx ...xtn t T h e : s fieldsOf( s)(/) = f

F h (fun m{varo,...,varn).e:T (eo,...,en)):t F h e.f: t

T-SET r h e, : u fieldsOf{u){f) = t T-CAST T-SEQ F h 62 : s s ^ f FI- e:s FI- ei : s F H 62 : t

F h 6!./ = e2 :s F h cast t e:t F h ei; 62: ^

Figure 3.6 Static Semantics of MiniMAOo 77

Rule T-MET says that a method declaration is well typed within a class c if its method body is well typed.

That is, the type of its method body is a subtype of the declared return type, assuming that the formal parameters have their declared types and this has type c. The last hypothesis of T-MET uses the auxiliary function override (defined in Figure 3.3 on page 70) to require that either the method is fresh (i.e., no method of the same name exists in a superclass) or the method is a valid override—it has the same type as the overridden superclass method. This definition precludes static overloading.

The expression typing rules are mostly straightforward. Instead of a separate subsumption rule as is sometimes used, subtyping is handled directly in the appropriate rules (T-CALL, T-EXEC, and T-SET). The

T-NEW, T-OBJ, and T-VAR rules are obvious. The T-Loc rule is used in the meta-theory, where the domain of the type environment is extended to include locations. The T-NULL rule says that null can be treated as having any type.

The T-CALL rule uses the type of the target object expression to look up the method type. The rule checks that all argument expressions are subtypes of the formal parameter types. The type of the entire call expression is the declared return type of the method.

The T-EXEC rule is only necessary for the subject-reduction proof. The fun application form can only appear during evaluation; it cannot be used statically. The rule uses the formal parameter types to type the body expression. It also ensures that the actual arguments are subtypes of the formal parameter types.

The T-GET and T-SET rules use the type of the target object expression to look up the field type. For T-GET, the field type is the type of the whole expression. For field update, T-SET requires that the right-hand expression, giving the new value of the field, be a subtype of the field type. The type of the right-hand expression is also the type of the whole update expression.

I choose to use a single rule, T-CAST, for typing casts in MiniMAOo. This is more permissive than Java, which disallows casting an expression to an unrelated type. As pointed out by Igarashi et al. [73], we need to allow such "stupid casts" between unrelated types to achieve a proof of subject reduction for a small-step semantics. This is because an upcast followed by a downcast can reduce to a stupid cast. Igarashi et al. [73] introduce a technique of splitting the casting rule into three rules: one for downcasts, one for upcasts, and one for stupid casts. The stupid cast rule allows for a subject reduction proof while still matching the typing rules of Java: a Featherweight Java program is a well-typed Java program if its typing derivation does not include a stupid cast. The three cast typing rules of Featherweight Java also allow a strong safety property: for a program that can be typed without downcasts or stupid casts, progress is always possible. In my terminology, they show that evaluation cannot result in a ClassCastException. (Featherweight Java is a functional calculus and does not include a null value. Hence, NullPointerExceptions are not an issue there.) I choose to use the simpler 78 single cast rule, since the precise correspondence to Java's cast typing rules is not needed for my work and a type safety theorem that admits exceptions is sufficiently strong.

Finally, the T-SEQ rule simply requires both expressions in a sequence to be well typed and gives the sequence the type of the second expression.

3.1.4 Meta-theory of MiniMAOo

The key property of MiniMAOo is that it is type safe: a well-typed MiniMAOo program either converges to a value or exception, or else it diverges. I prove this using the usual subject reduction and progress theorems.

The proofs closely follow those of Flatt et al. [61].

Before stating and proving a subject reduction theorem, we first need a notion of consistency between a type environment and a store [58,61]. For the meta-theory, the type environment maps variables and store locations to types, F : %is u i?) —• 5~.

I 1 Definition 3.1 (Environment-Store Consistency). A type environment F and a store S are consistent, and

we write T » S,if all of the following are satisfied:2

1. \/loceS?-S{loc) = [t.F] ==>

(a) F (Zoc) = t and

(b) dom(F) - dom[fieldsOf{t)) and

(c) rng{F) ç dom{S) u {null} and

(d) V/ e dom(F) • (F (/) = loc' and fieldsOf( t)(/) = u and S (loc?) = [ t'.F'] => t' =4 u)

2. VZoc E if • (Zoc e dom (F) => loce dom{S))

3. dom{S) ç dom(Y) I i

The following standard substitution lemma will also be useful.

I I Lemma 3.2 (Substitution). IfT, var\ : t\,...,varn :tn\- e:t andVi e {\..n} • F h e; : s; where si ^ f; then

F h e\e\! var\ e„l var„\ : s for some s =4 t.

Proof To simplify the notation, let F' = F, van '• t\,...,varn : tn and write for\e\! var\,...,enl varn\.

The proof proceeds by structural induction on the derivation of F h e: t and by cases based on the last step

2Using an implication in part 2 of this definition allows the type environment to give types to global constants should one wish to add basic types to the calculus. 79 in that derivation. The base cases are T-NEW, T-OBJ, T-NULL, T-LOC, and T-VAR. The first four of these cases are trivial: e has no variables and s= t.

In the T-VAR base case, e = var, and there are two subcases. If var € \vari,...,var,,} then V'{var) =

T{var) - t and the claim holds. Otherwise, without loss of generality, let var = var\. Then e\ë!mr\ = e\ and, by the assumptions of the lemma, r h e\ël mr[ : si and si ^ t\ - t.

The remaining cases cover the induction step. The induction hypothesis is that the claim of the lemma holds for all sub-derivations of the derivation being considered.

Case 1—T-CALL. Here e = e'Q. m{ e\,... ,e'f) ). The last type derivation step has the following form:

r'b e'0:u'0 Vz e {l..p} - T' h e^ : M-

methodType(u'0,m) = «1 x... xup — t Vz e {l..p} • u't =4 ui

T'he:t

Let e'! = e'^ë/vïïrl for i e {0..p}, then elëlvâr\ = e'^.m{ e'[,...,e"p ).

We show that T h e\ël var\ : t by T-CALL. By the induction hypothesis, F h e," : u(", where Mq u'{).

And methodType{UQ, m) = methodType{u'0, m) by the definitions of methodType and override. Also by the induction hypothesis Vz e \l..p\ • F h e": u'! and u" ^ u'j. Finally, Vz £ {l..p} • u'! =4 u j by transitivity and thus the claim holds.

Case2—T-EXEC. Here e = ( fun m(var'0,...,var'p}.e' :T ( e'0,...,e'p ) ), where T = u'Qx... xu'p — t. The last derivation step is:

J J T,var 0:u'0,...,vat p:u'p)r e':s' s'=4 t

Vz £ {0..P} -T I- e- : Ui Vz £ \0..p} • Ui -=4 u\ T = MQX ... xu'p — t

F'he:f

As in the preceding case, let e" = e'^ëlvïïrl for i e {0..p}. Also let e" - e'\e! var\, then

J e\elmr\ - (fun m{vai Q,...,var'p).e":t {eQ,...,ep ) ).

By T-EXEC, the induction hypothesis, and transitivity of subtyping, F h e\ëI var\ : t. 80

Case3—T-GET. Here e = e'.f. The last derivation step is:

F' h e' : u fieldsOf (u)(f) = t

r' h e'.f:t

Now e\ê! var\ = e'\èl var\.f. By the induction hypothesis, F h e'iël var\ : u' where u! 4 u. By the definition of fieldsOf and by the first hypothesis of T-CLASS, fieldsOf [u'){f) = fieldsOf(u)[f) = t. Therefore F H elê/lwt : t and the claim holds.

Case4—T-SET. Here e = [e[.f = e'2) and the last step in the type derivation is:

T'\-e[: u\ fieldsOf (u[) [f) = u F' h e'2 : t t =4u

F' h e'^.f = e'2'. t

Now e$ëlvâr\ - {e'^ê/vârl.f = e'2lëlmrl). By the induction hypothesis F h e'l\êl'vïïf\ : u", u'[ ^ u'v F h e'2iëlvârl : t', t' =4 t. By definition of fieldsOf and by the first hypothesis of T-CLASS, we have

fieldsOf [u") (/) = fieldsOf (u\) (/) = u.

By transitivity t' 4 u. Therefore, F h e\ël uar\ : t', where t' =4 t and the claim holds.

Case 5—T-CAST. In this case, e = cast t e'. Here the last derivation step is:

F'he:s

r' h cast t e' : t

By the induction hypothesis, F h e'\èll>âf\ : s1, and so F h e\èlwr\ : t by T-CAST.

Case 6—T-SEQ. In this case e= e'x; e'2 and the last step in the type derivation is:

T' h e\ : s r'\-e'2:t

r' h e[; e'2:t

Now e\ëlvâr\ = e'jlël varl; e'2\e\ var\. By the induction hypothesis, F h e\ \ël var\: s', F h e'2\ëlUâf\ : t',

and t' =4 t. Therefore, F h e\èlwr\ : t', t' ^ t, and the claim holds.

Thus, for all possible derivations of F' h e: f we see that F h e\ël var\ : t' for some t' =4 t. • 81

We will also need four other standard lemmas: the first pair let us introduce fresh references into, and remove unused references from, the domain of the type environment; the second pair of lemmas let us replace subderivations within typing derivations, with or without subtyping. These lemmas are useful when handling reductions within evaluation contexts.

I 1 Lemma 3.3 (Environment Extension). IfT\-e:t and at dom(T), thenT,a:t' h e: t.

Proof. The proof is by a straightforward structural induction on the derivation of F h e: t.

For the base case, the last step in the derivation is T-NEW, T-OBJ, T-NULL, T-VAR, or T-Loc. In the first

three cases, the type environment does not appear in the hypotheses of the judgment, so the claim holds.

For the T-VAR case, e ~ var and Y (var) = t. But a t dom(T), so var # a. Therefore (F, a : t') {var) = t and the

claim holds for this case. The T-Loc case is similar.

The remaining typing rules cover the induction step. By the induction hypothesis, changing the type

environment to T,a: t' does not change the types assigned by any hypotheses. Therefore, the types assigned

by each rule are also unchanged and the claim holds. •

Lemma 3.4 (Environment Contraction). If I,a: t' e:t and a is not free in e, thenT\- e: t.

Proof The proof is by a straightforward structural induction on the derivation of T, a : t' h e : t.

For the base case, the last step in the derivation is T-NEW, T-OBJ, T-NULL, T-VAR, or T-Loc. In the first

three cases, the type environment does not appear in the hypotheses of the judgment, so the claim holds.

For the T-VAR case, e = var and [T,a: t') (var) = t. But a is not free in e, so var # a. Therefore F (var) = t

and the claim holds for this case. The T-Loc case is similar.

The remaining typing rules cover the induction step. By the induction hypothesis, changing the type

environment to F does not change the types assigned by any hypotheses. Therefore, the types assigned by

each rule are also unchanged and the claim holds. • i I l 1 Lemma 3.5 (Replacement). IfT h E[e] : t, F h e: t', andYY- e': t', then F hE[e'] : t.

Proof. By examining the evaluation context rules and corresponding typing rules, we see that r h e: t' must

be a sub-derivation of F h E[e] : t. Now the typing derivation for F h E[e'l : t" must have the same shape as 82

that for Eie] : t, except for the sub-derivation for The': t'. However, because this sub-derivation yields the

same type as the sub-derivation it replaces, it must be the case that t" - t. • I i

I I Lemma 3.6 (Replacement with Subtyping). If Y b E[e] : t, Y h e: u, and Y (- e' : u' where u' =4 u, then

Y \- E[e'j : t' where t'^ t.

Proof The proof is by induction on the size of the evaluation context E, where the size is the number of

recursive applications of the syntactic rules necessary to build E. In the base case, E has size zero, E = -,

and t' = u' =4 u = t.

For the induction step we divide the evaluation context into two parts so that E[-] = E1E2ML where

E2 has size one. The induction hypothesis is that the claim of the lemma holds for all evaluation contexts

smaller than the one considered in the induction step. We use a case analysis on the rule used to generate

E2. In each case we show that F h E2 [e] : s implies that F h E2 [e'\ : s', for some s' 4 s, and therefore the claim

holds by the induction hypothesis.

Case 1 —E2 = -.m( e\,...,e n). The last step in the type derivation for E2 |E| must be T- CALL:

F h e: m Vie {l..n}-ri-e;:Mj methodType{u,m) = s\t ...xsn^ s Vi e {!..«} • w, =<: s*

FhE2le]:s

By the definitions of override and methodType, methodType(u!, m) = methodType{u, m), so T-CALL gives

T I- E2 [e'] : s.

Case2—E2 = VQ.m( v\,...,vp-\,-,ep+\,en) where p e {l..n|. The last step in the type derivation for E2 [e\

must be T-CALL:

F I- i/o : MO Vie{l..(p-l)}-rb Y\-e:u Vie {{p+ -Y I- e,- : Ui

methodType{uo,m) = s\* ...xsn^ s Vi e \\..n\\ {p} • ui =4 si u^,sp

rbE2[el:s

Now u! =4 u =4 sp, so by T-CALL r h tzie'] : s.

Case 3—E2 -(I ( VQ,...,Vp-\,-,ep+i,en) ) where pe |0..n|. The last step in the type derivation for E2\e] 83 must be T-EXEC:

T, varo : so,...,var n : sn h e" : u" u" =4 s

Vz e {0..(p-1)} -T h vi : m The: M VZ e {(p + l)..ra} - T h e,- : w,-

Vz E {0..n} \ {p}-Ui =4 $i u=4sp

THE2 [e]:s

where I = fun m(var0,...,varn).e" :(sqx... xs„ — s). Now m' =<: u =4 sp, so by T-EXEC T H E2[E'l :s.

Case 4—E2 - The last step in the type derivation for E2 lei must be T-GET:

F h e: u fieldsOf (u)(/) = s

T h E2 [e] : s

By the first hypothesis of T-CLASS and the definition of field lookup, fieldsOf {u')(/) = fieldsOf {u)(/). Thus, by T-GET, E h E2 [e'] : s.

Case 5—E2 = cast s The last step in the type derivation for E2 [e] must be T-CAST:

TI- e:u

T I- E2[e] : s

Because T h e' : u', T I- E2 [e'l : s by T-CAST.

Case 6—E2 = e". The last step in the type derivation for E2\e\ must be T-SEQ:

r h E2 [e] :s

Thus, also by T-SEQ, T h E2le'] : s.

Case 7—E2 = (-./ = e"). The last step in the type derivation for E2Ïe] must be T-SET:

T I- e:u fieldsOf (w)(/) = u" V h e" : s s 4 u"

T I— E2 [e] : s

As in Case 4, fieldsOf\u'){f) - fieldsOf(u){f). Thus, by T-SET, E h E2\e'\ : s. 84

Case 8—E2 = (I/O./ = -). The last step in the type derivation for Eg [E] must be T-SET, letting s= u:

T I- i/o : MO fieldsOf (MO) (/) = u" The: u u =4 u"

FhE2[e]:s

Now u' =4 u ^4 u", so let s' = u' and F I- E2 le']: s'. •

Theorem 3.7 (Subject Reduction). Given a well typed MiniMAOo program, for an expression e, a stack J, a storeS, and a type environment T consistent with S, ifT\- e:t and(e,],S) —- (e',J',S'}, then there exist T' and t' such that r' = S',F'he': t', and t' =4 t.

Proof The proof is by cases on the reduction step applied. Based on the reduction step we can construct a

F' consistent with S' such that the claim is satisfied.

Case 1—NEW. In this case e = E[new c()], e' = E[Zoc], loct dom(S), and S' = S®{loc— [c.F]) where F -

{/—null-/G dom(fieldsOf{c))}.

Let r' = T, loc-.c.

We now show that F' = S'. Because loc € dom{S), (F = S) => loc t dom{T) by part 2 of Definition 3.1

(Environment-Store Consistency) on page 78. Thus part 1 of the definition for F' ~ S' holds for all lod e ££, loc1 ^ loc. Now S'(loc) = [c.F], F'(Zoc) = c, dom{F) - dom (fieldsOf ( c)), rng{F) = {null} G dom(S) u {null}, and 1(d) holds vacuously. So part 1 of F' = S' holds. Parts 2 and 3 hold because T « S, loc G dom (F'), and loce dom{S').

We now show that F' h E[Zoc] : t. By Lemma 3.3 (Environment Extension) on page 81 and loct dom(T), we have F' E[new c()[ : t. Now F' (- new c() : c and F' h loc: c, so by Lemma 3.5 (Replacement) on page 81,

T' h E[/oc] : t.

Case 2—CALL. Here e = E[loc.m{ v\,...,vn )], e' = E[( fun m(th\s,vari,...,varn).e" : t ( loc, v\,...,vn ) )]

(where S(loc) = [u.F], methodBodyiu, m) -fun m(this, var\,...,varn).e" :t, andr = u' x t\* ...xtn-* um), and S' = S.

Let r' = r.

Clearly F' = S'.

We now show that F h e': f. F h e:? implies that loc.m{ v\,...,vn) and all its subterms are well typed in F.

By part 1(a) of T = S, F h Zoc: M. By the definition of methodBody, u =4 Let F I- vi : M,- for all i G {l..n} and let 85

T h loc.m( v\ ,...,vn):tm. This last judgment must be by T-CALL with methodType{u, m) = tix ... x — tm where Vi e {l..n} • w,- 4 t;.

By the definition of methodType, rules T-CLASS and T-MET, and the definition of override, we have

(var\ : t\,...,varn : f«,this: u') h e" : u'm where um 4 u'm - tm. By Lemma 3.3 (Environment Extension) on page 81 (and appropriate alpha conversion of free variables in e"), F, var\ : t\,...,varn : this: u' h e" : u'm.

So

r.this: u',var\ : ti,...,varn: tn I- e" : u'm u'm=4tm

Y\-loc:u Vi e{\..ri\-T\-Vi'.ui

u =4 u' Vi e {l..n} - Ui tf T = u' x t\ x... x tn — tm

T H (fun m(this, van.....var n).e" : T ( loc, v\ vn))\tm

Finally, Lemma 3.6 (Replacement with Subtyping) on page 82 gives TI- e':t.

Case 3—EXEC. Here e = E[( fun m{varo,.. ,,varn).e" :T ( VQ,...,V„ ) )] (where T = to x... x tn —- u), e' =

E[e"\vol varo,...,vnl varn\], andS' = S.

Let T' = T.

Clearly T' = S'.

We now show that T h e'\t' for some t' 4 t. T h e:t implies that (fun m{varo,... ,varn).e" :t (vo,...,vn)) and all its subterms are well typed in Y. Let Y h (fun m(varo varn).e" :T (VQ,...,I>n)):u. This must be by T-EXEC:

T, varo: to,• --,varn: tn h e": u' u' u

Vi e \0..n} -T h v, : t\ Vi e {0..n} • t\ 4 ti

i - to x... x tn — u

F H (fun m(varo,...,varn).e" :T ( VO ,...,V„)):U

By Lemma 3.2 (Substitution) on page 78, Y h e"\v§! varo,...,vnl varn\:u" for some u" =4 u! =4u. Finally,

by Lemma 3.6 (Replacement with Subtyping) on page 82 T h e' : t' for some t' 4 t.

Case 4—GET. In this case e = E[loc.f], e' = El /'I (where S{loc) = \u.F] and F(f ) - v), and S' = S.

Let F' = F.

Clearly F' ~ S'.

We now show that Y E[ v] : t' for some t' =4 t. Let F h loc.f : s. The last step in this derivation must

be T-GET. By the first hypothesis of T-GET, by T-Loc, and by Y ~ S, we have F(Zoc) = u. By the second

hypothesis of T-GET, fieldsOf {U) (/) = s. Also by F = S, S(i>) = \u' .F'\ where u1 =4 s and F(z/) = u'. 86

Thus, T h v.u1 and, by Lemma 3.6 (Replacement with Subtyping) on page 82, F h El u\ : t' where t' ^ I.

Case5—SET. In this case e = E[loc.f = v\, e' = t\v], and S' = S ® (loc" [u. F® (/ i/)]), where S(/oc) =

[u.F].

Let r' = F.

We now show that F a s'. S' only changes in its mapping for loc. To see that part 1 of the consistency definition holds, note that S'(loc) - [u.F® {f—* f)]. For part 1(a) Y (loc) = u, since S{loc) = \u.F\ and F = S.

For part 1(b) dom{F ® (/-» i/)) = dom[fieldsOf{u)), since loc.f = vis well typed.

For part 1(c), rng[F ® (/ — ;;)) = rng(F) u {v\. Now since loc.f = v is well typed, we have v e dom[Y) or v = null. In the former case, by Y ~ S, we have vedom(S). v e dom[S) implies v e dom(S'). So in either case rng{F) u M ç dom{S') u {null}.

Part 1(d) holds for all /' e dom[F), f # /. Part 1(d) holds vacuously for / if v = null. Otherwise,

(F ® (/ >-• I/)) (/) = v and, by T- SET and T- Loc, T( v) 4 fieldsOf( u)(/).

Parts 2 and 3 hold since dom{S') = dom(S).

To see that T h El v] : t, let F h loc.f = v : s. By T-SET, R h v : S and by Lemma 3.5 (Replacement) on page 81, FhElv]:?.

Case6—CAST. Here e = Elcasl t" loc}, e' — Et/oc], S' = S, S{loc) - [M.F], and u =4 t".

Let F' = F.

Clearly F' = S'.

To see that F I- E [loc] : t' for some t' ^ t, note that Y {loc) -u by consistency of F with S. Thus F h loc: u.

By T-CAST, F I- cast t" loc: t". Since u =4 t", by Lemma 3.6 (Replacement with Subtyping) on page 82 we have F h El/oc] : t' where ( ' =<: t.

Case 7—NCAST. Here e = E[cast t" null], e' = E[null], S' = S.

Let F' = F.

Clearly F' ~ S'.

Now F h cast t" null : t". By T-NULL, F H null : t". So by Lemma 3.5 (Replacement) on page 81, F h

Elnull] : t.

Case 8—SKIP. Here e-Elv; E"], e' — E[e"], S' = S.

Let F' = F. 87

Clearly r' = S'.

Since T I-E[v; e"\ : t, let F I- v; e" : t". This derivation must be by T-SEQ, the second hypothesis of which says F he": t". By Lemma 3.5 (Replacement) on page 81, F h E|e"] : t.

The remaining evaluation rules reduce e to an error condition and are not applicable to the theorem. •

Theorem 3.8 (Progress). For an expression e, a stack J, a storeS, and a type environment Y consistent with

S, if Y h e : t then either:

— e - loc and loce dom{S),

— e= null, or

— one of the following hold:

- (e,J,S) (NullPointerException,J',S')

- {e,J,S> <-» (ClassCastException,j',S')

Proof. If e •= loc, then F h loc: t by T-Loc. This means that loc e dom{Y) and, since Y » S we have loc e

dom{S).

If e - null, then the claim holds.

Finally, when e is not a value we consider cases based on the current redex of e. Cases where the redex

matches NEW, EXEC, NCAST, SKIP, NCALL, NGET, and NSET are trivial. For the remaining cases we must show that the side conditions of the appropriate evaluation rules are satisfied.

Case I—e = E[loc.m( vi,...,vn )]. Because e is well typed, F h loc: s for some type s. Thus, loce dom{Y),

and part 2 of T ~ S implies loce dom{S). Let S{loc) - [s'.F]. Now s' = s by part 1(a) of F = S.

Because loc. m{ v\,...,v„ ) is well typed, we know by the hypotheses of T-CALL that methodType{s, m)

yields an n-arity method type. By the correspondence between the definition of methodType and that of

methodBody, it must be the case that rnethodRodyis, m) - I for some fu n term I. Thus (e, J, S> evolves by

CALL.

Case 2—e = E [loc.f]. As in the preceding case, e well typed implies S(loc) = [s.F] where Y {loc) - s. Now

loc.f well typed implies / e dom (fleldsOf{s)) by the hypotheses of T-GET. Finally, part 1(b) of F = S gives

/ e dom{F), so (e,J, S) evolves by GET. 88

Case 3—e = E [loc.f = v[. Similar to the preceding case.

Case 4—e = E[casf t' loc[. As in Case 1 on the preceding page, e well typed implies S{loc) = [s.F], where

Y{loc) = s. If s ^ t', then (e,J,S) <—

XCAST. • I I

The type safety property of MiniMAOo follows from subject reduction and progress.

I 1 Theorem 3.9 (Type Safety). Given a program P = dech... decln e, if\- P OK then either the evaluation ofe

diverges or else (e, *, 0) ^ {x, J, S> where one of the following holds for x:

— x = loc and loce dom[S),

— x null,

— x = NullPointerException, or

— x = ClassCastException

Proof. If e diverges then the claim holds. If e converges, then note that the empty environment is con­

sistent with the empty store. The proof (by induction on the number of evaluation steps) is immediate

from Theorem 3.7 (Subject Reduction) on page 84 and Theorem 3.8 (Progress) on the preceding page. •

3.2 MiniMAOi : Adding Aspects

In this section I add advice binding to MiniMAOo, producing the aspect-oriented core calculus MiniMAOi.

Continuing with the minimalist philosophy, the join point model of MiniMAOi is quite simple. The model

only includes call and execution pointcut descriptors, the parameter binding forms this, target, and args, and

the operators for pointcut union, intersection, and negation. The omission of the dynamic-context pointcut

descriptors, such as cflow, is an intentional decision. The techniques for dealing semantically with such

descriptors are well understood [157], and such dynamic-context pointcut descriptors do not substantially

affect the typing rules for aspects.

MiniMAOi accurately models AspectJ's semantics for around advice [83], in that it allows advice to change

the target object of a method call or execution before proceeding with the operation. Moreover, as in Aspect],

changing the target object at a call join point affects method selection for the call, but changing the target object

at an execution join point merely changes the self object of the already selected method. Changing the target

object is useful for such idioms as introducing proxy objects. Such proxy objects can be used in aspect-oriented 89 implementations of persistence or for redirecting method calls to remote machines. MiniMAOi does depart from AspectJ's semantics for around advice in two ways: it does not allow changing the this (i.e., the caller) object at a call join point and it uses a different form of proceed, which syntactically looks like the advised method call rather than the surrounding advice declaration as in Aspect], These differences are discussed more below.

One motivation for the design of MiniMAOi is to keep pointcut matching, advice execution, and primitive operations in the base language as separate as possible. This goal causes us to use more evaluation rules that are strictly necessary. One way to think of MiniMAOi is as an operational semantics for an aspect-oriented virtual machine, where each primitive operation may generate a join point that may trigger other rules for advice matching. My approach increases the syntactic complexity of the calculus, but I find that it actually simplifies reasoning. The approach keeps separate concepts in separate rules that can be analyzed with separate lemmas.

No previous work on formalizing the semantics of an aspect-oriented language deals with the actual

Aspect] semantics of argument binding for proceed expressions and an object-oriented base language. My calculus is motivated by the insight ofWalker et al. [156] that labeling primitive operations is a useful technique for modeling aspect-oriented languages. However, to handle the run-time changing of the target object and arguments when proceeding from advice, I replace their simple labels with more expressive join point abstractions. Also, rather than introduce these join point abstractions through a static translation from an aspect-oriented language to a core language, I generate them dynamically in the operational semantics. The extra data needed for the join point abstractions (versus the simple static labels) is more readily obtained when they are generated dynamically. (This dynamic generation is also adopted by Dantas and Walker [48].) Also, directly typing the aspect-oriented language, instead of just showing a type-safe translation to the labeled core language, seems to more clearly illustrate the issues in typing advice, though this is a matter of taste. My type system is motivated by that of Jagadeesan et al. [74]. I discuss this and other related work in more detail in

Section 3.3.

3.2.1 Syntax of MiniMAOi

Figure 3.7 on the next page gives the additional syntax for MiniMAOi. To the declarations of MiniMAOo

I add aspects, with a ranging over the set, $4, of aspect names. As for identifiers in MiniMAOo, I leave si unspecified, but for examples will draw names from the set of legal Java identifiers. For a MiniMAOi program the set of types is 5" = "tg'u.e/. An aspect declaration includes a sequence of field declarations and a sequence of advice declarations. 90

decl::-... I aspect a {field* adv* } adv.: = t around(form* ) : pcd { e }

pcd:: = ca\\( pat) | execution( pat) | aesd, the set of aspect names this(/orm) | target (form) | args(form* ) | idPat e.9, the set of identifier patterns pcd && pcd | ! pcd | pcd 11 pcd pat:: = t idPat(..)

e::-... | e.proceed(e* )

Figure 3.7 Syntax Extensions for MiniMAOi

I only include around advice in MiniMAOi. Operationally, around advice can be used to model both before and after advice. (As noted by Jagadeesan et al. [74], typing around advice is more challenging than typing before and after advice, since formal parameters in around advice appear in both co- and contravariant positions [31].)

An advice declaration in MiniMAOi consists of a return type, followed by the keyword around and a sequence of formal parameters. A pointcut description comes next. The pointcut description specifies the set of join points—the pointcut—where the advice should be executed. A join point is any point in the control flow of a program where advice may be triggered. The pointcut description for a piece of advice also specifies how the formal parameters of the advice are to be bound to the information available at a join point. The final part of an advice declaration is an expression that is the advice body.

MiniMAOi includes a limited vocabulary for pointcut descriptors. The call pointcut descriptor matches the invocation of a method whose signature matches the given pattern. I restrict method patterns to a concrete return type plus an identifier pattern that is matched against the name of the called method. I choose not to include matching against target or parameter types here because that is just syntactic sugar for the target and args pointcut descriptors.

I leave the set J? of identifier patterns underspecified. Generally, we can think of .9 as a regular expression language such that all members of Ji are elements of regular expressions in .9. For examples, I will treat -9 as the set of all legal Java identifiers, but treating the wildcard character, *, as a legal identifier character.

The execution pointcut descriptor is like the one for call, except that it matches the join point correspond­ ing to a method execution. There are two key differences between method call and method execution join points:

— at a method call join point the this object is the caller, while at a method execution join point the this

object is the callee, and 91

— a method call join point is reached before method dispatch is performed, but the corresponding method

execution join point is reached after method dispatch.

The this, target, and args pointcut descriptors correspond to the parameter-binding forms of these de­ scriptors in AspectJ; they bind the named formal parameters to the corresponding information from the join point. To simplify the operational semantics, the syntax requires a type and a formal parameter. For example, where one could write this(n) in AspectJ, one must write this(Number n) in MiniMAOi (where Number is the type of the formal parameter n in the advice declaration). This type elaboration could easily be performed automatically; including it in the syntax clarifies the formalism. Another simplification versus AspectJ is that the args pointcut descriptor in MiniMAOi binds all arguments available at the join point; that is, MiniMAOi does not include AspectJ's mechanism for binding arguments when matching methods with differing numbers of arguments. I do not include any wildcard or subtype matching for this, target, or args pointcut descriptors.

The final three pointcut descriptor forms represent pointcut negation Oped], union {pcd || pcd), and intersection {pcd && pcd). Pointcut negation only reverses the boolean (match or mismatch) value of the negated pointcut. Any parameters bound by the negated pointcut are dropped. Pointcut union and intersection are "short circuiting"; for example, if ped^ in the form pcdx 11 pcd2 matches a join point, then the bindings defined by pcd± are used and pcd2 is ignored.

MiniMAOi also includes proceed expressions, which are only valid within advice. An expression such as eo.proceed(ei,...,e„) takes a target, eg, and sequence of arguments, e\,...,en, and causes execution to continue with the code at the advised join point—either the original method or another piece of advice that

applies to the same method. As noted above, the proceed expression in MiniMAOi differs from AspectJ. In

MiniMAOi, an expression of the form eç,.proceeds ,...,en) must be such that the type of the target, ey, and the

number and types of the arguments, e\,...,en, match those of the advised methods. In AspectJ, the arguments

to proceed must match the formal parameters of the surrounding advice. This design decision matches my

intuition for how proceed should work; it has little effect on expressiveness in a language with type-safe around

advice. My design also precludes changing the this object at call join points. Such changes would only be

visible from other aspects, not the base program. Precluding these changes eliminates some possibilities for

aspect interference, a useful property for my work on aspect-oriented reasoning. I am not aware of any use

cases demonstrating a need to allow changing the this object.

3.2.2 Operational Semantics of MiniMAOi

This section gives the changes and additions to the operational semantics for MiniMAOi. Subsections

describe the stack in MiniMAOi, new expression forms introduced for the operational semantics, the new 92

J -j+J I •

i — §k, v0pt, m0pt, loptt t k = call | exec | this Vopt -v\- = m | - mopt lopt = 1 \ - t opt = T | -

Figure 3.8 Join Point Stack evaluation rules, and pointcut descriptor matching. Another subsection gives several example evaluations.

3.2.2.1 The Join Point Stack

The stack in MiniMAOi is a list of join point abstractions, each of which is a five-tuple denoted by half- moon brackets, 0...B, as shown in Figure 3.8. A join point abstraction records all the information in a join point that is needed for advice matching and advice parameter bindings, together referred to as advice binding. A join point abstraction also includes all the information necessary to proceed from advice to the original code that triggered the join point. A join point abstraction consists of the following parts (most of which are optional and are replaced with when omitted):

— a join point kind, k, indicating the primitive operation of the join point, or this to record the self object

at method or advice execution (for binding the this pointcut descriptor);

— an optional value indicating the self object at the join point, used for parameter binding by this pointcut

descriptors;

— an optional name indicating the method called or executed at the join point, used for pattern matching

in call and execution pointcut descriptors;

— an optional fun term recording the body of the method to be executed at an execution join point; and

— an optional function type indicating the type of the code under the join point (or, equivalently, the type

of a proceed expression in any advice that binds to the join point). The code under a join point is the

program code that would execute at that join point if no advice matched the join point. For example,

the code under a method execution join point is the body of the method. The function type includes

the type of the target object as the first argument type. 93

e|joinpt j(e* ) | under e | chain B,j(e* ) Ë — B + B | •

B::= [1b, loc,e, T,TJ1 b:: - (a,/3,p*) a :: = var >— loc | - fi::= var | -

b e »#, the set of advice parameter bindings

Figure 3.9 Additional Expression Forms for the Operational Semantics of Mini- MAOT

3.2.2.2 New Expression Forms

The operational semantics relies on three additional expression forms, as shown in Figure 3.9. The first, joinpt, reifies join points of a program evaluation into the expression syntax. A joinpt expression consists of a join point abstraction followed by a sequence of expressions representing the actual arguments to the code under the join point.

The second expression form that I add for the operational semantics is under. An under expression serves as a marker that the nested expression is executing under a join point; that is, a join point abstraction was pushed onto the stack before the nested expression was added to the evaluation context. When the nested expression has been evaluated to a value, then the corresponding join point abstraction can be popped from the stack. (In a calculus that included after advice, a term under v (where v is a value) could also serve as an indication that any after advice matching the stack should be triggered.)

The final additional expression form is chain. A chain expression records a list, B, of all the advice that matches at a join point, along with the join point abstraction and the original arguments to the code under the join point.

The advice list of a chain expression consists of body tuples, one per matching piece of advice. For visual clarity, I use "snake-like" brackets, [1...J1, to denote each body tuple. A body tuple is comprised of two parts: operational information and type information. The operational information includes three elements: a param­ eter binding term, b, described below; a location, loc, and an expression, e. The location is the self object; it is substituted for this when evaluating the advice body. The expression is the advice body.

The binding term, b, describes how the values of actual arguments should be substituted for formais in the advice body. This substitution is somewhat complex to account for the special binding of the this pointcut descriptor, which takes its data from the original join point, and the target and args pointcut descriptors, which 94 take their data from the invocation or proceed expression immediately preceding the evaluation of the advice body. (No previous formalization of AspectJ has faithfully modeled this binding semantics for target and args.)

I give examples of binding terms in Section 3.2.2.5.

Structurally, a binding term consists of a variable-location pair, var >—• loc, which is used for any this pointcut descriptors, followed by a non-empty sequence of variables, which represent the formais to be bound to the target object and each argument in order. The symbol is used to represent a hole in a binding term.

This might occur, for example, if a pointcut descriptor did not use this. The set of all possible binding terms is

The type information in a body tuple is contained in its last two elements. The first of these is the declared type of the advice, a function type from formal parameter types to the return type. The second type element, the last element in the body tuple, is the type of any proceed expression contained within the advice body. I include the type information in body tuples to simplify the subject-reduction proof; the type information is not needed for the evaluation rules.

3.2.2.3 Evaluation Rules for MiniMAOi

Next I give an intuitive description of the new evaluation rules in MiniMAOi. These rules are given in Figure 3.10 on the following page. The example evaluations in Section 3.2.2.5 illustrate the rules.

I add new evaluation contexts to handle the joinpt, under, and chain expressions. The semantics replaces proceed expressions with chain expressions, so I do not need an additional context for proceed.

I replace the CALL rule of MiniMAOo with a pair of rules, CALLA and CALLB described below, that introduce join points and handle proceeding from advice respectively. I replace the EXEC rule similarly. This division exposes join points for call and execution to the evaluation rules. Just as virtual dispatch is a primitive operation in a Java virtual machine, my semantics models advice binding as a primitive operation on these exposed join points. This advice binding is done by the new BIND rule. The new ADVISE rule models advice execution, and an UNDER rule helps maintain the join point stack by popping join point abstractions from the stack when appropriate.

The evaluation of a program in MiniMAOi does not begin with an empty store as in MiniMAOo. Instead, a single instance of each declared aspect is added to the store.3 The locations of these instances are recorded in the global advice table, AT, which is a set of 5-tuples. Each 5-tuple represents one piece of advice. The 5-tuple for the advice t around( t\ var tn varn ): pcd { e }, declared in aspect a, is {loc, pcd,e,(t\ X... xf„ f) ,T);

^Because of the lack of constructors, there is no obvious mechanism in MiniMAOi for initializing the state of these implicitly instantiated aspects. Section 3.4 address this issue. 95

Evaluation contexts:

E:: = ... I joinpt j(v...Ee... ) I under E | chain B,j( v...Ee... )

Evaluation relation (additional and replacement rules):

(E[loc.m{ v\,...,vn )],/,S) <-> (Eljoinpt (|call,-,/n,-,T||( loc, v\,...,vn )],J,S) CALLA

where S(loc) = {t.F], methodTypeito,m) = t\x ...xtn — t',

origType{t, m) - to, and T = to x... x tn — t' (Elchain •Jcall,-,m,-,r|)( loc, v\,...,v„)],},S)

<-* (E[( / ( loc, v\,...,vn))],J, S) CALLB where S(loc) = [t. F] and methodBodyit, m) = l

where I-fun m(varo,...,varn).e-.T

(Elchain «Jexec, v,m,l,T\i( vo,...,vn)],J,S)

•— (Elunder e\v0l var0 vnl varn\\,j+ J,S) EXECB

where / = fun m(varo,...,varn).e:T and y = flthis,

(E[null.m( v-[,...,vn )],J,S) •— (NullPointerException,/,S) NCALLA (Elchain •,flcall,—,/M, —,TD( null, v\,...,v„ )],J,S)

<—• (NullPointerException,/,S) NCALLB

(Eljoinpt j( vo,...,vn )],/,S) ^-» (Elunder chain B,j( vo,...,vn )],/ + /,S) BIND where adviceBind( j + J, S) = B

(Elchain ft_b,loc,+B,j( v0,...,v„)],/,S)

(Elunder e'\locl\h\s\\{vo,...,vn)l b\],j' + J,S) ADVISE where e' - «e»g , and j' - flthis, loc,

(Elunder v],J,S) <— (E[v],/,S) UNDER where/ = j + J', for some j

Figure 3.10 Changes to the Operational Semantics for MiniMAOi 96

CT{a) = aspect a { ... }

a 4 Object

Figure 3.11 Additional Subtyping Rule for MiniMAOi

in this 5-tuple S[loc) - {a. F] is the aspect instance for a in the initial store. For a given aspect a,every 5-tuple in AT representing advice from a has the same location. The function type T is the type of proceed expressions in e, derived from pcd. (In AspectJ, T would be redundant, because the type of proceed expressions in AspectJ

advice is derived from the advice signature. That is, T = (?i x ... x tn —• t). In MiniMAOi the type of proceed

expressions is derived from the pointcut descriptor.)

The global class table, CT, is extended in MiniMAOi to also map aspect names to the aspect declarations. I

extend the subtyping rules with a rule that all aspects are subtypes of Object, as shown in Figure 3.11. Treating

aspect instances as regular objects allows the rules for field access to be applied uniformly for aspect and

class instances. This treatment also matches the situation in AspectJ. I also extend the field lookup function, fieldsOf, with an additional rule for aspects as shown in Figure 3.12 on the following page.

Next I describe the new evaluation rules in more detail.

SPLITTING THE CALL RULE In object-oriented MiniMAOo, a method call is evaluated by applying the

CALL and EXEC rules in turn. In aspect-oriented MiniMAOi, each of these steps is broken into a series of steps.

The CALL step becomes:

— CALLA: creates a call join point

— BIND: finds matching advice

— ADVISE: evaluates each piece of advice

— CALLg : looks up method, creates an application form

A similar division of labor is used for EXEC. I next describe each of these four steps in turn.

Create a Join Point The CALLA rule says that a method call expression with a non-nul I target evaluates

to a joinpt expression where the join point abstraction carries the information about the call necessary to

bind advice and to proceed with the original call. This information is: the call kind, the method name, and a

function type, T, for the method. The function type includes a target type in the first argument position. The 97

Field lookup (additional rule):

CT(a) - aspect a { t\ /ï; tn f„; adv* }

fieldsOfla) = [f) >-» f,- • i e jl..rc}}

Original declaration lookup:

origType{t, m) - max{s e3~ • t =4 s A methodType{s,m) = methodType(t,m)}

Advice binding: adviceBind-.Stackx Store(58 x x

adviceBind[J,S) = B, where B is a smallest list satisfying

\/(loc,pcd,e,T,T')eAT-{{matchPCD{j,pcd,S) = b^±) => \[h,loc,e,T,T'JI EB)

Advice chaining:

<(e0.proceed( ei e„ )»Sj- = chain B,;'( «e0»b,j, «ei» Si ,...,«e„» ë j )

For all other expression forms, the chaining operator is just applied recursively to every subexpression. For example, the definition of the chaining operator for field set is:

<(e./=e'»gj = ((e»jjj./=«e'»j3j

Binding substitution:

eKi/o,...,!/») /(far —<• loc,fo,...,fip)\ - e\lod var\\vil vari\m^n].p.=var. where n< p

e{(vo,...,vn) / = E|F,-/ varili£{0.M].p.=vari where T-Z < p

In all other cases, binding substitution is undefined.

Figure 3.12 Auxiliary Functions for MiniMAOi Operational Semantics 98 function type is determined using a pair of auxiliary functions, methodType and origType, shown in Figure 3.12 on the previous page.

The methodType function is similar to methodBody discussed above; it searches the class table for the method declaration and returns a function type. The origType function finds the type of the "most super" class of the target type that also declares the method m. The target type included in the call join point abstraction generated by CALLA is this most super class. Using the most super class allows advice to match a call to any method in a family of overriding methods, by specifying the target type as this most super class. I discuss this a bit more when describing the target pointcut descriptor below. Finally, the arguments of the generated joinpt expression are the target location—again in the first position—and the arguments of the original call, in order.

Find Matching Advice The BIND rule is the only place in the calculus where advice binding (lookup)

occurs. This rule takes a joinpt expression and converts it to a chain expression that carries a list of all matching

advice for the join point. It also pushes the expression's join point abstraction onto the join point stack.

The rule uses the auxiliary function adviceBind to find the (possibly empty) list of advice matching the

new join point stack and store. The adviceBind function applies the matchPCD function, described in Sec­

tion 3.2.2.4, to find the matching advice in the global advice table. (I leave adviceBind underspecified. In

particular, I don't give an order for the advice in the list. For practical purposes some well-defined ordering is

needed, but any consistent ordering, such as the declaration ordering used in my examples, will suffice.)

Having found the list of matching advice, the BIND rule then constructs a new chain expression consisting

of this list of advice, the original join point abstraction, and the original arguments. The result expression is wrapped in an under expression to record that the join point abstraction must later be popped from the stack.

Evaluate Advice The ADVISE rule takes a chain expression with a non-empty list of advice and evaluates

the first piece of advice. The general procedure is to substitute for this in the advice body with the location,

loc, of the advice's aspect and substitute for the advice's formal parameters according to the binding term, b.

I describe below how the binding term is used for the substitution. However, before the substitution occurs

the rule uses the «-» ;j • auxiliary function to eliminate proceed expressions in the advice body. This "advice

chaining" function rewrites all proceed expressions, replacing them with chain expressions carrying the

remainder of the advice list B, along with the join point abstraction, j, needed to proceed to the original

operation once the advice list has been exhausted. This rewriting is like that used by lagadeesan et al. [75],

though they do not consider the target object to be one of the arguments to proceed. Advice chaining is

illustrated with an example in Section 3.2.2.5. 99

After using the advice chaining function to rewrite the advice body, the ADVISE rule uses variable substitu­

tion to bind the formal parameters of the advice to the actual arguments. It substitutes the aspect location, loc, for this and substitutes the actuals for the formais according to b. I overload notation to define this substitution for binding terms (see Figure 3.12 on page 97). The definition says that the variable in the iw— loc pair is

replaced with the location, unless there is a hole,"-", in this position of the binding term. Each element, /3,-, in

the binding term that is not a hole must be a variable. Each such variable is replaced with the corresponding

argument, f;. For example:

(x.f = y)KlocO,loc1)/(x ~ loc2, -, y>{ = (loc2.f = loci)

The x t— loc2 in the binding term does not use data from the arguments (Ioc0,loc1 ); the value locO is not

used because of the hole in the binding term; and y is replaced with loci. The type system rules out repeated

use of a variable in a binding term.

After substitution, the ADVISE rule pushes a this join point abstraction onto the stack—analogous to the self reference stored on the call stack in a Java virtual machine—and wraps the result expression in an under

expression, which records that the join point abstraction should be popped from the stack later.

Finish the Original Operation Once the list of advice has been exhausted, the result is achain expression with an empty advice list, the original join point abstraction, and a sequence of arguments. If the BIND rule

had found no advice, then the arguments will be the target and arguments from the original call. Otherwise,

the arguments will be whatever was provided by the last piece of advice. This chain expression is used by the

CALLB rule to evaluate the original call.

The CALLB rule looks up the type of the (possibly changed) target object in the store and finds the method

body in the global class table. The rule takes the method name from the join point abstraction. The result of

the rule is an application expression, just like the result of the CALL rule in MiniMAOo-

Because both the CALLA and CALLB rules use a target location for method lookup, there are corresponding

rules for null targets. These rules just map to a triple with a NullPointerException.

A GENERAL TECHNIQUE The technique used to convert the CALL rule from the MiniMAOo calculus into a

pair of rules, with intervening advice binding and execution, is general. The first rule in the new pair replaces

the original expression with a joinpt expression, ready for advice binding. The second rule in the pair takes a

chain expression, exhausted of advice, and maps it to a new expression like the result expression of the rule

from MiniMAOo- This is how the two new EXEC rules are generated. 100

The EXECA rule replaces the application expression with a joinpt expression. The join point abstraction of this expression includes the exec kind, the method name, the fun term of the application, and the type of the fun term. The abstraction also includes, in the position reserved for this objects, the value of the target object from the argument tuple, because target and this objects are the same at an execution join point. The arguments to the joinpt expression are the arguments to the original application expression.

The EXECB rule takes a chain expression that has been exhausted of its advice. It applies the fun term from the chain's join point abstraction to the argument sequence, substituting the arguments for the variables in the body of the fun term. Like ADVISE, the EXECB rule pushes a this join point abstraction onto the stack and wraps its result expression in an under expression.

It would be straightforward to add pointcut descriptors and join points for any of the primitive operations in the original calculus. One would have to generalize the data carried in the join point abstractions to accommodate additional information, but the BIND and ADVISE rules would remain unchanged. Because the call and exec join points are sufficient for my study, I choose not to include join points for the other primitive operations. To do so would just introduce additional notation and bookkeeping.

THE UNDER RULE The UNDER rule is the simplest of the new evaluation rules. It just extracts the value from the under expression and pops one join point abstraction from the stack.

3.2.2.4 Pointcut Matching

Following Wand et al. [ 157], I use a boolean algebra over binding terms to define a matchPCD function, for matching pointcut descriptors to join points. My binding terms, as described in Section 3.2.2.2 above, are somewhat more complex than theirs, since I model this, target, and args pointcut descriptors and faithfully model the semantics of proceed from AspectJ with regard to changing target objects in advice. Nevertheless, the basic technique is the same.

Figure 3.13 on the next page gives the boolean algebra. The terms of the algebra are drawn from the set

Âʱ = ÂSU {-L}, where binding terms can be thought of as "true" and _L as "false". The operators in the algebra are conjunction (A), disjunction (v), and complement (->). The complement of the complement of an element is not necessarily the original element, unless we consider all binding terms to be isomorphic; this effect of this detail on advice binding is discussed below. The binary operators are short circuiting; for example, bv r - b, ignoring the value of r. One difference in my algebra, versus Wand et al. [157], is in the conjunction of two non--L terms. My calculus must consider the bindings from both terms, because I have more than one pointcut descriptor that can bind formal parameters. Sometimes these bindings must be combined, for example when 101

Boolean algebra of bindings (adapted from Wand et al. [157]):

âë± = SS u {-L} beâë r £ 58 j_ bvr = b J_ v r= r lAr= l foA_l_ = _L bAb' = b\db'

-i± =(-,-> -ib — 1.

)oin of bindings:

(a,Po,---,Pn)u(a',Po>--->P'p) = (

where q = max(n,p), Vi e {[n+ l)..q}-(Pi = and Vi e {{p+ l)..g}- (/^. - -)

(var —* loc) u [var' -» loc') = var >— loc [var>~* loc) u - = i/sf— Zoc - u [var1 >— Zoc') = rar1 —» Zoc'

rar u var' = var var u - = var - u var1 = var' — u - = -

Figure 3.13 Boolean Algebra over Binding Terms both a target and args pointcut descriptor are used. The bindings are combined using a pointwise join (denoted

LJ) that extends the shorter binding term if the two terms do not have the same number of elements. Collisions in the join operator, where neither binding has a hole at a given position, are resolved in favor of the left-hand term; however, the typing rules for pointcut descriptors ensure that such collisions do not occur in well-typed programs.

The rules defining matchPCD in Figure 3.14 on the following page are straightforward. If the pointcut descriptor matches the join point stack, then the rules construct the appropriate binding term; otherwise they evaluate to _L. The only complications are to accommodate the multiple parameter binding forms. For example, this and target matching must be done without information on how many additional arguments might be bound by an args pointcut descriptor. Thus, the length of binding terms must be allowed to vary.

Call and Execution The call and execution rules only match if the most recent join point is of the corresponding kind and the return type and name of the method under the join point are matched by the pattern. Because these pointcut descriptors do not bind formal parameters, a match is indicated by an empty binding term.

This Two rules are used to handle this pointcut descriptors. Together, these rules find the most recent join point where the optional self-object location is provided in the join point abstraction. Once found, if the object record in that location is a subtype of the formal parameter type, then the formal named by the pointcut descriptor is mapped to the location; otherwise the result is X. 102

matchPCDdk,I_1, m,^, to*... x rp — f[I + /, cal l( u idPat(..) ),S)

(-,-> if k- call, t = u, and m e idPat {1 otherwise

x matchPCD^k.^m,^, ?o ... x tp — ti + /,execution( u idPat(..)),S)

(-,-} if fc = exec, t= u, and m E idPat {_L otherwise

I (var~ v,-) if v # null, S{v) = [s.F], and s^; t matchPCDiZAl_,,1_,,1_li) + /,this( r var),S) - < [ _L otherwise

matchPCDiD + /,this( t var),S) = matchPCDU,this( t var),S)

<- ,var> if so = t {± otherwise

matchPCDil_J,-|) + /,target( t var),S) - matchPCDU,target( t var),S)

matchPCDi^,fox... xfp R|) + /,args( MI var\,...,un varn ),S)

vary,...,var„) if p-n and V ie {!..»} • (f,- = w,0 -L otherwise

matchPCDU, pcd | | pcd', S) - matchPCDU, pcd, S) v matchPCDU, pcd', S)

matchPCDU, pcd && pcd',S) = matchPCDU, pcd, S) A matchPCDU, pcd' ,S)

matchPCDU,! pcd, S) = matchPCDU, pcd, S)

matchPCDU, pcd, S) = ± for any case not matched by the preceding rules

Figure 3.14 Pointcut Descriptor Matching for MiniMAOi 103

Target The target pointcut descriptor is handled similarly to this, but uses the target type from the join point instead. Unlike the this pointcut descriptor, the location to be bound to the formais is not available from the join point abstraction. The location may come from a proceed expression to be evaluated later. Also unlike this, target requires an exact type match. This is necessary for static type safety, as noted by Jagadeesan et al.

[74]. If the descriptor were to match when the target type was a supertype of the parameter type, then the advice could call a method on the object bound to the formal that did not exist in the object's class. On the other hand, if the descriptor were to match when the target type was a subtype of the parameter type, then the advice could replace the target object with a supertype before proceeding to a method call. If this supertype did not declare the method, then a runtime type error would result.4 Thus, for static type safety the target

pointcut descriptor must use exact type matching. If advice were not allowed to change the target object, then less restrictive target type matching could be used.

This restriction to exact type matching is not as severe as it may seem at first. This is because when the

CALLA rule generates the target type for its join point abstraction, it uses the type of the class declaring the top-most method in the method overriding hierarchy. Thus, the actual target object for a matched call may be a subtype of the target type that was matched exactly. Using the declaring class of this top-most method also

means that advice can be written to match a call to any method in a family of overriding methods. Unlike the

CALLA rule, the EXECA rule creates a join point abstraction using the actual target type. Again, this is necessary for type safety. At an exec join point method selection has already occurred and advice cannot be allowed to

change the target object to a superclass even if that superclass declared an overridden method.

I am also interested in investigating whether a more elaborate type system might permit more expressive

pointcut matching while maintaining soundness of the static type system. However, this is orthogonal to my

concerns with modular reasoning and so I leave it for future work.

Args The args pointcut descriptor matches if the argument types of the most recent join point match

those of the pointcut descriptor. The resulting binding includes all formais named in the pointcut descriptor

in the corresponding positions. As with the target pointcut descriptor, only the relative position to be bound,

not the actual value, is available until the advice is executed. Like the target rule, the args rule uses exact type

matching.

The rules for pointcut descriptor operators simply appeal to the corresponding operators in the binding

algebra: union to disjunction, intersection to conjunction, and negation to complement. The definition of

complement implies that -i-ipcd # pcd. Both would match the same pointcut, but the former would not bind

4Indeed, in AspectJ 1.2, which includes subtype matching for its target pointcut descriptor, one can generate a run-time type error in just this way. 104 any formais while the later might. (This is slightly different than AspectJ, which simply disallows binding pointcut descriptors under negation operators.)

A final rule says that any cases not covered by the preceding rules evaluates to ±. This just serves to make matchPCD a total function, handling cases that do not occur in the evaluation of a well-typed program (such as matching against an empty join point stack).

3.2.2.5 Example Evaluations in MiniMAOi

This section gives several example MiniMAOi programs and their evaluations.

CALLS IN MINIMAOO VS. UNADVISED CALLS IN MINIMAOI The first example compares the evaluation of method calls in MiniMAOo and MiniMAOi • Consider the following program:

class Simple extends Object { Object f; Object m(Object arg) { this.f = arg } } new Simple().m(new ObjectQ)

Figure 3.15 on the next page shows the evaluation of this program in both MiniMAOo and MiniMAOi.

The evaluation on the left uses the operational semantics of MiniMAOo- The one on the right uses that of

MiniMAO;. This illustrates the splitting of the CALL and EXEC rules into pairs with advice look up, by the

BIND rule, on the inserted join points. Because this program includes no advice, the BIND rule creates chain expressions with empty advice lists and the ADVISE rule is never used. At the end of the MiniMAOi evaluation, the UNDER rules pop the join point stack.

ADVICE BINDING The next example illustrates advice binding. The example code is given in Figure 3.16 on page 106. Below is the evaluation in MiniMAOi. In the evaluation, the initial store is

So = {locA-^ [Asp.{fl i— nu 11, f2 ~ null}]}.

The illustrative part of this example is in the application of the BIND and ADVISE rules—the last two steps shown. In the BIND rule the binding term, b is <-, s, arg1 ), indicating that the target object will be bound to the formal parameter s and the argument to arg1. Figure 3.17 on page 107 shows the matching operation that yields this binding term. In the ADVISE rule the argument to the original method call, loci, is substituted for arg1 in the advice body. The formal parameter s does not appear in the advice body and so the target object of Evaluation in MiniMAOo Evaluation in MiniMAOi (new Simplef).m(new Object()),»,0) (new SimpleO.m(new ObjectO), *, 0) ^ (Ioc0.m(new Object()),*,So) (NEW) <— (Ioc0.m(new ObjectO),*,So) (NEW) ^ (Soc0.m(loc1),*,S\) (NEW) <— (loc0.m(loc1),*,S\) (NEW) — (fun m(this, arg). this. f=arg:r (locO,locl),*,S\) (CALL) (joinpt71 (locO,loc1),*,Si) (CALLA) (under chain *,j\ (locOjocI),ji,S\) (BIND) *-» (under fun m(this,arg).this.f=arg:j (Ioc0,loc1 j,71,Si) (CALLB) (locO.f = loci,»,Si) (EXEC) >— (under joinpt 72 (locOjocI) ,71,Si) (EXECA)

(under under chain *,j2 (Ioc0,loc1) ,72 + 71, Si) (BIND) (under under under locO.f- I0CIJ3 + 72 + 71, Si) (EXECB)

<—• (loci ,»,S2) (SET) ^ (under under under lochjz + 72 + ji,S2) (SET) •— (under under loc ?, 72 + 71, S2) (UNDER)

<— (under loc1,ji,S2) (UNDER)

•— (loci ,*,S2) (UNDER)

where So = {locO>— [Simple.{f-*null}]},

51 = {locO" [Simple.{f>— null}],loci •— [Object.0]},

T = Simple x Object — Object,

52 = {locO 1-» [Simple.{f•— loci}],loci —- [Object.0]},

71 = Qcatl, -, m, -, TD,

72 = (exec, -, m, fun m(this,arg).this.f=arg:T, TD, and 73 = (this, locO, -, -, -{.

Figure 3.15 Comparison of Evaluation in MiniMAOo and MiniMAOi 106

aspect Asp { Object f1; Object around(Object arg1, Simple s) : call(Object m(..)) && args(Object arg1) && target(Simple s) { this.f1 = arg1;

class Simple extends Object {class Simple extends Object { Object f; Object m(Object arg) { this.f = arg } } new Simple().m(new ObjectQ)

Figure 3.16 Sample Program Showing Advice Binding the original call, locO, is not bound. The advice never proceeds to the original method, as evidenced by the dropping of the chain expression in the application of the ADVISE rule.

(new Simple().rr\(new ObjectQ),»,So)

«— (Ioc0.m(new Object()),*,S\) (NEW)

loc A" [Asp.{f1 -» null,f2 >-» null}], where Si = locO — [Simple.{f •— null}] <-~ (loc0.m(loc1),»,S2) (NEW)

locA— [Asp.jfl •— nu 11, f2 — null}],

where Sg - - locO " [Simple, {f >— null}],

loci [Object.0]

<— (joinpt (|call, -, m, -, Simple x Object — ObjectH (Ioc0,locl),*,S2) (CALLA)

<-> (under chain (BIND)

[[ b, loc A, this.f1=arg1, Object x Simple — Object, Simple x Object ObjectW,

(Icall, -, m, -, Simple x Object — Object|) (locO,hcl),J\,S2)

where b = (-,s,arg1 )

Ji - (|call, -, m, -, -, Simple x Object — Object!) (under under locA.f1=locl,h,S2) (ADVISE)

where J2 - (this, locA, -, -, -D + }\ 107

matchPCDU(call, -, m, -, -, Simple x Object •— ObjectD, call(Object m(..)) && args(Object arg1) && target(Simple s),S2) = matchPCDU]calI, -, m, -, -, Simple x Object — Object]),call(Object m(..)),Sz) A matchPCD{^ca\\, -, m, -, -, Simple X Object -* ObjectD,args(Object arg1),%) A matchPCD(t\ca\\, -, m, -, -, Simple x Object — ObjectD,target(Simple s),%) = (-,-> u(-,-,arg1)iiJ(-,s) = (-,-,arg1) LLI <—, s> = <-s,arg1)

Figure 3.17 Sample Derivation of Pointcut Descriptor Matching

I omit the remaining steps of the evaluation because similar steps have been shown already.

ADVICE CHAINING The next example illustrates how multiple pieces of advice may bind to a single join point. It also shows how proceed expressions are converted by the «-»g j auxiliary function. I give the full program listing in Figure 3.18 on the following page, but only describe the advice chaining part of the evaluation in detail.

After looking up advice for the method call in this program, the BIND rule produces an expression that contains a subexpression like the following:

chain H<—,s1 ,arg1 >, locA, this.f1 =s1 ,proceed(arg1 ), T, T2J1 + H(-,s2,arg2), loc A, this.f2=s2.proceed(arg2), T, T2J], (call, -, m, -, T2D (locO, loci) where I assume appropriate values for the store and the type meta-variables, r and T2, but omit those details.

This expression is evaluated by the ADVISE rule, which applies the advice chaining function to the body of the first advice in the chain's advice list:

«this.fi =s1 .proceed(arg1 )» |L(-;S2,arg2>, loc A, this.f2=s2.proceed(arg2), r, T2J|, (call, -, m, -, T2|

The function replaces the proceed expression with a chain expression, yielding:

this.fi =chain (l(-,s2,arg2), locA, this.f2=s2.proceed(arg2), T, T2J], (call, -, m, -, T2D (S1, arg1)

Finally, the ADVISE rule substitutes for this and the formal parameters, and adds an under expression yielding:

under locA.f1 = chain H(-,s2,arg2>, locA, this.f2=s2.proceed(arg2), r, T2J1, (call, -, m, -, T2J (locO, loci) 108

aspect Asp { Object f1 ; Object f2;

Object around(Simple si, Object arg1) : call(Object m(..)) && target(Simple s1) && args(Object arg1) { this.f1 = sl.proceed(argl); }

Object around(Simple s2, Object arg2) : call(Object m(..)) && target(Simple s2) && args(Object arg2) { this.f2 = s2.proceed(arg2); } }

class Simple extends Object {class Simple extends Object { Object f; Object m (Object arg) { this.f = arg } }

new Simple().m(new ObjectQ)

Figure 3.18 Sample Program Showing Advice Chaining

The next evaluation step is also by ADVISE and reduces the chain expression, exhausting the advice list, and yielding the expression:

under locA.f1 = (under locA.fZ = chain •, {call, -, m, -, T2|) (locO, loci))

The last chain expression has an empty advice list. It will be evaluated by the CALLB rule, causing evaluation to proceed to the originally called method. Although the target object was not changed in this example, either piece of advice could have used a different first argument for its proceed call. The effect of this would be to replace locO in the above expression with the location of the new target object. Because the CALLB rule uses that argument position for method lookup, changing the target object at a call join point will affect method lookup.

THIS BINDING VS. TARGET BINDING My final example illustrates the differences between parameter bind­ ing for this and target pointcut descriptors in MiniMAOi. Recall that my semantics for proceed with respect to the this pointcut descriptor differs from AspectJ's. AspectI treats both this- and target-bound arguments like 109 target-bound arguments in MiniMAOi. That is, AspectJ allows advice to change the value bound by the this pointcut descriptor in subsequent advice. As discussed in above, my treatment of this is intended to reduce the interaction of aspects.

Besides contrasting the this and target pointcut descriptors, the example also uses both call and execution advice. Figure 3.19 on the next page gives the sample program.

Below is the evaluation in MiniMAOi. In the evaluation, the initial store is So - {locA — [Asp.0]}. For conciseness, the values of the stores and the derivation of the binding terms are left as exercises for the reader.

I write under" to indicate n instances of the keyword under. Interesting parts of the evaluation are noted along the way.

(new 5uperf).run(V,So)

(loc0.run(),»,Si) (NEW)

(Joinpt (ca//,-,run,(locO),», SI} (CALLA)

where TO = Super—Object

•— (under chain », Qcall,-,run,-,T0i (IOCO),JQ,S\) (BIND)

where Jo - (call,-,run,-,TOD

(under (fun run(this).this.mfn ew Super()):rO (locO)),Jo,S\) (CALLB)

<— (under joinpt §exec,locO,run,fun run(this).this.m(new Super()):r0,T0i (locO),Jo>Si) (EXECA)

^ (under2 chain », §exec,locO,run,fun run(this).this.m(new Super()):T0,T0§ (locO),J\,S\) (BIND)

where J\ = (exec,locO,run,fun run.this.m(new Super0):TO,TOl) +/o

<-> (under3 loc0.m(nevv5uperO),/2,Si) (EXECB)

where J2 - flthis, locO,——D +/i

^ (under3 Ioc0.m(locl),J2,82) (NEW)

3 (under joinpt t\call,-,m,-,Tl\i (Ioc0,locl)J2,S2} (CALLA)

where T1 = Superx Super—Object

(under4 (BIND)

chain H(caller^locO,callee,arg}, locA, (caller;callee;new Sub().proceed(arg)), T2, T/J1

icall,-,m,-,Tl\i (locO,loc 1),h,S2)

where T2 =SuperxSuperxSuper—Object

h = (|call,-,m,-,TL 6 + 72

The binding term above maps caller to the calling object's location, locO, and records that cal lee and arg should be bound to the target and argument of the chain expression. 110

aspect Asp { // call advice Object around(Super caller, Super cal lee, Super arg) : call(Object m(..)) && this(Super caller) && target(Super callee) && args(Super arg) { cal 1er; // these variable references just help illustrate the substitution behavior callee; new Sub().proceed(arg) // changes target to subtype, affects method selection }

// execution advice Object around(Super caller, Sub callee, Super arg) : execution(Object m(..)) && this(Super caller) && target(Sub callee) && args(Super arg) { caller; // these variable references just help illustrate the substitution behavior callee; new SubSubQ.proceed(arg) // changes target to subtype, no effect on method selection } } class Super extends Object { Object run() { this.m(new SuperO) }

Object m(Super arg) { arg } } class Sub extends Super { Object m(Super arg) { arg; this } } class SubSub extends Sub { Object m(Super arg) { this } } new SuperQ.runQ;

Figure 3.19 Sample Program Contrasting this vs. target Binding and call vs. exe­ cution Advice Ill

5 ^ (under (Ioc0;loc0;chain • (| call,-,m,-,Tli (new Sub(), loci )),J4,S2) (ADVISE)

where /4 = Qthis, locA, + /3

Now the proceed expression in the advice body has been replaced with a chain expression. The target argument to the chain is new Sub(), not the original target.

5 <— (under chain • flcall,—,m,—,T1 D (new Sub(), loci ),/4,S2) (SKIPX2)

^ (under5 chain • (Ioc2, loci A/4, S3) (NEW)

— (under5 (fun m{this,arg),(arg;this):T3 (loc2, loci)), J4,S3) (CALLB)

where T3 = Subx Super—Object

Because the advice changed the target of the call to loc2, the fun term above came from Sub, not Super.

5 <— (under joinpt i\exec,loc2,m,fun m(this,arg).(arg;this):T3,T3\I (loc2, loc1),J4,S3) (EXECA)

(under6

chain \[(caller^loc2,callee,arg), locA, (caller; callee; new SubSub().proceed(arg)), T4, T3J]z

<\exec/loc2/m,fun m{this,arg).(arg;this):T3,T3|) (IOC2, loci) J5,S3> (BIND)

where T4 = Superx Subx Super—Object

h = (exec, loc2, m, fun m(this,arg>.(arg;this):T3, T3D + h

(under7

(loc2; loc2; chain •, (|exec,loc2,m,fun m{this,arg).(arg;this):x3,T3^ (new SubSub()Joc1 )),}%,S3) (ADVISE)

where J§ = (|this,locA,-,-,-D + J5

Again the proceed expression in the new advice body—new SubSubQ.proceed(arg)—was replaced with a chain expression that has a new target object, new SubSubQ instead of loc2.

(under7 chain •, (|exec,loc2,m,fun m(this,arg).(arg;this):T3,T3D {new SubSubO^ocDJs^j)

(SKIP x 2)

7 — (under chain •, iexec,loc2,m,fun m(this/arg).(arg;this):j3/T3\I (loc3,loc1 ),h,S4:) (NEW)

8 '—(under (loci;IOC3),JI,S4) (EXECB)

where /y = Qthis,loc3,—D + h

Unlike for the call advice above, even though the target object was changed to an instance of SubSub, the already selected method body was used when proceeding to the code under the exec join point. 112

(under8 loc3,77,84) (SKIP)

• (IOC3,*,S4) (UNDER x8)

3.2.3 Static Semantics of MiniMAOi

Figure 3.20 on the following page and Figure 3.22 on page 116 give the additional rules for the static semantics of MiniMAOi. All of the rules from MiniMAOo are used unchanged.

For typing MiniMAOi, I extend the domain of F to include the keyword proceed, and its range to include function types. That is, for the static semantics:

F:{y u {this,proceed}) — {3~u(3~* —5"))

This lets us use the type environment to record the type of an advised method so that proceed expressions in

the body of advice may be assigned the appropriate type.

3.2.3.1 Declaration and Expression Typing Rules

The T-ASP rule says that an aspect declaration is well typed if all of its advice declarations are well typed.

Advice is well typed, as defined by the T-ADV rule, if its pointcut descriptor matches a join point where the code

under the join point has target type uo, argument types u\,...,up and return type u. The "J' in the hypothesis

indicates that we do not care about the type bound by a this pointcut descriptor here. The pointcut descriptor

must also specify bindings for all of the formal parameters of the advice. These requirements are embodied in

the pointcut descriptor typing, pcd\^.u$.{u\,...,up).u.V.V, which is discussed in Section 3.2.3.2 below. The

body of the advice is typed in an environment that gives each formal its declared type, gives this the aspect type,

and gives proceed the type of the code under the join point matched by the advice. In this environment, the

advice body must have a type that is a subtype of the declared return type of the advice. In turn, this declared

return type must be a subtype of the return type of the original code under the join point. This allows the result

of the advice to be substituted for the result of the original code.

Rule T-ADV permits advice to declare a return type that is a subtype of that of the advised method. This

means that advice like:

A around(C targ) : call(B m(..)) && target(C targ) && args() { targ.proceedO }

is not well typed if A is a proper subtype of B: the proceed expression has type B, which is not a subtype of

the declared return type of the advice. Wand et al. [157, §5.3] argue that this advice should be typable, but I 113

Aspect typing:

T-ASP Vz' e {l..p}- h advi OK in a

h aspect a {fieldi.. ,fieldn adv\... advp } OK

Advice typing:

T-ADV

VCITj : t\,...,V&RFI : tn I pcd:^ • u@ * (^U \t... ,up) m Uw V• V

V = \ vari,...,varn} var\ : ti,...,varn : f„, this : a, proceed : (mo x ... x Mp -- u) I- e:s

h t around( t\ vari,...,tn varn ) : pcd { e } OK in a

Expression typing:

T-PROC VZE [Q..n}-Y\~ ei:ui T-UNDER

r (proceed) - fax ...xtn~* t Vz e {0..n} • ui =4 tj Y\-e\t

r h eo.proceed( e\,...,en)-.t Y h under e:t

T-CHAIN

Vz E {Q..n} • Y h e'f : u!i Vi e {0..n( • u't 4 ti

Vz E {l..p} T,this:F(/oc,),proceed:t ,typeBind(Y ,bi,{to,... ,tn)) h e, : s-

Vz e {l..p} - F h bi OK Vz E {l..p} • s'^ t T = fox ... x tn — t

F H chain \[bit locifeitT',xjlie{1 e'0,...,e'n ): ?

T-JOIN

Vz E {0..«} • T h ez- : u/ Vz E {0..W} • u; =4 ti [vopt - loc) =» (loce dom{Y))

rhjoinpt vopt,^,^Afax...xtn — f)P(eo,...,e„):f

Binding typing:

T-BIND (a = t/ar— => [vart V\{var}) Vz e \0..n] • (/3; = var) => (z/arC V\ {j8z})

Vvar e V• (V € dom(Y)) V - var(b) b = {a,Po,...,pn)

ThfoOK

.. 0 „ {{var}\j\pri£{0..n},Piï-} if a = var— v where var({a,p0,...,pn)) = < I {j6, • z E |0..n}, otherwise

Figure 3.20 Additions to the Static Semantics for MiniMAC^ 114 disagree. This case is really no different than a super call in a language with covariant return-type specialization.

In such a language, an overriding method that specializes the return type cannot merely return the result of a super call as its result. The overriding method must ensure that the result is appropriately specialized.

There are four new typing rules for expressions in MiniMAOi. Only the first, T-PROC, is used in the static typing of programs. The other three arise in the subject reduction proof to handle expression forms that are only introduced by the evaluation rules.

The T-PROC rule types proceed expressions. A proceed expression is well typed if its argument expressions are subtypes of the required types as recorded in the type environment. The type of the proceed expression is also taken from the type environment.

The T-UNDER rule says that an under expression is well typed if its contained expression is well typed. The type of the under expression is just that of the contained expression.

The most complex of the typing rules is T-CHAIN. This rule is not used in the static typing of programs, but arises in the subject reduction proof to handle chain expressions introduced by the evaluation rules. My use of chain and joinpt expressions in the semantics of MiniMAOi allows advice binding to be localized in a single evaluation rule, and to be separated from advice execution.. The necessary trade-off is the complexity of the

T-CHAIN rule, which ensures the advice bound to a join point is well behaved.

The first two hypotheses of T-CHAIN require that the argument expressions are subtypes of the types expected for the code under the join point. The last hypothesis is just a side condition on r. The remaining hypotheses ensure the each piece of advice in the advice list satisfies the following conditions:

— The advice's binding term is well formed according to the T-BIND rule, which ensures that only fresh

variables are bound and no variable is bound more than once.

— The advice's body expression is a subtype of the return type of the join point abstraction. This is also the

type given to the entire chain expression. The typing of the body expression uses an auxiliary function,

typeBind, defined in Figure 3.21 on the following page, that converts the type environment, the binding

term, and the argument types into a type environment. This type environment corresponds to the

substitution defined by the binding term (see Figure 3.12 on page 97).

Finally, the T-JOIN rule types joinpt expressions. It simply ensures that all of the arguments are subtypes of the argument types in the join point abstraction. It also checks that any location given in the join point abstraction is valid in the type environment. 115

typeBind(r,(var — loc,/30,...,jSM),(to,•..,tp)) = var:T{loc),(vart : ti)ie[o..n].pi=mri if n

typeBind(r, /30,... ,0„), ( f0,... ,fp» = (van : ti)i€[0..n}.pi=mri if n < p typeBind(r,(a,Po,--->Pn),(to>---,tp)) is undefined if n > p

Figure 3.21 Binding for Type Environments

3.2.3.2 Pointcut Descriptor Typing Rules

The rules for typing pointcut descriptors are shown in Figure 3.22 on the following page. These rules make use of a simple algebra over ST u {_!_}, whose only operator, u, is used to combine type information when pointcuts are intersected. This is also lifted to type sequences. The pointcut descriptor typing judgment,

TI- pcd:û.û' .U.Û". V\ . Vz, gives:

— û, the this type for any code under a join point matched by this pointcut descriptor, or _L if the informa­

tion cannot be determined from the pointcut descriptor;

— û!, the target type for any code under a join point matched by this pointcut descriptor, or 1 if the

information cannot be determined from the pointcut descriptor;

— U,the argument types for any code under a join point matched by this pointcut descriptor, or _L if the

information cannot be determined from the pointcut descriptor;

— û", the return type for any code under a join point matched by this pointcut descriptor, or _L if the

information cannot be determined from the pointcut descriptor;

— Vi, the set of variables that would definitely be bound by the pointcut descriptor at a matched join

point; and

— Vz, the set of variables that might be bound by the pointcut descriptor at a matched join point.

The two sets of variables represent "must-bind" and "may-bind" sets respectively, which are useful in reasoning about variable bindings in pointcut unions and intersections. Well-typed advice requires that the must-bind and may-bind sets are identical (see the first hypothesis of T-ADV).

Given this form for the typing judgment, the rules for the primitive pointcut descriptors are mostly obvious.

The only interesting bits are:

— the T-THISPCD, T-TARGPCD, and T-ARGSPCD rules verify that the type annotations for the bound

parameters match the type of the formais as recorded in the type environment; and 116

Pointcut typing:

U :: = (t*) | _L ZÎ :: = f | _L y e

m u _L = m ± u û = M t/ul = U ±uU = U T-CALLPCD T-EXECPCD

F h call( t idPat(,,)):±.±.±.t.0.0 F hexecution( t idPat(.,)):±.±.±.t.0.0

T-THISPCD T-TARGPCD F(mr) = t T{var) - t

T hthis( t var): f.±._L._L.{tw}. {var} F h target( r var):±. t.±.±.{var}.{var}

T-ARGSPCD Vz E {l..n} • (F (vart) - f,0 Vz E {l..n} • (V j E {!..»} \ {z} • [vari ^

F h args( t\ var\,...,tn varn):±.±.(ti,...,tn).±.{vari,...,varn}.{vari,...,varn}

T-UNIONPCD

R h pcdx : û.û'. U. û".Vi. V( T\- pcd2:û.û' .U .û" .V2.V2 T-NEGPCD V = V] n V2 V' = V{ u v[ T\-pcd:û.û'.U.û".V.V'

F h pcdl II pcd2:û.û' .U.û" .V.V' F h ! pcd:±._L._L.±.0.0

T-INTPCD

F h pcd\ : û]. û\ .U\ . û". Vj. V,' F h pcd2 : Î12 • û'2 • Lh • û'I • V2 - V2

û=û]uû2 û' = û[ u û2 U=UiuU2 û"=û"uû2

V[ nV^=0 V=ViuV2 V' = y/ u V2

1 F h pcdi && pcd2 :û.û'.U.iï" .V.V

Figure 3.22 Static Semantics of Pointcuts in MiniMAOi

— the second hypothesis of T-ARGSPCD ensures that no formal parameter is bound twice.

The typing rules for pointcut descriptor operators are more interesting. The T-UNIONPCD rule requires that the two combined pointcut descriptors match join points where the type of the code under the join points is the same. This allows typing of any proceed expressions within the advice regardless of which pointcut in the disjunction was matched. The T-INTPCD rule requires that the combined pointcut descriptors specify types in disjoint positions. For example, if one of the combined pointcut descriptors specifies the argument types, then the other must not. This helps to ensure that no actual argument may be bound to multiple formal parameters. The T-INTPCD rule also requires that the sets of variables that may be bound by the two pointcut descriptors be disjoint; this helps to ensure that no formal is bound twice. 117

3.2.4 Meta-theory of MiniMAOi

The meta-theory of MiniMAOi is essentially the same as for MiniMAOo. One difference in the theorems and lemmas is that we must deal with a non-empty initial store that contains aspect instances. Some complications arise in the proofs, which must be extended to deal with the new typing and evaluation rules. The key technical innovation is a Binding Soundness lemma that relates the type of a pointcut description to the type of any code that it matches.

The statement of the Substitution lemma is unchanged. For clarity, I repeat it here with the updated proof.

I 1 l Lemma 3.10 (Substitution). IfT,var\ : t\,...,varn :tn\- e:t and^i e {!..«} • F h e,- : s,- where Si =4 ti then

F h e\e\ / vari,...,en/var n\: s for some s ^ t.

Proof. Let F' = F, var\ : h,...,var n : tn and let J ê/ mr\ represent Jei / var\ ,...,enl var„\. The proof proceeds

by structural induction on the derivation of F H e: t and by cases based on the last step in that derivation.

The base cases are T-NEW, T-OBJ, T-NULL, T-LOC, and T-VAR. In the first four of these cases, e has no

variables and s= t.

In the T-VAR base case, e = var, and there are two subcases. If var € {varvarn] then Y'{var) =

T{var) = t and the claim holds. Otherwise, without loss of generality, let var = var\. Then e\el var) = e\,

F h e\êl~vcîr\: si, and si ^ t\ = t.

The remaining cases cover the induction step. The induction hypothesis is that the claim of the lemma

holds for all sub-derivations of the derivation being considered.

Case 1—T-CALL. Unchanged from original proof of Lemma 3.2 (Substitution) on page 78.

Case 2—T-EXEC. Unchanged from original proof.

Case 3—T-GET. This case is essentially unchanged from the original proof, except for some details regard­

ing the extended fieldsOf auxiliary function. I restate the entire case for clarity.

In this case e = e'.f. The last step in the type derivation for e is

f' h

T'\-e'.f:t

Now elëI mr\ - e'\et var\.f, and by the induction hypothesis F h e'\êl~vâr\:u', where u' =4 u. Consider

subcases on whether u' is a class or an aspect. If isClass{u'), then by the definition of fieldsOf and by the 118

first hypothesis of T-CLASS, fieldsOf (U1) (/) = fieldsOf{u){f) = t.On the other hand, if u' is an aspect, then u' = u (since an aspect is only a subtype of itself and Object, and u ^ Object because fieldsOf (u) ^ 0). So again fieldsOf(«')(/) = fieldsOf (u){f) = f. In either case, T h e\ë! var\ : I and the claim holds.

Case 4—T-SET. Like the previous case, this case is essentially unchanged from Lemma 3.2 (Substitution) on page 78, but with the same concession made for the subcases on fieldsOf.

Case 5—T-CAST. Unchanged from original proof.

Case 6—T-SEQ. Unchanged from original proof.

Case 7—T-PROC. Mere e - e^.proceecK ,...,e'p ) and the last derivation step is

Vz e {0..p}-r' I- e\ : r' (proceed) = uox ••• x"p — t Mi G {0..p\-u\ ^ M,-

T' h gQ.proceed(e'v...,e'p)\t

Let e'! = e'Jë/vârl for all i e {0..p\. Then e\elmr\ - gg.proceed( e'[,... ,e'p ). Now F (proceed) =

T' (proceed) = uqx ...*up — t and by the induction hypothesis

Vz e {0..p} • (r h e" : u", where u" =4 u\ ^ u{].

Thus, by T-PROC, T H e\ël var\ : t and the claim holds.

Case 8—T-UNDER. Here e = under e' and the last derivation step is

r' I-e'\t

r' I- under e': t

The claim is immediate by the induction hypothesis.

x x u Case 9—T-CHAIN. Here e = chain uopt, mopt, /Opt»(wo ••• p f)D( e'0,...,e'p ). The last derivation step for the judgment r' h e : t is by T-CHAIN, with the first two hypotheses being:

\/ie{0..p}-T'\-e'i:u'i Vz e {0..p} • u'i =4 ui 119

Let e'! = e'^el var\ for all i e {0..p}. Then

e\ël~vâr\ -chain BJfc, vopt, mopt,l opt,{u 0x...xup — f))( eQ,...,ep ).

Substitution does not recurse into the advice list, B, or the join point abstraction.

As in the T-PROC case, the induction hypothesis gives VZ e {0,.p\ • (r h e" : u", where u" =4 z/. =<: Uj).

Because substitution does not replace variables within B, the remaining hypothesis of T-CHAIN are un­

changed in the type derivation of e\êl~vïïr\, except for using F instead of I"'. This fact does not change the

judgments. Thus, T h e\ëlvïïr\ : t.

x x Case 10—T-JOIN. Here e = joinpt D k, vopt, mopt, lopt, ("o • • • up — £)D( e'w... ,e'p ). The proof is like that for

Case 9. • 1 1

The Environment Extension, Environment Contraction, and Replacement lemmas (Lemma 3.3 (Environ­ ment Extension), Lemma 3.4 (Environment Contraction), and Lemma 3.5 (Replacement), respectively) apply to MiniMAOi without change. The proof of Lemma 3.6 (Replacement with Subtyping) on page 82 needs two additional cases in the induction step to account for the new evaluation context rules. I restate it here.

I 1 Lemma 3.11 (Replacement with Subtyping). IfT\- E[e] :t,T\-e:u, and T H e' :u' where u' =4 u, then

r h E[e'] : t' where t' ^ t.

Proof. The proof is by induction on the size of the evaluation context E, where the size is the number of

recursive applications of the syntactic rules necessary to build E. In the base case, E has size zero, E - -,

and t' = u' ^ u= t.

For the induction step we divide the evaluation context into two parts so that E[—] = Ei IE2ML where

E2 has size one. The induction hypothesis is that the claim of the lemma holds for all evaluation contexts

smaller than the one considered in the induction step, and therefore holds for Ei. We use a case analysis on

the rule used to generate Ez- In each case we show that if Y h E2\e] : s then F h E2 [e'] : s' where s' 4 s, and

therefore the claim holds by the induction hypothesis.

Casel—E2 = -.m( e\,...,en ). Unchanged from original proof of Lemma 3.6 (Replacement with Subtyping)

on page 82.

Case2—E2 = i>o-m( vi,...,vp-i,-,ep+\,en ) wherepe \l..n\. Unchanged from original proof. 120

Case3—E2 = (I ( vo,...,vp-\,-,ep+\,en) ) where p e Unchanged from original proof.

Case 4—Eg = Unchanged from original proof.

Case 5—Eg = cast s -. Unchanged from original proof.

Case 6—E2 = e". Unchanged from original proof.

Case 7—Ez - (-•/ = e"). Unchanged from original proof.

Case 8—E2 = (v.f - -). Unchanged from original proof.

Case 9—E2 = joinpt §k,v0pt,m0pt,l0pt,(so* ...xsn — s)i( vo,...,vp-i,-,ep+\,e„ ) where p E {Q..n}. The

last step in the type derivation for Ezle] must be T-JOIN:

Vz e {0..(p-1)} - F h Vi : ut Y\~e:u Vz e {(p + !)..«} - T h e,- : M,

Vz' e {0..n} \{p}-Ui=4 ti u=4sp [vopt = loc) => (locedom{T)}

T h E2[e] : s

Now u! =4u^ sp. So, also by T-JOIN, F h E2[E'] :s.

Case 10—E2 = under The proof for this case is immediate from T-UNDER with s = u and s' - u'.

Casell—E2 = chain B,j( vo,...,vp-i,-,ep+\,en ) where p e \Q..n}. The proof is like that for Case 9, but

using T-CHAIN instead of T-JOIN. The additional hypotheses of T-CHAIN, beyond those of T-JOIN, are

unchanged in the type derivations for E2 [e] and E2[e'l • • 1 1

Before stating the Subject Reduction theorem for MiniMAOi, I give a few necessary definitions and lemmas.

One simple lemma is analogous to substitution but changes the environment instead of the expression.

I I Lemma 3.12 (Environment Subtyping). LetT, var: t\- e:s. Then for all t' ^4 t, there exists some s' =4 s such

that, T, var: t' h e:s'.

Proof. Let var* be a variable reference such that var11 dom{T), var1 ^ var, and var' is not free in e. Then by

the assumption of the lemma and Lemma 3.3 (Environment Extension) on page 81, T, var1 : /', var: t h e : s.

By Lemma 3.10 (Substitution) on page 117, F, var' : t' h elvar11 var\ : s' for some s' =4 s. Finally, by a-

converting var1 to var (relying on the correspondence of «-conversion with capture avoiding substitution

of one variable reference for another), we have F, var: t' e:s' for some s' =4 s. • 121

I define notions of a consistent stack and a valid store for a given MiniMAOi program. These definitions are used to ensure that all locations listed in the stack are bound in the store, and that the store contains an instance of every aspect declared in the program.

I 1 Definition 3.13 (Stack-Store Consistency). A stack ] and a store S are consistent, and we write / = S, if

V(L, loc, ^ 5 e ] • loc e dom(S).

Definition 3.14 (Store Validity). Given a program P, we say that a store S is valid if both of the following

hold:

1. Vaspect a { ... } e CT-{3loce££-S(loc) = [a.F])

2. 3T-T-S i I

We will need a lemma that relates advice binding to advice typing. This lemma is used in the subject reduction proof to argue that the list of advice that matches at a joinpt expression can be used by the BIND rule to generate a well typed chain expression.

I 1 Lemma 3.15 (Binding Soundness). Let S be a valid store and J = (]..., fox... x tn — £D + J' be a stack con­

sistent with S. IfB - adviceBindU, S), then Vfli>, loc,e, T, T'JI e B the following conditions hold:

L T'= fox...xf„ — f,

2. 0\-b OK, and

3. forT ~ S the judgment r,this: F ( loc), proceed :t' , typeBind(T ,b,(to,... ,tn» h e:t' holds for some t' ^ t.

Proof I will use some common meta variables throughout the proof. Pick an arbitrary element of Ë,

life, loc,e, T, T'JI , and let T = si x... x sp — s. Let the advice corresponding to \[h, loc, e,T, T'JI be

s around( si vanvarp): pcd{ e} 122

Advice declaration: s around( si var\ sp varp ): pcd { e)

fib, loc, e,t ,T 'JI E Ë

T = SI X ... X SP — S

T' = WO x ... x Uq —• U

r' = var\ : si,...,varp : sp r' h pcd: ^,Uq).u.V. V

Figure 3.23 Meta-variables Used in the Proof of Lemma 3.15 with advice table entry (loc, pcd, e, T,T'). Let this advice be declared in an aspect a. T-ADV gives

var\ :s\,...,varp:sp h pcd: ^.uo • (ui,... ,uq) .u.V. V

x V - {var\,...,varp} vari : s\,...,varp:sp,this : a, proceed : («o ••• *Uq -* u)\- e:s' s' =4 s =4 u

h s around( s% var\,...,sp varp):pcd { e } OK in a (3.1)

By the construction of AT, r = uo x... x uq — u. To simplify the notation, let F' = ran : si,..., varp : sp. For

convenience, Figure 3.23 summarizes the use of these meta variables in the proof.

Because a well-typed pointcut descriptor in MiniMAOi must consist of multiple primitive pointcut

descriptors, it is difficult to prove the consequents of the lemma using a single inductive argument. Instead,

I propose and prove a series of simpler subclaims. Each subclaim is proven via a structural induction on

the pointcut type derivation. A well-typed pointcut descriptor that matches J will satisfy the antecedents

of all the subclaims, and the consequents of the subclaims will imply the consequents of the lemma.

Consequent 1 on the preceding page relates the proceed type of the advice, T', to the function type in

the join point abstraction. The proceed type, T' = UQ X ... x uq — u, is constructed from the pointcut typing

for the advice, pcd:. uq. ( ui,...,u q ).V. V. To satisfy the consequent we must show that T' = to x ... x tn — t.

We use three separate subclaims, one for each pertinent position in the pointcut typing. The subclaims let

us show:

— MQ = to,

— q = n,Vi E {!..»}• M, = t[, and

li — t 123

Subclaim 1. Assume T' h pcd : û. uq .U. û'.V'. V" (i.e., the "target type" is not _L). Then

matchPCDU, pcd, S) # ± => uq -to

Proof of subclaim.

— pcd = call( t" idPat(..) ). Subclaim assumption cannot hold.

— pcd= execution( t" idPat(..) ). Subclaim assumption cannot hold.

— pcd = this(... ). Subclaim assumption cannot hold.

— pcd = target( t" var" ). By T-TARGPCD, t" = uq.By the definition of matchPCD,

matchPCDU, pcd, S) ^ _L => to = l"

•' Uo — to-

— pcd - args(... ). Subclaim assumption cannot hold.

— pcd - pcd y || pcd2. ByT-UNlONPCD, T' h pcd, : û\.uq.U\.û\.V\.V,' and F' h pcd2 : û2• «o V'2.

By the induction hypothesis, matchPCDU, pcd1,S) -£ _L ==> uq = to and matchPCDU, pcd2,S) #

1 ==> uq - to. By the definition of matchPCD,

matchPCDU, pcd, S)^± ==> matchPCDU, pcd1, S) •£ 1or matchPCDU, pcd2,S) # _L

=> Uo = to

— pcd = pcdJ && pcd2. By T-INTPCD and the definition of u, one of the following hold:

- F' h pcd1 :û\.Uo. U\. û\.V\. V[ and F' h pcd2 :û.2.1.U2.û2.V2.V' 2

- T' h pcd] : Mi. _L.U\. .V]. Vj' and F' h pcd2 : u2. uq. U 2 • u'2 • V2.V 2

So the induction hypothesis holds for the type derivation of at least one of pcdl and pcd2. By the

definition of matchPCD,

matchPCDU,pcd, S) ^ -L ==> matchPCDU, pcdl,S) ^ 1 and matchPCDU, pcd2,S) 7^ _L

=> Uo = to

— pcd = ! pcdi • Subclaim assumption cannot hold. 124

Subclaim-n

Subclaim 2. Assume T' h pcd: û.û'. (ui,...,u q). û".V'. V" (i.e., the argument type sequence is not _L).

Then

matchPCDU, pcd, S) #1 => (q = n and Vi e {!..»} • Uj - tt)

Proof of subclaim.

— pcd - ca 11 (Subclaim assumption cannot hold.

— pcd — execution(... ). Subclaim assumption cannot hold.

— pcd = this(... ). Subclaim assumption cannot hold.

— pcd = target(... ). Subclaim assumption cannot hold.

— pcd = args( t" var"vt"H! var). By T-ARGSPCD, W = q and V i e \l..q\• U, = t'!. By the definition of

matchPCD,

matchPCDU,pcd,S) # _L => w = n and Vi e {l..n} • £,- = t"

=> q = n and Vi e {1..n] • w, - ti

— pcd- pcd1 || pcd2. By T-UNIONPCD, F' H pcdi u\ Uq).û'Î.Vi.V^ and F' h pcd2 :Û2.Û'2.

V Uq ). û?,'. • 2- By the induction hypothesis, matchPCDU, pcd], S) ± => q = n and V i e

[l..n\ • Uj = ti and similarly for matchPCDU, pcd2,S). By the definition of matchPCD,

matchPCDU, pcd, S) ^ 1 => matchPCDU,pcdi, S) # _L or matchPCDU, pcd2,S) # _L

=> q = n and Vi E {1..n} • w,- =

— pcd - pcdi && pcd2. By T-INTPCD and the definition of u, one of the following hold:

- F' h pcdi '• "i • û'i • («i,-..,Uq). û". Vi. V{ and F' h pcd2 :û2.û'2.±.û2.V2.V 2

- F' h pcdx '• "l • "'i • -L • û'I.Vi . Vj and F' h pcd2 :û2.û'2.(ui,...,uq).û2.v2.V 2

So the induction hypothesis holds for the type derivation of at least one of pcdi and pcd2. By the

definition of matchPCD,

matchPCDU, pcd, S) ^ _L => matchPCDU, pcd],5) ^ 1 and matchPCDU,pcd2,S) ^ _L

=> q-n and Vi e {\..n} • w, = ti 125

— pcd = ! pcd]. Subclaim assumption cannot hold.

Subclaim-O

Subclaim 3. Assume f h pcd-.û.û' .U .u.V' .V" (i.e., the "return type" is not 1). Then

matchPCDU, pcd, S) ^ _L => u = t

Proof of subclaim.

— pcd - calI( t" idPat{..) ). By T-CALLPCD, t" - u. By the definition of matchPCD,

matchPCDU, pcd, S) 1 => t = t"

=> u—t.

— pcd = execution( t" idPat(..) ). Similar to previous case, but by T-EXECPCD.

— pcd = this(... ). Subclaim assumption cannot hold.

— pcd = target(... ). Subclaim assumption cannot hold.

— pcd= args(... ). Subclaim assumption cannot hold.

— pcd= pcd y 11 pcd2. By T-UNIONPCD, T'H pcd^ûi.ô'j.l/I.u.Vi. V{ and F'H pcd2 :Ù2-û'2.U2.u.V2.V 2.

By the induction hypothesis, matchPCDU, pcd j,S) ^ ± => u = t and matchPCDU, pcd2,S) # _L =>

u = t.By the definition of matchPCD,

matchPCDU,pcd, S) ^ _L => matchPCDU,pcd}, S) ^ 1 or matchPCDU, pcd2,S) # 1

=> U—t

— pcd = pcd y && pcd2. By T-INTPCD and the definition of u, one of the following hold:

- r' h pcdy :û\.û'x.U\.u.V\. and F' h pcd2 :Û2'û'2.U2.L.V2.V2

- F' h pcd] : û\.û[. U]. J_.V] . V/ and F' h pcd2 : «2 • û'2.U2. u.V 2. V2'

So the induction hypothesis holds for the type derivation of one of pcd] and pcd2. By the definition of

matchPCD,

matchPCDU, pcd, S) # ± =» matchPCDU, pcd[, S) # _L and matchPCDU, pcd2, S) ^ -L

==> u = t 126

— pcd = ! pcdx. Subclaim assumption cannot hold.

Subclaim-O

With these three subclaims we can now prove consequent 1 on page 121. The first hypothesis of T-ADV

(see (3.1) on page 122) is:

T' h pcd :.M Q .( Mi uq).u.V .V

Thus, the target type is not _L, nor is the argument type sequence, nor the return type. So the assumptions of the first three subclaims all hold. Furthermore, by the definition of adviceBind, \[b,loc, e, T, T'JI eB implies matchPCDU, pcd,S) ^ J_. Thus:

T'— MO X ... X Uq —* M by construction of AT

— fa x MI x...x uq — M by Subclaim 1

= to x t\ x ... x tn — M by Subclaim 2

= to x... x tn — M

= fox ...xtn — t by Subclaim 3

We next turn to consequent 2 on page 121. We can this prove consequent with a single subclaim. We use a subclaim that is stronger than the consequent, partly so that the induction hypothesis is sufficiently powerful. The stronger subclaim will also be useful in proving consequent 3. In the subclaim, var(b) means all variables appearing in b (as defined in Figure 3.20 on page 113).

Subclaim 4. Assume F' h pcd-.û.û! .U. û".V'. V". Then matchPCDU, pcd, S) - b- (a,Po,---,Px) implies all of the following:

0 h b OK (3.2a)

V' ç var(b) Q V" (3.2b)

M = -L <=> a = — (3.2c)

û' = ± <=> fio — — (3.2d)

U = -L => x - 0 (3.2e)

U 5^ _L => x — n (3.2f)

U=L<=> VzE{1..4-/3i = - (3.2g) 127

Proof of subclaim.

— pcd = call( t" idPat(..) ). By T-CALLPCD, F' h pcd:.L. J 1.1" .0.0, By the definition of matchPCD,

matchPCDU,pcd,S)-b-(a,po,...,$x) ==> b

=> 0 h bOK

V' = 0 ç var(b) Ç0 = V"

û — _L and a = - so (3.2c) holds

û' = _L and /3q = -so (3.2d) holds

U = 1 and x = 0 so (3.2e) holds

U = J. so (3.2f) holds

U - 1 and V i e {1..0} • f>j = - vacuously, so (3.2g) holds

— PCD = execution( t" idPat(..) ). Similar to previous case, but by T-EXECPCD.

— pcd = this( t" var" ). By T-THISPCD, F' h pcd: t". J.. _L. -L .{var"} ,{var"\. By the definition of

matchPCD,

matchPCDU,pcd,S) = b=(a,fio,...,Px) => b= {var" — v,-) for some v e Y

=> 0 h fo OK

V' = {var"} Ç var(b) <~ {var"} - V"

û £ _L and a ^ - so (3.2c) holds

and /3Q--SO (3.2d) holds

U= ± and x = 0 so (3.2e) holds

U - 1 so (3.2f) holds

U - ± and Vi e {1..0} • /3, = - vacuously, so (3.2g) holds

— pcd = target( F" FAR" ). By T-TARGPCD, F' H pcd : _L. . J L. {var"}. {var"}. By the definition of 128

matchPCD,

J matchPCDU,pcd,S) = b-(a,Po,...,px) => b = {-,vat ')

0\- b OK

V' = {var") ç var{b) G {var"} = V"

û -1 and a - - so (3.2c) holds

«V 1and y3o ^ - so (3.2d) holds

U = -L and x = 0 so (3.2e) holds

t/ = 1so (3.2f) holds

U =1 and Vi e {1..0) •/?,- = - vacuously, so (3.2g) holds

pcd = args( ï" m//,...,t'^ var1^ ). By T-ARGSPCD, R' h pcd:1.1. (t",...,t'^).1. V'. V" where V' =

J V" = {vai [,...,var'lv\, and all var'! are unique. By the definition of matchPCD,

J matchPCDU,pcd,S) = b= (a,^,...,^x) =>• b = (-,-,var'{,...,va.i lv)

=> 0 I- b OK

V' ç var(b) ç V"

M = 1and a = - so (3.2c) holds

û' =1 and = - so (3.2d) holds

U ^ 1so (3.2e) holds

[7^1 and x = w = n by Subclaim 2, so (3.2f) holds

U ^ 1and 3/ e {1..0} • - so (3.2g) holds

• pcd = pcd] 11 pcd2. By T-UNIONPCD, let

T'h pcdj : MI .M 'j .U\ . M" .Vi . V[

F' h pcd2 : «2 • û'2 • U2 • M2 . V2. V2

Also let matchPCDU,pcdx,S) = ri and matchPCDU,pcd2,S) - r2.

By elementary set theory, V' = V\C\ V2 =^> V' Q V\ and V' Ç v2. Dually, V[ Ç V" and V'2 Ç I/". By the

definition of matchPCD,

matchPCDU,pcd,S) = b = {a,(5o,---,Px) => b = r\ •£ 1or b - r2 ^ 1 129

Without loss of generality, let b-r\.Then the induction hypothesis gives:

matchPCDU,pcd,S) = b = (a,/5o,...,/3x) => 0 H bOK

V' Q Vi S var(b) Ç V,' Ç V"

(û = -L <=> a — —)

[ù! = _L <=> /3q = -)

((/ = _!_ ==> x = 0)

((/ ^ 1 => x=ri)

{U=.L <=> Vi e {1..JC}-/3j = -)

— pcd = pcd] && pcd2. By T-INTPCD, let

r' h pcdj : ûi.û'j .Ui. û".Vi. Vj'

,j/ T' h pcd2 : Û2 • «2 • 2 • û" • V2. V2'

Also let matchPCDU, pcdx,S) = n and matchPCDU, pcd2, S) - r2. By the definition of matchPCD:

matchPCDU,pcd,S) = b=(a,Po,...,px) => n # 1, r2 / _L, and = n ur2

Thus, all the consequents of the subclaim hold for pcdx and pcd2 Assume matchPCDU, pcd,S) = b =

(a,Po,---,Px}> let

H = («1,^0,1.••• A:,i>

r2 = (a2,A),2,...,A%,2)

and consider each consequent of the subclaim.

- By T-INTPCD, û-û\U w2. By the definition of u,

ii — _L ' U\ — _L — w2

=> «i = -,«2 = - by induction hypothesis

=> a = -u- = -by definition of w 130

On the other hand,

w ^ 1 => mi ^ _L or Û2 ^ -L, but not both

Without loss of generality, let Û2- ±

&i # _L and Û2 = -L => ai ^ -, a-i = - by induction hypothesis

=> a - a i ^ - by definition of u

So M = - <=> a = -, and (3.2c) holds.

- Similarly, û' = - <=> 0o = -, and (3.2d) holds.

- By T-INTPCD, U - U\ u U2. By the definition of u,

U = _L => U\ = ± = U2

=> a-1 = O = %2 bv induction hypothesis

=> x — 0 by definition of u

=> Vz e {!..%} • fii = -, vacuously

On the other hand,

U ï 1 => U\ ^ 1 or U2 ^ -L, but not both

Without loss of generality, let U2 = -L

U\^1 and U2- -L => xi -n,X2 = 0,3z £ {l..n} -/S^i 7^ -by induction hypothesis

=> x=n,Vie {l..x} -0, = by definition of u

=> 3z E {1..XÎ • Pi —

So {U — — => x — 0),{U^— ==> JC = n), and [U — — <=> Vz e {!..%} -/3, = —Thus, (3.2e), (3.2f),

and (3.2g) all hold.

- The above arguments also demonstrate that var{b) = var{r\) u varirz), since at each position

at most one of n and z"2 is not Thus, there are no collisions that could cause id to drop a 131

variable that appears in r-i. By the induction hypothesis, Vi ç var(r\) G V[ and V2 Ç uatir-i) G V2'.

By T-INTPCD,

V( n V2' = 0 => rar(ri) n varfo) = 0

=> 0hbOK

Thus, (3.2a) holds.

- Finally, T-INTPCD, the induction hypothesis, and some set theory gives

V' = V\ u V2 S var(r\) u rar(rg) = var{b).

and

var(b) - var{r\) u varirz) Ç V( u = V"

Thus, V e var{b) ç I/" and (3.2b) holds.

— pcd = ! pcd1. By T-NEGPCD F' h pcd: J I I L.0.0. By the definition of matchPCD,

matchPCDU,pcd,S) = = (a, 0o,...,fix) => b-{~,-}

=> 0hbOK

V' = 0Q var(b) Q0 = V"

û — J_ and a - - so (3.2c) holds

«' = 1and 0o = -so (3.2d) holds

U = -L and x = 0 so (3.2e) holds

U - .L so (3.2f) holds

C7 = 1and Vi e {1..0} • 0/ = - vacuously, so (3.2g) holds

Subclaim-H

By T-ADV, the assumption of the subclaim holds. Therefore, consequent 2 on page 121 holds by (3.2a).

Consequent 3 is more complex. To prove this consequent, it will suffice to show that

typeBind{Y,b, (to,...,tn)) = var\ : s\,...,varp:s'„ where Vi e {l..p} • s't =4 s/ (3.3)

We will see that this juxtaposition of £; in typeBind and sz- in the result is resolved by the pointcut descriptor 132 typing rules and matchPCD, which will impose constraints on the types. We use a final subclaim.

Subclaim 5. Assume h pcd : û. û'.U. û".V'. V", where V" Q {var\,...,var p}. Then

matchPCDU, pcd, S) = b /1

=> V var e var(b) • (3z e {l..p},s|. e .T • ( z/ar = vari, typeBind ( 1', b,(Z (l,((«r,- ) = and5- =<: s,))

Proof of subclaim. The assumption of this subclaim implies the assumption for Subclaim 4 on page 126; we will make free use of the earlier result.

— pcd = calL( ... ). By T-CALLPCD, V' = V" = 0. By (3.2b) on page 126, matchPCDU,pcd,S) = b ±

implies var[b) - 0, satisfying the subclaim.

— pcd = execution(... ). Similar to previous case, but by T-EXECPCD.

— pcd = this( t" var" ). By T-THISPCD, V' = V" - {var"}. By the subclaim assumption,

var" E {var\,...,varp}.

Without loss of generality, let var" - var\. By the hypothesis of T-THISPCD and the definition of l ',

t" = Si.

matchPCDU, pcd, S) = b^ 1 => b = (var\ — loc\,-)

for some loc\ in J, where

loci E dom(S) by J ~ S,

S (loci) = [.s-,. F], s\ ^ si, by definition of matchPCD, and

T (Zocj) = s[ by T « S.

Thus,

typeBind (T, b, (fa,... ,tn}) = i'ar\ : s, where 5j Sj.

— pcd = target( t" var" ). By T-TARGPCD, V' = V" = {var"}. By the subclaim assumption, var" E

{var\,...,varp}. Without loss of generality, let var" = var\. By the hypothesis of T-TARGPCD and 133

the definition of T', t" = s\.

matchPCDU,pcd,S)-b^± ==> b = van)

where to = t" by definition of matchPCD. So to — S] and

typeBind{Y,b,(to,...,t„)y- var\ :s\.

— pcd = args( t" var1). By T-ARGSPCD and the subclaim assumption, all var1! are unique

1 1 and V' = V" = {var ^ var ^} G {vari,...,varp}. Thus,

Vi £ {!.. • (3!j e {l..p} • [t'l - Sj and var" = varj)) (3.4)

The definition of matchPCD gives

matchPCDU,pcd,S)-b^± => b var'l,...,var"w)

where n-wand V i e 11..w} • (t'f = ti).So

J typeBind(T,b,{to,...,t„» = vat [ : t",...,vai"w\t"w

Let vare var[b). Without loss of generality, let var= var". Now

typeBind(f,b,{to,...,tn)) (var'l) = t".

By (3.4), there exists j such that var'I = varj and t'{ = sj, thus the subclaim holds.

— pcd - pcd] 11 pcd2. By T-UNIONPCD and the subclaim assumption, let

T' h pcd] : û]. û\.U). û'{.V]. V{ matchPCDU, pcd1 ,S) = n

r' h pcd2 : û2.û' 2.U 2 • û2 .V 2.V 2 matchPCDU, pcd2 ,S) = r2

By the definition of matchPCD,

matchPCDU,pcd,S) = b^ 1 => b = r\ ^ _L or b = r2 -L 134

So either

typeBind (T,M?o tn)) = typeBind (1,/',,{% tn))

or

typeBind {T,b,(to,...,tn)) = typeBind [T,r2,(to,...,tn)).

As noted in the corresponding case of the proof of Subclaim 4, Vj Q 1/" and V2 s V". Thus, we can

apply the induction hypothesis to the type derivations for pcd\ and pcd2, and the subclaim holds.

— pcd - pcd| && pcd2. By T-INTPCD and the subclaim assumption, let

r' h pcd| : à,. M|.(/]. û". Vi. Vj' matchPCD(f, pcd\, S) = r\

r' h pct/2 : Ù2. M2 .U 2. w". V2. V2' matchPCDU, pcd2, S) - ^

By the definition of matchPCD,

matchPCDU,pcd,S)-b^± => n # J. and r2 ^ 1

As argued in the corresponding case of Subclaim 4, var(r\) and var(r2) are disjoint. Also, since

V" = VJ U V2', we have VJ S V" and similarly for V2. Thus, the induction hypothesis is applicable to

the type derivations for pcdi and pcd2. Let rare va.r(b). By definition of the union of bindings, raris

in exactly one of rar(n) and rar(r^). In either case, the claim holds by the induction hypothesis.

— pcd = ! pcd{. By T-NEC,PCD and subclaim assumption, V' = V" = 0.

matchPCDU, pcd, S) = b ^ ± => b= (-,-)

=> var{b) = 0

Subclaim-d

With this last subclaim in hand we can now prove the final consequent of the lemma. The first two hypotheses of T-ADV (see (3.1) on page 122) are:

r' h pcd:^. UQ.(u\,...,Uq), u. V. V

V = {vari,...,varp} 135

By definition of adviceBind, \[b, loc, e, T, T'JI E B implies matchPCDU, pcd,5) / ±. We first use Subclaim 4

and Subclaim 5 to prove equation (3.3) from page 131.

V = {var\,...,var p} by T-ADV

=^> var{b)-{var\,...,varp} by(3.2b)

=> Vz e {l..p} -3sf £ 3~

[typeBind(T,b,(to tn))(vari) = , s'f 4 s,) by Subclaim 5

Thus, all var e V are bound appropriately. By examination of the definition of typeBind, we see that

dom(typeBind(T,b,{to,...,t„))) - var{b) -V.

Thus, no additional variables are bound and (3.3) on page 131 holds:

typeBind{T,b, (to,...,tn)) = van:s[,...,varp:s'p where Vz e ^ s,-

The third hypothesis of T-ADV gives

van '• s\,...,varp: Sp,this: a,proceed-.T11- e:s'

=^> var\-.Sy...,varp :s'p,this: a,proceeds'\-e:s" by Lemma 3.12

where s" =4 s and Vz e {l..p} • s't =4 sz-

=> this : a, proceed : T', typeBind{T, b, {to,.. .,tn)) V- e:s" by (3.3)

=> F, this: cz, proceed : T', typeBind {T,b,{to,...,tn}) h e:s"

where the last implication is by Lemma 3.3 (Environment Extension), with appropriate «-conversion of b

and e. Finally, the last hypothesis of T-ADV gives 5' s =4 u. By transitivity of subtyping, and u - t, s" t.

Thus the final consequent holds. • L

The following lemma states that advice chaining, replacing proceed expressions with chain expressions, does not affect typing judgments given the appropriate assumptions. These assumptions are essentially the hypotheses of the T-CHAIN rule, since advice chaining is performed by the ADVISE evaluation rule on chain

expressions. This lemma is used for the ADVISE case in the subject reduction proof.

I 1 Lemma 3.16 (Advice Chaining). Let T, proceed:! h e:t, j = (L,r = to* ...xtn — t, and for all

\[b, /oc, e',T',rJl e B let 136

— T,this: Y Hoc), proceed :t ,typeBind(T ,b,{to,...,tn)) h e':s',

— F h b OK, and

— s! ^ t.

Then F h ((e)) : t.

Proof. The proof is by structural induction on the type derivation for e. In the base case, the type derivation

for e is by one of T-NEW, T-OBJ, T-VAR, T-LOC, or T-NULL. For all of these rules e does not contain a

proceed expression. Therefore, ((e))g • = e and the claim holds by Lemma 3.4 (Environment Contraction)

on page 81.

The induction hypothesis is that the claim holds for all type derivations smaller than the one for e. For

all the remaining expression typing rules but T-PROC, the claim follows immediately from the induction

hypothesis. So the only interesting case is for

e- eo-proceed(ei,...,eR)and

(

Assuming that F, proceed: T h e: t, we need to show that F h ((e)) : t. The later must be by T-CHAIN, so we

must establish the hypotheses for that rule. Now the last step in the type derivation for e must be T-PROC:

V/ E {0..«! -T, proceed :T I- e, : U,- Vz e {0..rc} • M, ^ tj

T, proceed :T I-eo-proceed(ei,...,e n):t

By the hypotheses of this judgment and the induction hypothesis, we have:

: u Vz' e {0,.n] • F h ((e,))gj i where ut ^ f,

The remaining hypotheses of T-CHAIN hold by the assumptions of the lemma regarding B and j, thus

F h ((e))ÔJ: t. • i ! i

Finally, a simple lemma regarding join point abstractions will be useful in the subject reduction and

progress proofs.

I 1 Lemma 3.1 7 (Join Point Abstractions). InaMiniMAOi program evaluation, if a join point abstraction, j,

appears in the expression of an evaluation triple, then one of the following hold: 137

1. Either j = flexec, v,m,l,T\I andl = fun m(varo,...,varn).e:i, or else

2. j - ^call,-,m,-, (fox... xtn ->• f)D and methodType(to, m) = t\x ... x tn -> t.

Proof. Join point abstractions are not part of the user syntax of MiniMAOi- By inspection, the only eval­

uation rules that can introduce new join point abstractions in the expression of an evaluation triple are

EXECA and C/\i.[.;\. Only EXECA introduces exec join point abstractions, and these abstractions satisfy part

1 of the lemma. Only CALLA introduces call join point abstractions. By the definition of origType, these call

join point abstractions satisfy the part 2 of the lemma. • I I

The Subject Reduction theorem for MiniMAOi is essentially the same as for MiniMAOo, except that it requires and maintains stack-store consistency and stack validity. The proof is extended to account for the new evaluation rules.

I l Theorem 3.18 (Subject Reduction). Given a well typed MiniMAOi program, for an expression e, a valid

store S, a stack J consistent with S, and a type environment T consistent with S, ifT h e : t and (e,J, S> ^

{e',J',S'), then /' » S', S' is valid, and there exist F' and t' such thatT' = S', F' H e':t', and t' =$ t.

Proof. The proof is by cases on the evaluation rule applied. We note that the evaluation rules obey a

monotonicity property with regard to the store: none of evaluation rules remove a location from the

domain of 5, nor do they change the type of the object in any store location. Because none of the evaluation

rules inherited from MiniMAOo modify the stack, /' = S' for the proof cases corresponding to those rules.

Also by the monotonicity property, S valid implies that part 1 of Definition 3.14 (Store Validity) on page 121

holds for S'. Based on the reduction step we can construct a F' consistent with S' that witnesses to the

validity of S' and satisfies the claim. The cases for NEW, GET, SET, CAST, NCAST, and SKIP are unchanged

from the original proof of Theorem 3.7 (Subject Reduction) on page 84.

x Case 1—CALLA- Here e = E\loc.m( v\,...,vn )], e' - Etjoinpt deal I,-, m,-,(so ... xsn — s)D( loc,v i,...,v„ )]

(where S(loc) = [u.F], methodType{so, m) = x... xsn — s, and origType(u, m) = so), /' = J, and S' = S.

Let T' = F. Clearly F' = S' and /' = S'.

We now show that T\-e':t. The judgment F h e : t implies that loc.m{ v\ vn ) and all its subterms

are well typed in F. Let F h : r, for all i e By part 1(a) of F = S, F h loc : u. The type judgment for

loc.m( v\,...,vn) must be by T-CALL with Vz e {\..n) • ti ^ S, and F h loc.m( v\ vn):s. By the definition 138 of origType, u sy. T-JOIN gives:5

r h loc: u \/ie{l..n}-T\- Vj-.ti u^sq Mi e {l..n} • ti =4 s,

r h joinpt (|call,-,m,-,(sox... x$n — s)D( loc, v\,...,vn):s

Therefore, Lemma 3.5 (Replacement) on page 81 gives F I- e' : t.

Case 2—CALLB- Here e = Efchain •, ([call, —, m, —,T&( loc,vi,...,vn )], e' = E[( I ( loc,v\,...,vn ) )] (where

S(loc) = \t().F\ and methodBody{to,m) = /),/' = /, and S' = S.

Let T' = T. Clearly T' ~ S' and J' ~ S'.

We now show that r h e' : t. Let e|eft = chain •, flcallloc, vi,...,v„ ). The judgment r h e: t implies that g|eft and all its subterms are well typed. Let r I- v,: ti for all i e {1..n} and let F I- e|eft : s. By part

1(a) of F = S, F h loc: to. The type judgment for e\cjt must be by T-CHAIN with T of arity n + 1 and return

x type s. Let x - so* ... s„ — s. Then T-CHAIN gives tt =4 s/ for all i e {0..n}.

By Lemma 3.17 (Join Point Abstractions) on page 136, it must be the case that methodTypeiso, m) = s\ x... x sn — s. By the correspondence between the definitions of methodType and methodBody, and by

T-CLASS, T-MET, and override, it must be the case that

I = methodBody[to, m) =fun m

where to =4 u and r,this: u, vari : s\,...,varn\sn H e" : s' for some s' =4 s.

Thus, T-EXEC gives

r,this : u, vari :si,...,varn:sn h e" : s' s' =4 s

F h loc: to \/ie{l..n}-T\- Vi'.tj to =4 u Vz E \\..ri\ • f;- ^ s,

F h (fun m(this, var\,...,varn).e" : [u x sj x... xsn — s) ( loc, v\,...,vn)):s and Lemma 3.5 (Replacement) on page 81 gives T\- e' :t.

Case 3—EXECA. Here e = E[( I ( Vo,..-,vn))\ (where I = fun m(varo,...,varn).e" : (s0x ... xsn ->• s)), e' -

Eijoinpt flexec, vo,m,l,{sox... xsn — s)K vq ,...,vn)], J' = J, and S' = S.

Let T' = T. Clearly F' ~ S' and /' ~ S'.

5 1 omit the v0pt hypothesis because is not a location. 139

We now show that T\- e' :t. The judgment The:/ implies that (I (vo,...,v n)) and all its subterms are well typed. Let R I- vi : F,- for all i e |0..n}. The type derivation of ( I ( VQ,...,V„ ) ) must be by T-EXEC with T I- ( / ( VQ, ..., vn ) ) : s and F; =$ s,- for all i e {0..n}. If VQ is a location, then F h I/Q : TO must be by T-Loc, so VQ E dom{T). Thus, F h joinpt flexec, VQ, M,/,(SQX ... XS„ — S)D( VQ,...,V„ ):s by T-JOIN. Lemma 3.5 (Re­ placement) on page 81 gives T\- e' :t.

Case 4—Exscg. Here

e = E[chain •,flexec, v,m,l,{sox ••• *sn — s)K v0,...,v„ )]

I = fun m(var0,...,varn).e" :{s0x ...*sn — s)

e' — E[under e"lvo/ varo,...,vnl varn\}

F — flthis, VQ,—,—, — D + /

S' = S

Let T' = T. Clearly r' ~ S'.

We now show that / » S' = S. Let e|ef, = chain •, flexec, v, m, I, (so><... xsn — s)|)( vo,...,vn ). Because e is well typed, it must be the case that e\e^ and all its subterms are well typed. Let F H : ti for all i E

If t^o = null, then / » S because /' has no new location. On the other hand, if vq is a location, then the judgment r h vo : to must be by T-Loc with vq E dom{T). By F = S, we have vq E dom(S). Because / « S and

vq is the only potentially new location in /', we have that /' = S.

To complete the case, we will next see that F h e' : t' for some t' ^ f by appealing to the Substitution

Lemma. Rule T-CHAIN must be the last step in the type derivation for E|EFT with F h £>|et-t : s. The second hypothesis of T-CHAIN says that f,- =<: 5/ for all i e {0..n}.

It remains to be seen that F, vatQ : SQ varn :snh e" :u for some u =<: 5. No fun terms may appear in

user programs; they can only be introduced by the evaluation rules. By examination of the evaluation

rules, we see that the only rule that introduces a new fun term is CALLB- The term it introduces is provided

by the methodBody auxiliary function. By the definition of methodBody and by T-MET it must be the

case that varo : SQ,...,varn : sn h e" : u for some u =4 s. By «-conversion and Lemma 3.3 (Environment

Extension) on page 81 we have F, vara : so varn : sn h e" : u. Thus, by Lemma 3.10 (Substitution) on page 117, F h e"\val vai\),...,unl varn\:u' where u' -< u 4 s. So Lemma3.11 (Replacement withSubtyping) on page 119 gives T\- e':t' for some t' ^ t. 140

Case 5—BIND. Here:

e = Eljoinpt flfc, vopt,mopt,lopt,(sox • •• xs„ — s)D( vo,...,vn )]

e' = E[under chain BAk, vopt,mopt, lopt, (s0x... xs„ — s)D( vo,...,vn )]

x B = aduiceBindiflk, vopt, mopt, lopt, (s0 ... xsn — s)D + /,S)

/ = 0 k,Vo Pti wiofjtt loptr (-so* • ••* Sn > s) D + J

S' — S

Let r' = r. Clearly F' = S'.

We will see that /' = S'. Let = joinpt $k, vopt, mopt,l opt, (so x ... x — s)D( vo,.--,v„ ). Because eis well typed, it must be the case the e\e^ and all its subterms are well typed. The typing derivation for e]ct-t must be by T-JOIN with F h e|eft : s. Thus, if vopt is a location it must be in dom{T) and so / = S'.

It remains to show that F H e': t. Let E^ght = chain BJk, vopt, mopt, lopt, (SQ x ... x sn — s)P( vo,...,vn ).

(By T-UNDER, Erjg|.lt has the same type as under Erig^t, so we can focus on the smaller expression.) The typing judgment for E^IGHT must be by T-CHAIN. SO we next show that all the hypotheses of T-CHAIN are satisfied by e,-ight-

By the well-typedness of and its subterms, let F h i>i : t, for all i e \()..n\. By T-JOIN, we have F,- ^ sz- for all i E {0..»}.

The remaining hypotheses of T-CHAIN are related to the elements of the advice list, Ë. Let

B = flfo,Zoc,E",T,r'Jl be an arbitrary element of B. By the definition of adviceBind, it must be the case that there exists a piece of advice with aspect table entry (loc,pcd,e",t,t') such that matchPCD[J',pcd,S) - b # ±. By Lemma 3.15

(Binding Soundness) on page 121 we have:

t' = So X ... X Sn — s

0hbOK

F, this : F(Zoc), proceed : T\ typeBind{T,b,(so,... ,s„» h e" : s' for some s' ^ s

By appropriate «-conversion of b and e", we have F H b OK. The remaining hypotheses of T-CHAIN 141

are satisfied directly by the results of the lemma. Thus, F h ENG|LT : S and by T-UNDER and Lemma 3.5

(Replacement) on page 81, T h e' : t.

Case 6—ADVISE. Here

,Zoc, +B,j( vq vn )]

e' = E[under ((e"))SjlloclthisHivo,,vn)I b\]

f = dthis, loc, /

S' = S

Let T' = T. Clearly F' = S'. Because fl-Jl terms can only be added to a program by the auxiliary function adviceBind called by BIND, we know from the definition of adviceBind and the validity and monotonicity of S that loce dom{S). By F = S, we know loce dom[T). Thus, /' = S'.

It remains to be shown that T\-e':t' for some t' t. Let

e left = chain \[b, /oc,e",T,r'jj +B,j( vo,...,vn ) and

locl Bright = this[J (1*0,..., fn)/ b\.

Because e is well typed, we know that e\eft and all its subterms are also well typed. The type derivation for e|eft must be by T-CHAIN. Let the last element of j be to x... x tn — tc. Then by T-CHAIN the proceed type T' = to x... X tn — tc. From the hypotheses of T-CHAIN, we have

T, this : T(loc), proceed :(f0x...xt„ — tc),typeBind{T ,b,(to tn)) I- e":s

where s=4 tc-The constraints on B and j imposed by T-CHAIN satisfy the conditions of Lemma 3.16 (Advice

Chaining) on page 135, so we have

s F, th i s: F ( loc), typeBind (Y,b,(to,...,tn)} h «e">> '• (3.5)

Next we will appeal to the Substitution Lemma. To do so, we will need to expand typeBind so that we can demonstrate that the conditions for the lemma hold. Let b = (a,Poi--->Pp)- Assume a = var* — lod 142

6 and /30 = vara. Then (3.5) expands to

J h I\ this : Y {loc), vai : Y [loc'), {vari : ?i)/e{o..p}.,6,•=„«•; «e">> gj : s.

and the binding substitution in g^ight expands to give

((e"))È>jlloclth\s,loc/l va/Avil vari)i£{0„p].pi=var.\.

! Finally, by the hypotheses of T-CHAIN in the typing of g|eft we have VI £ {0..n} • (F I- v, : u't where u . ^ F,-).

: s Thus, Lemma 3.10 (Substitution) gives F h e^ght ' where s' =4 s =4 tc. By T-UNDER and Lemma 3.11

(Replacement with Subtyping) on page 119, The': t' for some t' 4 t.

Case 7—UNDER. Here e- E[under v], e' = E[v], J = j + / for some j, and S' = S.

Let r' = r.

Clearly F' = S'.Since the set of location is /' is a subset of those in J, ]' ~S'.

We now show that Yh e':t. The judgment Y\- e\t implies that under v is well typed. Let F h under v: t'.

This judgment must be by T-UNDER with the hypothesis R I- v : t'. So by Lemma 3.5 (Replacement) on

page 81, we have Y I- e' : t.

The remaining evaluation rules reduce e to an error condition and are not applicable to the theorem. • I I

The Progress theorem is slightly modified for MiniMAOi, to include the validity of the store. Additional proof cases are added for the new and modified evaluation rules.

I l Theorem 3.19 (Progress). For an expression e, a valid store S, a stack J consistent with S, and a type envi­

ronment Y consistent with S, if Y I- e:t then either:

— e- loc and loc E dom{S),

— e = null, or

— one of the following hold:

-

6The argument connecting typeBind to binding substitution is similar if a (resp. /3q) is but with typings and substitutions for var1 (resp. varo ) omitted. 143

- {e,],S} <•— (ClassCastException,J',S')

Proof. If e = loc, then F h loc: t by T-Loc. This means that loc e dom(T) and, since T ~ S we have loc e dom(S).

If e = null, then the claim holds.

Finally, when e is not a value we consider cases based on the current redex of e. Cases where the redex matches NEW, NCAST, SKIP, NGET, NSET, EXECA, NCALLA, and ADVISE are trivial. For the remaining cases we must show that the side conditions hold and the join point abstractions are of the correct form. The cases for redexes matched by GET, SET, and CAST are unchanged from the proof of Theorem 3.8 (Progress) on page 87.

Case 1—e = E{loc.m( v\ vn )]. Because e is well typed, F h loc: s for some type s. Thus, loce dom(Y), and part 2 of F = S implies loce dom(S). Let S{loc) = [s'.F], Now s' = s by part 1(a) of F » S.

Because loc.m( v\,...,vn) is well typed, we know by the hypotheses of T-CALL that methodType(s,m) yields an ra-arity method type. By the definition of origType, we know that origType{s, m) - to, where .s- ZQ.

By T-CLASS, T-MET, and override, we know that methodType[to, tri) also yields an n-arity method type.

Thus, (e,J, S) evolves by CALLA-

Case 2—e = E [chain È,j( vo,...,vn)]. If B is non-empty, then (e,J,S) evolves by ADVISE. Otherwise, we must consider cases based on the value of j. By Lemma 3.17 (Join Point Abstractions) on page 136, there are two cases:

— j = flexec, v, m,l,TD : By Lemma 3.17,1 = fun m(varo,... ,varn) ,b:t . Thus, (e,J,S} evolves by EXECB-

— j = flcalI,-, m,-,T|): There are two subcases. If VQ = null, then (e,J,S) evolves by NCALLB to a triple

with a NullPointerException. Otherwise, vo is a location. Because e is well typed we have F h VQ : u'Q

X x for some u'Q; this is by T-Loc with VQ E dom{T). By T » S, S(vO) = [U'q.F], Let T = ?O ••• tn —• t,

where the arity is zz -t-1 by T-CHAIN and the well-typedness of e. By Lemma 3.17, methodType{to, m) =

t\ x... x tn — t. Also by T-CHAIN, U'0 4 to. By the correspondence between methodType's definition

and that of methodBody, and by the definitions of T-CLASS, T-MET, and override, it must be the case

that there exists a fun term I such that methodBody(u'0, m) ~ I. Therefore, (e,J, S) evolves by CALLB

in this subcase.

Case 3—e = E\under u\. In this case, we only need to argue that the stack, J, is not empty. Note that under expressions are not part of the static syntax. These expressions are only introduced during the 144

evaluation of a program, by rule BIND, EXECB, and ADVISE. Each of those rules also pushes a join point

abstraction onto the stack. The UNDER rule removes the under expression and pops the stack. Thus,

the size of the stack corresponds to the number of under expressions present in the expression. The

presence of an under expression in the evaluation context implies that the stack is non-empty. Therefore,

(Elunder v],j + J,S)^ by rule UNDER. • I

Finally, the Type Safety theorem must be updated to consider the initial, non-empty store.

I Theorem 3.20 (Type Safety). Given a program P - decl\...decln e, with h P OK, and a valid storeS q, then

either the evaluation of e diverges or else (e,*, So)

— x- loc and loce dom(S),

— x- null,

— x = NullPointerException, or

— x - ClassCastException

Proof If e diverges then the claim holds. If e converges, then note that the empty stack is consistent with

any store and the validity of SO implies the existence of an initial type environment consistent with SQ.

The proof (by induction on the number of evaluation steps) is immediate from Theorem 3.18 (Subject

Reduction) on page 137 and Theorem 3.19 (Progress) on page 142. •

3.3 Related Work

No previous work deals with the actual Aspect] semantics of argument binding for proceed expressions and an object-oriented base language. Wand et al. [157] present a denotational semantics for an aspect-oriented language that includes dynamic-context pointcut descriptors. My use of an algebra of binding terms for advice matching is derived from their work. Their semantics binds all advice parameters at the join point instead of at each subsequent proceed expression. Their calculus is not object-oriented and so does not deal with the effects on method selection of changing the target object. Douence et al. [53] present a system for reasoning about dynamic-context pointcut matching. They do not formalize advice parameter binding and do not include proceed in their language.

Jagadeesan et al. [75] present a calculus for a multithreaded, class-based, aspect-oriented language. They omit methods, using advice for all code abstraction. The lack of separate methods simplifies their semantics, 145 but makes their calculus a poor fit for my study of reasoning in an Aspect!-like language. Also, their calculus does not include the ability of advice to change the target object of an invocation. In an unpublished paper

Jagadeesan et al. [74] add a sound, static type system to their calculus. My type system is motivated by that work, but extends it to handle the separate this, target, and args binding forms and the ability of advice to change the target object.

Masuhara and Kiczales [108] give a Scheme-based model for an AspectJ-like language. They do not include around advice in their model. They do sketch how this could be added, but do not address the effect on method selection of changing the target object.

Orleans [128] also presents a Scheme-based language, Fred, that includes some aspect-oriented features.

Essentially Fred allows programmers to write reflective predicates which are evaluated at every method call.

If true, these predicates trigger the execution of associated code. Fred does not try to model Aspect] per se, but only advice-like constructs. Lâmmel [89] also presents a core aspect-oriented calculus that models advice execution, but not Aspect] in particular. He uses "method call interception" to trigger advice at method call sites in the operational semantics. Neither of these studies considers changing target objects or the affect of that on method dispatch. Neither study considers execution join points.

Aldrich [8] presents a system called "open modules" that includes advice and dynamic-context pointcut descriptors with a module system that can restrict the set of control flow points to which advice may be attached. The system is not object-oriented, so it does not address the issue of changing the target of a method call, and it does not include state. Dantas and Walker [48] present a calculus for "harmless advice", based on an extension of the typed lambda calculus plus Abadi-Cardelli-style objects. They use a type system with "protection levels" to keep aspects from altering the data of the base program. In keeping with this non-interference property, they do not allow advice to change values when proceeding to the base program. I discuss this more in Section 4.5.

Bruns et al. [27] describe /uABC, a name-based calculus in which aspects are the primitive computational entity. Their calculus does not include state directly, but can model it via the dynamic creation of advice.

However, it is not obvious how such a model of state could be used in my study of aspect-oriented reasoning when aspects may interfere with the base program via the heap. Also, while their calculus does allow modeling of a form of proceed, it is difficult to see how it could be used to study the effects of advice on method selection.

Finally, their calculus is untyped and is not class-based.

Walker et al. [156] use an innovative technique of translating an aspect-oriented language into a labeled core language, where the labels serve as both advice binding sites and targets for goto expressions (used to translate around advice that does not proceed). While their work does consider around advice and proceed in 146 an object-oriented setting—the object calculus of Abadi and Cardelli [1]—it does not consider changing any arguments to the advised code, let alone the effects on method selection of changing the target object of an invocation.

3.4 Discussion

As noted in Section 3.2.2.3, because of the lack of constructors, there is no obvious mechanism in MiniMAOi for initializing the state of the implicitly instantiated aspects.

The meta-theory for MiniMAOi only relies on having a valid store. Thus, one can reason about the language by assuming a store where aspects have already been initialized. Because of this, I choose not to complicate the calculus further by adding a mechanism for aspect initialization. For the reader's edification, I sketch here how such a mechanism might be added. The basic idea is to lazily initialize an aspect instance at the start of every advice body. A full-scale language like Aspect! has constructors, so this mechanism would not be necessary there, but could still be used.

The problem for lazy initialization in MiniMAOi is that there is no way to check whether an aspect is already initialized. Polymorphic method dispatch is the only branching mechanism in the language. An uninitialized aspect has null-valued fields, so there are no objects on which to dispatch. My proposed solution would be to add a simple if expression to the calculus for branching based on whether or not a value is null. The expression would have the form

if ( eo == null ){e\} else { % } -

A new evaluation context, evaluation rule, and typing rule would also be needed. These would be:

IE:: =... | if ( E == null ) { e } else { e }

e\ if v = null (E[if ( v == null ) { e\ } else { ez } ],S,/) <— (E[e'],S,/), where e' = < 62 otherwise

Vz £ {0..2} - F h ef.st s\ =4 t % 4 f

T I— if ( eo == null ) { e\ } else { % } : f

The updates to the meta-theory to add this expression form would be straightforward. I leave them as an exercise for the reader. 147

3.5 Conclusion

In this chapter I introduced MiniMAOi, a core calculus for Aspect], MiniMAOi faithfully explains the semantics of AspectJ's around advice at method call and execution join points. In particular, MiniMAOi is the first aspect-oriented formalism to model the possibility that advice can change the target object at a join point and affect method dispatch. MiniMAOi models the fact that in Aspect], advice that changes the target object at a call join point may change the method dispatched to, while advice that changes the target object at an execution join point will not affect the dispatched method. The semantics supports this ability by breaking the processing of method calls into several steps: (i) creating the join point for the call, (ii) finding matching advice, (iii) evaluating each piece of advice, and (iv) finally creating an application form. Since the target object is not used to determine the method called until step iv, a piece of advice can change the target by passing a different object in a proceed expression. Such a change affects method dispatch by potentially changing the application form created.

The application form created in step iv of the method call sequence is processed through a similar four-step sequence modeling method execution. In the fourth step of this sequence, arguments provided by the last piece of advice are substituted for formal parameters in the application form generated by the method call sequence. A new target object provided by execution advice will replace any this expressions in the application form. In this way, execution advice may change the "self" object used, but does not affect method dispatch.

This four-step sequence, used for method call and execution in MiniMAOi, is a general technique. It separates advice binding and advice execution from the primitive operations in the base language. This simplifies the modeling of join points for any primitive operation.

MiniMAOi faithfully models the binding of formal parameters in advice to the target, self, and argument objects at a join point. It uses the notion of a binding term, derived from a pointcut description, to perform this binding. This modeling of binding, plus the imperative nature of the calculus, provides the foundation necessary to investigate both the power of my proposed assistant aspects and my proposed restrictions on spectator aspects.

Aspect] is not statically type safe [74]. With MiniMAOi, I demonstrate that the type safety problems extend to, and are exacerbated by, the ability to change target objects in advice. To provide a solid foundation for formalizing the reasoning issues that I am concerned with, MiniMAOi changes advice matching and pointcut typing to provide static type safety. The concept of binding soundness, introduced here, is instrumental in proving the soundness of my static type system. MiniMAOi s sound static type system is a first for a language with such powerful around advice.

MiniMAOi uses a different semantics for advice binding than Aspect], using exact type matching rather 148 than subtype matching in many cases. The semantics in MiniMAOi causes pointcut descriptions to match a subset of the join points matched using the Aspect] semantics. MiniMAOi's more limited matching semantics is necessary for static type safety.

The typing of proceed and the various pointcut descriptors in MiniMAOi also differs from Aspect]. The typ­ ing of proceed expressions in MiniMAOi corresponds to the type of the method being advised, instead of being related to the type of the advice's formal parameters. This contributes to a simpler and more understandable semantics for proceed.

In the next chapter I build on MiniMAOi, introducing new type system features that help to distinguish, and reason about, spectators and assistants. 149

CHAPTER 4. MiniMA02: PARTITIONING THE HEAP BY

CROSS-CUTTING CONCERNS

In this chapter, I extend MiniMAOi with "concern domains" and read-only pointers. I call the new calculus

MiniMAC>2 •

Informally, concern domains represent a partitioning of the heap into sets representing orthogonal, or cross-cutting, concerns. Concern domains in MiniMAOi allow cross-cutting concerns to be represented in

the type system. MiniMAOg enables efficient static detection of tangled code by lifting cross-cutting concerns from the program implementation into the type system.

A global configuration declares the concern domains that may be used to partition the heap. Thus, the

programmer controls which actual concerns are expressed in the type system. The signatures of declarations in the calculus, along with object instantiation expressions, determine the actual partitioning. The type system

enforces a non-interference property so that a global, signature-level search can identify all the code that

might mutate a particular concern domain. By "signature-level", I mean that only method and advice headers,

and not their bodies, must be considered. This global search is related to the global configuration informally

argued for by Kiczales and Mezini [80]. As discussed in Chapter 2, in a language with concern maps and explicit

acceptance of advice, the search scope could be further narrowed.

MiniMAOa's type system statically detects code tangling, based on a separation of concerns defined by the

programmer. Aspects in MiniMAOg are assistants; they may interfere with the concerns of the base program.

However, in MiniMAOi this interference must be declared in the advice, and so is easily identified. The

subsequent chapter describes how we can formally define spectator aspects that are statically known to not

affect the concerns of other code.

In addition to concern domains, MiniMAOg also has read-only pointers. These serve two purposes: practi­

cally, they provide a mechanism for formalizing spectators in the subsequent chapter; theoretically, they serve

as a proxy for the reasoning issues involved in combining more general alias-control type systems with an

aspect-oriented language. 150

The type system for MiniMAOg is inspired by the various ownership type systems for object-oriented languages [9,10, 25, 35,116, 117, 118,121]. It is also similar to the "Harmless Advice" system described by

Dantas and Walker [48], though the type system of MiniMAOg provides more fine-grained control to the programmer. For example, unlike harmless advice, aspects in MiniMAOg may be given permission to mutate data from the base program.

4.1 Intuition

Perhaps the best way to develop an intuition for MiniMA02 is to consider the store of the calculus as representing words in memory. The concern domains declared in a MiniMAOg program partition these words into sets. This partitioning is formalized in Definition 4.20 (Concern Domain) on page 231. Figure 4.1 gives a schematic view of this intuition. The cloud-shaped outlines in the figure represent two concern domains, one for Products and one for People.

An object record in the store can be thought of as a contiguous of words, all of which must appear in the same domain. Each of the rounded rectangles in the figure represent an object record. As in MiniMAOi, each object record describes the object's type and its fields. Object types in MiniMAOi include a type like that in MiniMAOi, naming the class or aspect of which the object is an instance. The object type in MiniMAOg also includes a sequence of concern domain names. The first name in this sequence is the home domain of the object (see Definition 4.28 (Home Domain) on page 236). The remaining names say which domains the object may access, either through method calls or field accesses. In Figure 4.1 on the following page, the Book object is in the Products domain, and may also access the People domain. The remaining objects in the figure may not access any objects in other than their home domains.

The devalues stored in an object's fields can be thought of as pointers to other blocks of memory repre­ senting other object records. For example, the locT pointer for the title field in the Book object points to a

StringBuffer object, also in the Products concern domain. It is also possible for a pointed-to object to be in a different domain than the field itself. The authorl field in the Book object demonstrates this. While the field itself is in the Products domain—the home domain of its object—the value stored in the authorl field points to an Author object in the People domain. Such interdomain pointers are only allowed to domains named in the object's type. For example, the Book object in the figure could only store pointers to objects in its home

Products domain or to objects in the People domain.

As for object records, each field in MiniMAOg has a type like that in MiniMAOi and a sequence of concern domain names. The first name in this sequence specifies the domain of the object to which the field points.

For example, the authorl field in Figure 4.1 has the type Author(People). Products locP locT [Book.{ |StringBuffer.{ title » locT, authorl locAl, author2 locA2,

People

locAl

[Author. name » locN, locN [StringBuffer.{

locA2

Figure 4.1 Schematic View of a Store in MiniMAO] 152

I will occasionally find it useful in this chapter to refer to public concern domains. In MiniMAOg, all concern domains are public. But in the subsequent chapter, I introduce private concern domains. A private concern domain can only can be named within the aspect that declares it. Such concern domains provide an encapsulated region in the heap. No pointers into a private concern domain may escape the declaring aspect.

But again, all of the concern domains dealt with in the present chapter are public.

Besides concern domains, MiniMAOz also includes a notion of read-only fields. Each field in MiniMAOg may contain either a read-only pointer or a write-enabled pointer. If a field is marked as readonly, then code is not allowed to dereference the field and mutate the object to which that field points. This restriction does not prohibit the field itself from being changed to point to a different object. For example, consider the authorl field of the Book object in Figure 4.1. If this field were read-only, then code could change the value stored in the field within the Book object record. This is allowed because that would just involve changing the Book object record. However, code could not dereference the field and mutate the Author object to which the field points.

A key property enforced in MiniMAOz is that all interdomain pointers, such as those from the Book object to the Author objects in the figure, must be read-only. The static type system of MiniMAOz ensures that this property holds for any valid store occurring in the evaluation of a well-typed program. Thus, I was a bit misleading when I said above that the authorl field has the type Author(People); it must actually have the type readonly Author(People). In the subsequent chapter, this property of interdomain pointers will be central to my argument that unseen spectator aspects may not affect the behavior of an operation with respect to the writable domains of that operation.

4.2 Syntax

The syntax of MMMAO2 extends that of MiniMAOi. The essential changes are the introduction of:

— public concern domain declarations, naming the concerns present in a program;

— concern domain arguments on class instantiations and aspect instantiation instructions, placing the

instances in particular domains and allowing multiple instances of a single aspect;

— refined types, adding concern domain parameters and read-only annotations that make the cross-

cutting concerns and concern interference of the program explicit;

— effects clauses on methods and advice, describing the domains that may be modified if the body of the

method or advice is evaluated; 153

— writes pointcut descriptors, allowing advice to bind to a method based on the domains that the method

might modify; and

— domain dependency declarations in aspects, making the interference of aspects and the base program

explicit.

In this section, and the subsequent ones on semantics and meta-theory, I include the full calculus in figures and proofs, instead of just showing the changes versus MiniMAOi. Hopefully, complete figures make the reader's task easier, reducing page flipping. I provide full versions of the proofs because of the subtle interaction of the new and old features. To avoid too much tedium of detail in the discussion, I will focus on the changes versus

MiniMAOi » and the interaction of new and old features where appropriate.

Figure 4.2 on the next page gives the syntax of MiniMAOg. The following subsections describe the six essential changes. Figure 4.3 on page 155 gives a fragment of a MiniMAOi program illustrating the new syntax.1

4.2.1 Public Concern Domain Declarations

MiniMAOg extends program declarations, denoted by the meta variable P, with public concern domain declarations and aspect instantiation instructions. The latter are described in Section 4.2.2. Public concern domain declarations have the simple form domain g;, where the metavariable g ranges over the set # of valid concern domain names. I leave this set unspecified, but use legal Java identifiers in examples. A program may have zero or more public concern domain declarations. The sample program in Figure 4.3 declares five public concern domains, beginning on line 39: a domain for the main (driver) class of the program, a domain each for objects related to products and people, and two "logger" domains that are used for aspects.

4.2.2 Class and Aspect Instantiation

Class and aspect declarations in MiniMAOi are polymorphic with respect to concern domains.

A class declaration in MiniMAOg lists, following the class name, the concern domain variables that are in scope for the remainder of the declaration (see line 1). The first concern domain variable listed, home in the example, represents the home domain for instances of the class (as described in Section 4.1, and formalized in Definition 4.28 (Home Domain) on page 236). The remaining concern domain variables (what and who in the example) are used to endow instances of the class with permission to access objects in other domains. The extends clause of a class declaration specifies the mapping of the concern domain variables to those of the superclass. For simplicity, the sequence of concern domain variables for the superclass must be a prefix of the

1 For conciseness, I take some liberties in the sample program. In particular, I treat integers, strings, and string concatenation as built-in features of the language. 154

P:: = decl* { domain* asp* e } declv. = class c(G*> extends c(G*) {field* meth* } \ aspect a{G*) { dep* field* adv* } field:: = t /; meth:: - t m(form* ) eff { e }

dep:: = Y varies with 7; adv.: - t around {form* ) eff : pcd { e }

eff::- writes (7*)

pcd:: = call( pat) | execution(pat) \ writes( 7* ) | this(/orm) | target(form) | args(form* ) I pcd && pcd I ! pcd I pcd \ \ pcd pat:: = t idPat(..)

form ::-t var, where var 5^ this

e::- new c<7*)() | var | null | e.m( e* ) \ e.f I e.f = e | cast te \ e; e I e.proceed(e* ) t,s,u:: = S* 7(7*) ô::-£ I readonly, where e represents the empty string T,S::-c \ a j:: = g I G domain:: - domain g; asp:: - use a{g*);

G G (Spar, the set of concern domain variable names g e CS, the set of concern domain names c, d e the set of class names aesé, the set of aspect names /E^, the set of field names m E .M, the set of method names var E {this} u Y, where ~V is the set of variable names id Pat £ JP, the set of identifier patterns

Figure 4.2 Syntax of MiniMA02 155

class Main(home, what, who) extends Object(home) { Book book;

4 readonly Object(home) run() writes (home, what, who) {

5 this.book = new Book(what, who)(); this.book.initQ; 6 this.book.setTitle("The Long Dark Tea Time of the Soul");

7

8 }

9 }

10 class Book(home,author) extends Object(home) { il StringBuffer(home) title; 12 readonly Author(author) authorl;

13 readonly Author(author) author2;

14 15 readonly Object(home) setTitle(String(home) newTitle) writes (home) { lb this.title.setLength(O); this.title.append(newTitle)

17 } 18 }

19 class Author(home) extends Object(home) {

20 StringBuffer(home) name; 21 readonly Object(home) setName(String(home) newName) writes (home) { this.name.setLength(O); this.name.append(newName) } }

aspect Logger(logger, loggee) { logger varies with loggee; 28 StringBuffer(logger) log;

29 readonly Object(loggee)

30 around(String(loggee) newVal, StringBuffer(loggee) targ)

31 writes (logger, loggee) : call(readonly Object(loggee) append(..)) && args(String(loggee) newVal) && target(StringBuffer(loggee) targ) && writes(loggee) {

34 this.log.append("Setting " + targ + " to " + newVal);

35 targ.proceed(newVal)

36 }

37 }

38 {

39 domain Main; domain Products; domain People; domain ProductLog; domain PeopleLog; use Logger(ProductLog, Products); use Logger(PeopleLog, People);

44

45 new Main(Main,Products,People)().run(); 46 }

Figure 4.3 Fragment of a MiniMAOg Program Illustrating New Syntax 156 sequence for the subclass. This could be relaxed in a practical language, but the strict correspondence avoids some unnecessary complexity in the core calculus. Aspect are declared similarly to classes (see line 26).

Iextend the object instantiation instruction, new, in MiniMAÛ2 to include concern domain arguments

(see line 45). The static type system ensures that new expressions within the main expression of a program only use the names of declared, public concern domains. Furthermore, new expressions within a method or advice declaration must only use concern domain variables that are in scope. When the body expression of the method or advice is evaluated, the concern domain variables will be replaced with the concern domain names used to instantiate the self object of the evaluation. For example, the new expression in line 5 uses the concern domain variables what and who, which are in scope from the declaration of Main. When the run method is called on the instance of Main created in line 45, these concern domain variables will be replaced with the concern domain names Products and People.

As in MiniMAOi, new expressions are syntactically restricted to creating class instances, not aspects. So, what concern domains should the semantics use for creating aspect instances? My answer is to add aspect instantiation instructions to MiniMAOi. These instructions, denoted asp in Figure 4.2 on page 154 and written use a(g,...), appear in the program declaration, following the concern domain declarations and preceding the main expression of the program. The sample program has two aspect instantiation instructions, beginning on line 42. Aspect instantiation instructions are like new expressions, in that they create objects and specify the concern domains to be used. However, aspect instantiation instructions are not part of the expression syntax.

MiniMAOg uses the aspect instantiation instructions only to generate the initial store for a program evaluation.

Additional aspects cannot be instantiated during program evaluation. (This ensures that all aspects that might affect a calculation may be statically identified.)

MiniMAOg no longer restricts programmers to a single instance of each aspect. Instead, they can explicitly instantiate aspects and assign them to particular domains. Because writes pointcut descriptors in advice declarations, described below, use concern domain variables, a programmer could instantiate an aspect for monitoring changes to a particular domain. The sample program illustrates this. The program creates two instances of the Logger aspect. By virtue of substitution of concern domains names for concern domain variables, one of these instances will bind advice to StringBuffer updates in the Products domain (see the advice declaration beginning on line 29). The other will bind advice to such updates in the People domain.

Although MiniMAOz does not have a module system to provide scoping, the aspect instantiation instruc­ tions can be thought of as a degenerate form of the concern maps introduced in Chapter 2. The instructions specify all the aspects that one must consider when reasoning about the program. It would be technically straightforward, though notationally complex, to extend the operational semantics to support modules and the 157 scoping of aspect instantiation. I say that this would be technically straightforward, because the current type system already checks each class and aspect separately, without relying on the aspect instantiation instructions.

Thus, the only technical issue would be to design the operational semantics to match advice based on just the aspect instances which are applicable according to the concern maps.

4.2.3 Refined Types

As discussed in Section 4.1, MiniMAOg adds read-only status and concern domain information to types. As in MiniMAOi, the meta variables t, s, and u range over types. But in a MiniMAOi program the set of types is

3~={8 1!,

where the meta-variables 5, T, and y are such that:

— 5 is either readonly or the empty string (denoted e),

— T ranges over the set of valid class and aspect names ('<$' u si), and

— 7 is either g, which ranges over the set of valid concern domain names, or else G, which ranges over the

set of valid concern domain variables.

The sample program includes several of the new types. For example, line 2 declares a field named book. An object stored in this field must be an instance of the Book class (see line 10). Furthermore, the concern domains of the Book instance must match the second and third concern domains of the Main instance. To be concrete, the instance of Main created in line 45 could hold in its book field an instance of Book with concern domains

Products and People.

As shown in Figure 4.2 on page 154, a type may include zero or more read-only annotations, Ô. I treat zero annotations as equivalent to a single e annotation. For multiple annotations, if any one of them is readonly I treat this as equivalent to a single readonly annotation. Otherwise, I treat multiple e annotations as a single one.

Allowing multiple S annotations on types is something of a hack. The readonly annotation is idempotent—one readonly is as good as a dozen. The hack is useful in the static semantics where I can write "readonly t" to confer read-only status to the type t regardless of whether or not it is already read-only. (See the fieldsOf auxiliary function, in Figure 4.9 on page 167, for an example of this.) 158

4.2.4 Effects Clauses

In most languages, the side effects of a method or advice body on the store can only be determined by analyzing the code of the method or advice, and that of any methods called, or advice triggered, by that code.

Some languages have added support for "modifies" clauses, which describe the state that may be changed by a method [22, 97, 99,100,104,118,159].

MiniMAOg adds effects clauses, written writes {j\ y„), to the declarations of methods and advice (see line 15 and line 29 of Figure 4.3 for examples). These effects clauses indicate all the concern domains that might be modified when the code of the method or advice is evaluated. The static type system of MiniMAOg ensures that no other domains may be modified at evaluation time (modulo domain dependencies, described below).

Effects clauses are written using the concern domain variables of the host class or aspect. The actual concern domains that may be modified at evaluation time are thus a function of the concern domains used to instantiate the class or aspect that is the "self" object of the method or aspect evaluation.

4.2.5 New Pointcut Descriptor

The presence of effects clauses gives another mechanism for matching advice in MiniMAOz. The new writes pointcut descriptor allows advice to match any method whose effects clause lists a particular set of concern domains. Consider the writes pointcut on line 33 of the sample program. The pointcut uses the loggee concern domain variable. Based on the aspect instantiation instructions in the example, one instance of the

Logger aspect will monitor matched methods that may write to the Products concern domain, while the other instance will monitor matched methods that may write to People.

For soundness of the static type system, we will see that the domains listed in the writes pointcut descriptor must exactly match the writable domains of the advised code. This restriction, and other matching restrictions are relaxed for spectators in the subsequent chapter. These relaxations make "concern-domain generic" aspects, like Logger, more practical.

As far as I know, MiniMA02 is the first language to propose a pointcut descriptor based on the statically verified side effects of the matched join point.

4.2.6 Concern Domain Dependencies

Finally, MiniMAC>2 adds concern domain dependency declarations to aspects. These declarations allow an aspect to declare that one concern domain may be modified when code that is declared to modify another domain is executed. These dependency declarations allow aspects to modify other domains besides those 159 written by some advised code. They also allow—thanks to the aspect instantiation instructions—a static analysis of what other domains might be modified.

For example, line 27 declares that the home domain of the aspect may vary with the second domain.

So for the aspect instance with type Logger(ProductLog,Products), the advice can mutate its own state (in the ProductLog concern domain) when advising a method that is supposed to mutate the Products domain.

In a full language with concern maps, this dependency declaration would also be useful. It would tell any classes accepting the aspect that a method that mutates Products might also trigger aspect code that mutates

ProductLog.

4.3 Semantics

4.3.1 Operational Semantics

The main changes to the operational semantics of MiniMAOi versus MiniMAOg are for tracking concern domains in the store, read-only status of values, and the writable concerns for methods and advice. Most of the changes are only to simplify the type safety proof by letting the operational semantics do some of the symbol shuffling needed for the subject reduction proof. Other changes are an important part of the evaluation, because they are used for matching the new writes pointcut descriptor.

4.3.1.1 Extensions to the Syntax

Figure 4.4 on the next page gives the extensions beyond the user syntax that MiniMAOg uses for maintaining the machine state. Again, I just discuss the differences from MiniMAOi.

The value expressions in MiniMAOi, loc and null, bear subscripts indicating whether the pointer is read­ only. (The subscript on null is just for consistency.) The read-only status of a value is used in the evaluation for type casts and for type matching in advice. The status is also important for some proofs of the meta-theory

(see Section 4.4.3.2 in particular). As with the types in Figure 4.2 on page 154, readonly subscripts on loc and null in the operational semantics may appear multiple times and are idempotent. In the sequel, when I write

"pointer", I mean a loc value.

MiniMAOg adds an entirely new expression form, called a tagged expression, of the form (e)grf. This expression is used in the evaluation rules for method and advice bodies. The 5 subscript indicates the read­ only status to be given to the value that results from evaluating e (assuming the evaluation does not diverge).

The f subscript gives the set of domains that are writable during the evaluation of e. The meta variable f ranges over all possible sets of concern domain names and concern domain variables. It is used solely for the 160

Syntax extensions:

e :: = ... | locs* | nullô» | (l(e* )) | (e)Sif |

joinpt j( e* ) | under e | chain B,j( e* )

1 : = fun m(var*).e:r.f B : = B+ Ë |• loc e if, the set of store locations

B : = \ib,loc, e,f,T,Tj] &eS§, the set of advice parameter bindings b g e i 1 I 1 a u f E0»(#U*Mar)

P := var | - I X X I T î

V : — locg* | nulls*

Evaluation contexts:

E:: = - | E,m(e...) | v.m( v...Ee...) | ( I ( v...Ee... ) ) |

cast t E I E.f I E; e I E.f = e \ v.f = E I ô,f I

joinpt j( v...Ee... ) | under E I chain B,j{ v...Ee... )

Objects:

o:: = [t.F]

Figure 4.4 Syntax Extensions for the Operational Semantics of MiniMAOa subject reduction proof. MiniMAOg also uses an additional evaluation context for tagged expressions.

The writable domains meta variable, f, also appears in the fun form, I, and the advice body tuple, B, where it represents the writable domains of the method or advice respectively. Join point abstractions in MiniMAOg also get an optional writable domains entry (see Figure 4.5 on the next page); optional, because not every kind of join point abstraction includes this information.

Objects in the store in MiniMAOa have the same general form as in MiniMAOi: \t.F\. But, as discussed in

Section 4.2.3, the type t carries concern domain information. A property of the evaluation relation is that no

type, t, in an object record is marked read-only. Read-only status is a property of a pointer, not of the object in the store. Multiple pointers to an object may exist in an evaluation, only some of which are read-only. 161

/: = ;' + /!•

m )• = d k, V0pt, opt> lopt>Topt>fopt§ k: = call | exec | this Vopt : = v | - wiopt • = 171 | - lopt : = / 1 - T opt = T | - Y opt : = 7 1 -

Figure 4.5 Join Point Stack in MiniMAOa

4.3.1.2 Evaluation in MiniMA02

PROGRAM EVALUATION Program evaluation in MiniMAOa begins with the triple (e, »,So>, where e is the main expression of the program and So is a valid initial store containing aspect instances formed according to the aspect instantiation instructions. The notion of a valid store is formalized in Definition 4.5 (Store Validity) on page 186.1 also use a global class table, CT, and a global advice table, AT, as in MiniMAOj.

The advice table in MiniMAOg is constructed differently than in MiniMAOi to account for the aspect instantiation instructions. As in MiniMAOi, AT consists of re-tuples recording information for each piece of advice, but MiniMAO^ replaces the 5-tuples from MiniMAOi with 6-tuples. Figure 4.6 on the next page shows a sample aspect declaration, along with two aspect instantiation instructions and the corresponding advice table entries. As in MiniMAO] , the recorded information includes the location of the advice's aspect instance in the store, the pointcut descriptor of the advice, the advice body expression, and two function types representing the formal parameter types and return type of (1) the advice and (2) any proceed expressions appearing within the advice body expression. In MiniMAOg, any concern domain variables appearing in this information are replaced with the appropriate concern domain names from the aspect instantiation instruction. Thus in Figure 4.6, the first advice table entry refers to the ProductLog and Products concern domains, while the second refers to People Log and People. The additional piece of information, new in MiniMAOg, is the set of writable domains declared for the advice, again with concern domain variables reified.

EVALUATION RULES Figure 4.7 on page 164 gives the normal evaluation rules for MiniMAO^, i.e., the rules that do not lead to an exception state. Figure 4.8 on page 165 gives the exceptional rules. Nearly every normal rule requires some modifications from its MiniMAO i version, whether to record concern domain information or to shunt about read-only annotations and writable domains sets. Only the SKIP, BIND, and UNDER rules 162

Example aspect to be Instantiated:

aspect Logger(logger, loggee) { logger varies with loggee; StringBuffer(logger) log;

readonly Object(loggee) around(String(loggee> newVal, StringBuffer(loggee) targ) writes (logger, loggee) : call(readonly Object (loggee) append(..)) && args(String(loggee) newVal) && target(StringBuffer(loggee) targ) && writes(loggee) { this.log.appendf'Setting " + targ + " to " + newVal); targ.proceed(newVal) } }

Advice table entries:

Aspect Instantiation Instruction Advice Table Entry, ( loc, pcd, e,f,T , T ) < loci, callfreadonly Object(Products) append(..)) && args(String(Products) newVal) && target(StringBuffer(Products) targ) && writes(Products), use Logger(ProductLog, Products) (this.log.append("Setting " + targ + " to " + newVal); targ.proceed(newVal)), {ProductLog, Products}, String(Products) x StringBuffer(Products) — readonly Object(Products), StringBuffer(Products) — readonly Object(Products) > ( loc2, call(readonly Object(People) append(..)) && args(String(People> newVal) && target(StringBuffer(People) targ) && writes(People), use Logger(PeopleLog, People) (this.log.append("Setting " + targ + " to " + newVal); targ.proceed(newVal)), {PeopleLog, People}, String(People) x StringBuffer(People) — readonly Object(People), StringBuffer(People) — readonly Object(People)

>

Figure 4.6 Example of Advice Table Construction 163 are untouched. (The pointcut matching function, matchPCD—indirectly used by BIND through its call to adviceBind—does change, however. This change is described in Section 4.3.1.2.) Below I describe the sorts of changes needed for the other rules and note the rules where those changes are made.

Adding concern domains to objects in the store The NEW rule uses the concern domain names from an object instantiation expression when creating an object record in the store. As discussed above, object types in the store, which can only be added by the NEW rule, are never read-only. Because the object types in the store carry concern domain information, when an object type from the store is passed to an auxiliary function, the domain information is available.

As in MiniMAOi, the semantics of MiniMAO^ allows advice to change the target of a method, either before method lookup or else after method lookup but before method execution. In the latter case, the CALLB rule constructs the execution expression that represents the looked-up method. Examining the definition of the methodBody auxiliary function, in Figure 4.9 on page 167, one notes that the domain variables in the method body are replaced with the concern domain names from the target of the call operation. Does this create problems if advice later changes the target object? Thankfully, the answer is no. This is because the type rules only allow a subtype to be substituted for the target object, and the subtyping relation is "positionally invariant" in concern domains (see Figure 4.11 on page 169).

Tracking read-only status Several rules in MiniMAO] use the type of an object from the store during evaluation. Because read-only status, added in MiniMAO^, is an attribute of a pointer, rather than the refer­ enced object, several rules change to combine the read-only status of a location in the evaluation with the type of the referenced object from the store. For example, consider the call to the origType auxiliary function in the

CALLA rule. Here the read -only status, 5, of the target object location, loc, is combined with the type, t, of the object record at S(loc). By the definition of the origType auxiliary function, if ô here is readonly, then r0 must also be read-only (see Figure 4.9 on page 167). So the read-only status of the target object flows through to the function type, T, stored in the join point abstraction.

A similar change, combining a location's read-only status with a type from the store, is made in CALLB,

GET, CAST, and NCAST.

Also, the CAST rule, and the newly added NCAST rule, do not permit a readonly annotation to be "cast away"—any read-only annotation on the target of the cast survives in the result expression. The new NXCAST exceptional rule handles the cases not matched by the NCAST rule.

The EXECB and ADVISE rules initiate the "execution" of a method or advice body expression. In MiniMAO], this involved instantiating the expression (by substituting actual arguments for formal parameters), pushing a 164

(E[new c{gi,...,gn}()],J,S) • (E[loc], J,S® [loc-* [c{gi,...,g„).{f ^ rtu\\- f e dom{fieldsOf[c(gi,...,g„)))}})) NEW where loc C dom{S)

(E [locg.m{ vi,...,vn )],/,S)<— (Eljoinpt (call,-,m,-,T,fP( locg, v\,...,vn)\,J ,S) CALLA

where S(loc) = [f.F], methodType{to, m) — t\ x... x tn —• t', writableito, m) = f

origlypeiô t,m)-to, and T = tox... x tn t'

([[chain •,(call,-,M,-,T,fD( locs,v\,...,vn )],J,S)

"—(£[(/( locg, V\,...,Vn))],J,S) CALLB where S(loc) = {t.F] and methodBody{5 t,m) = I

where I = fun m(varo,...,varn).e:T .y (E[chain «, (exec, v,m,l,T,y\s{ VQ,...,V„ )],] ,S)

— plunder {elvQ/ varo,...,vnl varn\)5iyf\,j + J,S^ EXECB

where I = fu n m{varo,. • •,var n >.e : T . y, readonly(r) = 5', and j = (this, VQ,—,—,—,—I

(E[locô.f],J,S}<-+ (E[vsi],J,S) GET

where S{loc) = [T{yi,...,yn).F], readonly[fieldsOf [8 T{y\,...,yn)) (/)) =5', and F(f)= v (E[locg.f = v],J,S) <— (E[F],7,S® (ZOC— [t.F®{f<~* V')])) SET lod if v = lod , 6x ( null otherwise

(Elcast t locs],J,S)^ (E[locô],J,S) CAST where S(loc) = [s.F] andô s t

(Elcast 6 T(y\,...,yn) null5/],/,S) ^ (E[nullÔ/],/,S) NCAST if 6 = readonly or ô' = e

SKIP

(Eljoinpt j(vo,...,v„ )],J,S)—> (Elunder chain Ë,j( v0 vn )],/ + /,S) BIND where adviceBind{j + J, S) = B

(Elchain \[b,loc,e,y,T,^+B,j( v0,...,vn)],J,S)

— (Elunder {e'\loclth\s\\{vo,...,vn)lb\)Sif],j' + J,S) ADVISE where readonly{j) -5, e' - «e»g ,, and / = (this, loc,-, (E[under v],J,S) ^ (Elv],J',S) UNDER where J = j + J', for some j

(E[(F)Ô,Y],/,S) (E[FÔ],/,S) TAG

Figure 4.7 Evaluation Relation for the Operational Semantics of MiniMAÛ2 165

(Elnullfi.mt vi,...,vn )],J,S) <— (NullPointerException,/,S) NCALLA

(Elchain •,(call,-,M,-,T,Y|)(nullg,v\,...,vn)\,J,S) •— (NullPointerException,/,S) NCALLB

(E[nullg./],/,S) <-» (NullPointerException,/,S) NGET (Elnullg./ = v],J,S) ^ (NullPointerException, J,S) NSET

(Elcast t locg],},S} <-» (ClassCastException,/,S) XCAST whereS(loc) = [s.F] andÔ t

(Elcast ô T{ji,...,jn) null5/],/,S)<— (ClassCastException,/,S) NXCAST if 5' - readonly and 5 = e

Figure 4.8 Evaluation Relation for the Operational Semantics of MiniMAÛ2 (Ex­ ceptional Rules) join point abstraction onto the call stack, and wrapping the instantiated expression in an under expression to record that the call stack must later be popped. In MiniMAOg, these rules additionally place the instantiated expression inside a tagged expression. The tagged expression records the read-only status that is to be assigned to the result of evaluating the instantiated method or advice body expression. This read-only status is extracted from the type recorded in either the method's fun term or the advice's body tuple. For a method, this status will be readonly if either the method is declared to have a read-only return type or else the target object of the call was marked readonly (by the methodBody auxiliary function used in the CALLB rule). Tagging a method body as read-only when the target object pointer is read-only prevents accessor methods from being used to gain a write-enabled pointer into an object's representation via a read-only target object pointer. For advice, the self object is always writable, so the read-only status of the tagged expression is readonly only if the advice is declared to have a read-only return type.

The TAG rule takes the read-only status from the tagged expression, introduced in EXECB or ADVISE, and adds it to the result value. It drops the tagged expression wrapper from the result.

Similar to the EXECB rule, the GET rule combines the read-only status, ô, of the target object pointer, with the declared read-only status of the field type. This is done through the fieldsOf auxiliary function

(see Figure 4.9 on page 167). If either the target pointer or the field type is readonly, then the result value is also marked as readonly.

Finally, the SET rule changes to accommodate read-only annotations. In particular, if the value to be assigned to the field is marked read-only, this marking is dropped when the store is updated. This ensures that all pointers in the store are free of annotations. No information is lost, however. The static type system, 166 described in Section 4.3.2, ensures that the field itself is read-only in this case; otherwise the assignment would be ill typed. The type system also ensures that the target object pointer is not read-only.

Tracking writable domains Besides adding concern domain information to object records in the store,

MiniMAOa also tracks writable domains, from effects clauses, through the CALL, EXEC, and ADVISE rules. The

CALLA rule uses the writable auxiliary function (see Figure 4.9 on the following page) to find the set of writable domains, y, for the called method, given the concern domains of the target object. This set is recorded in the call join point abstraction. In the CALLB rule, the methodBody auxiliary function returns a fun term, I, that records the set of writable domains. This information flows through the EXECa rule and into the exec join point abstraction. The EXECB rule adds the set of writable domains to the tagged method body expression.

For advice, the set of writable domains comes from the advice table, via a body tuple. The ADVISE rule adds the set of writable domains for the advice to the tagged advice body expression.

Finally, the TAG rule drops the set of writable domains.

The pointcut matching function, matchPCD, described in Section 4.3.1.2, uses the writable domains information recorded in the join point abstractions. But otherwise the other threading of this information through the evaluation is just for the benefit of the subject reduction proof, and the meta-theory of effects clauses.

AUXILIARY FUNCTIONS Figure 4.9 on the next page and Figure 4.10 on page 168 give the auxiliary functions used in the operational semantics of MiniMAO?.

Several of the rules use a notion of domain variable substitution, defined in the obvious way. The auxiliary functions also take advantage of the "width subtyping" of concern domain variables; that is, q > r in a well- typed declaration like:

class c(G\,...,Gq) extends d(Gi,...,Gr) {...}.

Some auxiliary functions are changed from MiniMAOi to track read-only status. In particular, if the target object of an auxiliary function is read-only, then this information is carried over to the result. This can be seen in fieldsOf, methodType, and methodBody.

SUBTYPING Figure 4.11 on page 169 gives the subtyping relation for MiniMAO?. The two main changes are to handle concern domains and read-only types. Following Aldrich and Chambers [9],the subtyping relation allows things like lterlmpl(H,E,D> ^ lterator(H,E), so that downcasts may introduce (and dynamically verify) domain annotations. I say that concern domains in subtyping are positionally invariant and use width 167

Field lookup:

CT(c) = class c{Gi,...,Gq) extends d{G\,...,Gr) { t\ f\...tn fn meth* }

fleldsOf (<5 d(Yi,...,jr)) -F' Vz' £ {!../?}• sz- = 5 Gi,...,yql Gq\

z fieldsOf{0 c{yi,...,Yq}) - {ft -* st • i e {l..n|}uF

CT(tt) = aspect a(Gi Gq) { dep* t\ f\) ...; tn fn; adv* } Vz e {L.ni-s,- =6 f^yi/Gi yq! Gq\

fieldsOf (5 a(yi,...,yq)) = {fi <-* s; • z e {l..w}}

fleldsOf (5 Object(y)) = 0

Method type lookup:

CT{c) = class c{G\,...,Gq) extends d{G\,...,Gr) {field* methi... methp }

3i e {l..p} • methi = tm(t\ var\varn ) eff { e]

VZ E {L..W}-SJ = flyi/ G\,...,Yql Gq\ S = Ô t\j\! G\,...,Jql Gql

methodType{8 c{yi,...,yq), m) = sj x ... xsn — 5

CT(c) = class c(G\,...,Gq) extends d{G\,...,Gr) {field* methi... methp }

3Z e {l..p\• methi = t m(t\ var\,...,tn varn ) eff { e} methodType{5 d(j\,...,jr),m) = T

methodType{5 c{y\,...,yq),m) = x

Writable domains:

CT(c) = class c(Gi,...,G^> extends d(G\,...,Gr) {field* methi... methp }

Hi £ {L.p} • methi -tm(...) writes (y\,• • • ,y'n) { e } Vz e {l..n}-y" = y,-Syi/Gi,...,y,?/G

writable(Ô c{y\,...,y9>, m) = {y",...,y%}

CT(c) - class c(Gi,...,G(?> extends d(Gi,...,Gr> {field* methi... methp }

3/ £ {l..p} • methi = t m(... ) eff { e } writable(ô d{yi,...,yr),m) = y

writable{5 c(yi,...,yq),m)=y

Original declaration lookup:

origType{t, m) - max {S e ST • t =4 s A methodType(s, m) = methodType{t, m)}

Figure 4.9 Auxiliary Functions for Operational Semantics of MiniMAÛ2 168

Method lookup:

CT{c) = class c{G\,...,Gq) extends d{G\,...,Gr) [field* methi... methp }

3z e {l..p}-methi = tm(ti vari,...,tn varn ) writes {y\,• • • ,y'p) {

e = e'lyilGi,...,yCj/Gql y={y'i,...,y'p]\yilGi,...,yqlGq\

T = Ô c(yi,...,Yq) X 51X... XS„ — s Vz e {l..n}-sz- - tilyilGi,...,yql Gqi s = ô t\yi> Gi,...,yq! Gq\

methodBody{5 c{yi,...,yq),m) =fun m(th\s,vari,...,varn).e:T .y

CT[c) = class c(Gi,...,Gq) extends d {field* methi... methp }

3i e {l..p) • methi -tm(ti vari,...,tn varn ) eff { e } methodBody(ô d{yi,...,yr},m) = I

methodBody(ô c(yi,...,yq),m) = I

Read-only annotation:

readonly{5 T(yi,...,y p)) = ô readonly (to y. ...x tn-^ô T(yi,...,yp}) =ô

Advice binding:

f adviceBind:Stack x Store ->• {Sè x x g x WifM u 4mr) x {ST* — ST) x 3~))

adviceBindU, S) = Ê, where B is a smallest list satisfying

V(loc,pcd,e,y,t,%') e AT• ((matchPCD[J,pcd,S) = 5^ _L) => \[b, loc,e,y,T.T'JI E B)

Advice chaining:

<

For all other expression forms, the chaining operator is just applied recursively to every subexpression. For example, the definition of the chaining operator for field set is:

((e.f=e »5j = ((e»gj./=((e »5j

Binding substitution:

e\( v0 ,...,v n) / ( var — Zoc6, , • • • ,Pp ) f = e\locs / var\| vt / |iE{ o..n)-Pi=iw, where n

e\{vQ,...,vn) !(~,p0,...,pp)\ =e\vi! mri\i£lM.p.=mr. where n

In all other cases, binding substitution is undefined.

Figure 4.10 More Auxiliary Functions for MiniMAO^ Operational Semantics 169

t *4 s s^.u f =< s M f t=4 readonly t t =4 u readonly t =4 readonly s

CT{c) = class c{Gi,...,Gq) extends d{G\,...,Gr) { ... } CT(a) = aspect a(G\,...,Gq) { ... }

a(ji,...,jq) =4 Object<71)

Figure 4.11 Subtyping in MiniMAO] subtyping. The subtyping scheme also allows a write-enabled pointer to be used where a read-only one is expected, but not vice versa. Formally, [u ^4 t and readonly(u) = readonly) => (readonly(t) = readonly). I make liberal use of this property in the proofs of the meta-theory in Section 4.4.

POINTCUT MATCHING Figure 4.12 on the following page gives the definition of the pointcut matching function in MiniMAO?. MiniMAO? makes just three changes to the function. (1) The cases carried over from

MiniMAOi account for, but ignore, the writable concern domains information in the join point abstraction.

(2) The this rule gives the bound value, v, a read-only annotation if the formal parameter type is read-only but the bound value is not. (This change is actually immaterial for MiniMAO? but increases the consistency between it and MiniMAOg in the subsequent chapter.) (3) A new case handles the new writes pointcut descriptor. For static type safety, the case requires exact matching between the set of writable domains in the join point abstraction and the set in the pointcut descriptor. Since the writes pointcut descriptor does not carry any parameter binding information, a match is signaled by the empty binding, <-, -).

The algebra of bindings for MiniMAO? is like that for MiniMAO1, except for the shunting about of read-only subscripts on locations. Figure 4.13 on page 171 shows this.

4.3.2 Static Semantics

Although the changes to the operational semantics from MiniMAO1 to MiniMAO? are substantial, they pale in comparison to the changes in the static semantics. The operational semantics must handle the new concern domain and read-only information to describe the new writes pointcut descriptor, and to help with the proofs of the meta-theory. The static semantics must do this, plus enforce the desired properties of concern domains, effects clauses, and read-only annotations. It does this while maintaining separate static typechecking of class and aspect declarations.

I describe the static semantics by first giving some background on a couple of notions used throughout the discussion. I follow that with a description of the specific changes to the declaration, expression, and pointcut 170

matchPCD{(\k,^,m,^, t0x...xtp — £luJ +/,call( u idPat(..) ),S)

(-,-} if k = call, t = u, and m e idPat {_L otherwise

x x matchPCD{(\k,^, m,^, fo tp —• + /,execution( w idPat(..) ),S)

(-,-) if k = exec, f = w, and m e zVifto {_L otherwise

, [ if f = y' matchPCDd^,yD +/,writes(f ),S) = < I _L otherwise

matchPCDU^, t',1_1,LJ,LJ,1_1|) + /,this( f var),S)

(vari— vsi,~) if v - locg, S(loc) = [s.F], and 5 s 4 f (where readonlyit) = 8') { _L otherwise

mardzPCD((|1_,,-,l_J,UJ,l_j,,_1|) + /,this( f var),S) = matchPCDU,this( f var),S)

(-, far) if s0 = ï {_L otherwise matchPCDU ^-,,_J+y>target( t var),S)= matchPCDU,target( f var),S)

matchPCDitax...xtp -» ?,__,[) + /, args( MI vari,...,u„ var„ ),S)

var\,...,varn ) if p=n and Vz e {l..n} -(f,- = m,) _L otherwise

matchPCDU, pcd 11 pcd', S) = matchPCDU, pcd, S) v matchPCDU, pcd', S)

matchPCDU, pcd && pcd', 5) = matchPCDU, pcd, S) A matchPCDU, pcd', S)

matchPCDU, ! pcd, S) — matchPCDU, pcd, S)

matchPCDU, pcd,S) = ± for any case not matched by the preceding rules

Figure 4.12 Pointcut Descriptor Matching for MiniMAO] 171

Boolean algebra of bindings (adapted from Wand et al. [157]):

= Sëu {_!_} beSê reâê± b\/r = b ivr=r _L A r = _L b A_L = ± bf\b' = bhib'

-i± = <-,-) ->b = ±

Join of bindings:

(a,Po,~.,Pn)u(a',Po,.--,Pp) = (aua',p0up'0,...,pqup'q}

where q = max(n,p), Vz e {(« + l)..q\ • [Pi = and Vz e {(p + l)..g}- {P't = -)

1 (var*-* locg) u [var •-> loc's, j = tw—• loc$ (var<— locg) u -= var^ locg

-u^va/loc's,^ = var* ^loc'g, varu var' = var varu - = var -u var'= var' - u - = -

Figure 4.13 Bindings in MiniMAO] typing rules.

4.3.2.1 Dependency Tables and Writable Concern Domains

DEPENDENCY TABLES The static semantics must track the writable concern domains for each method and piece of advice. It also must account for the "varies with" dependency declarations in aspects, which extend the set of writable concern domains. To this end, the static semantics for MiniMAO? uses dependency tables, denoted DT, that record the information from a program's domain dependency declarations, reified according to the aspect instantiation instructions. Dependency tables are used in the meta-theory for reasoning about the effects of aspects on a program. Because this reasoning is based on the aspect instantiation instructions, which are like a degenerate form of concern map (as discussed in Chapter 2), the reasoning is analogous to the sort a programmer would have to do in a language with explicitly accepted assistants.

A dependency table is a reflexive, transitive relation on concern domain names and variables. It has the type DT : [

The definition of the evaluation dependency table below includes an auxiliary function, depTable. The function creates a reflexive, transitive relation such that for any pair (7, j') in the relation, code which has permission to mutate concern domain 7 may also mutate 7'. The elements in the pair are in "reverse order": a dependency declaration 7' varies with 7 induces a pair (7,7') in the relation. I believe that the dependency declaration ordering is more human-readable, while the ordering in the relation is more natural for the formalism. 172

The dependency table used in a program evaluation is constructed as follows:

I 1 Definition 4.1 (Evaluation Dependency Table). Let P be a well-typed program with public concern

domains g and aspect instantiation instructions asp1,...,aspn.

For each i e let aspi = use a(g\,...,gq), with

CT{a) = aspect a{G\,...,Gq) { depl; ...; depp; field* meth* },

and construct a set representing all the public concern domain dependencies for the aspect instance:

depi = {deplt...,depp}lgilGi,...,gq/Gq\.

With dep1,... ,depn constructed in this manner, the evaluation dependency table for P is:

depTable^g,\dep l u... udep„jj,

where

depTableif, dep) is the reflexive, transitive closure of:

U {(T'T)}j u{(T'/) ' {^depe dep-dep=j' varies with yj|.

I i

The evaluation dependency table defined above is a whole-program property (though the search depth is quite shallow, just aspect instantiation instructions and dependency declarations in aspects). In the static semantics the whole-program evaluation dependency table is not required. Instead, static typechecking uses a different dependency table for each top-level declaration. This smaller dependency table is constructed from the concern domain variables and dependency declarations in the class or aspect. The T-PROG, T-MET, and

T-ASP rules, described below, each construct a small dependency table for static typechecking. The use of these smaller dependency tables corresponds to separate typechecking of classes and aspects, without the global configuration information provided by the aspect instantiation instructions.

EXPRESSION TYPING JUDGMENT The typing judgment for an expression in MiniMAO? is:

r.f hDTe:u, 173 where DT is a dependency table, f is the set of writable concern domains for e, and the type of the type environment is

T : (Y uyu®u%flru {this, proceed}) — [ST u [ST* — 5") u {domain}).

Two invariants on any type environment, F, that are not shown in this "simple" typing are that (1) only unsubscripted locations appear in its domain and (2) for any location, loc, in the domain of F, Y (loc) ~ T

That is, the type to which F maps loc does not bear a read-only annotation. These invariants reflect the fact that locations in the type environment are just used to model the store in the subject reduction proofs, and locations and objects in the store do not bear read-only annotations. On the other hand, a type environment may map variable names to read-only types, modeling formal parameter declarations.

( ( The type environment, F, may include elements from fi and Smr in its domain, and the special type domain in its range. A type environment element g: domain indicates that the concern domain name g is in scope. A type environment element G: domain indicates that concern domain variable G is in scope.

The dependency table, DT, in the expression typing judgment might more conventionally be written on the left-hand side of the turnstile. I choose to part with convention and use a subscripted turnstile to more easily omit the dependency table from the notation when it is clear from context. Furthermore, unlike the other terms in the typing judgment, the dependency table is a constant throughout any given expression type derivation.

4.3.2.2 Declaration Typing

The declaration typing rules appear in Figure 4.14 on the following page. The following describes the changes to each rule versus MiniMAO i.

PROGRAM TYPING The T-PROG rule contains new hypotheses to check the aspect instantiation instruc­ tions. In particular, the concern domain names used in the instructions must be declared in the program, and the number of names given for each instruction must match the number of concern domain variables for the corresponding aspect declaration (which must also exist).

In MiniMAOi, the main expression of a program is typechecked in the empty environment. In MiniMAO?, the environment records that all declared public concern domain names are in scope. T-PROG allows all public concern domains to be mutated by the main expression; that is, the set of writable domains is all public concern domains. For typechecking the main expression, T-PROG uses a dependency table that is just the 174

T-PROG Vz' E {l..n} • h decli OK

Vz e {l..r}-3j E {l..n}-declj = aspect a,i(Gi,...,Gqi) { ... } Vz E {l..r}-(Vj E {l..<7,j-g,j E {gi,...,gp})

gi : domain,...,gp: domain. {gi,...,gp} \-DTe\t DT = depTable{{g\ gp\, 0)

h dech...decln { domain gi; ...; domain gp; use a\ ; ...; use e } OK

T-CLASS

Vz E {l..zz}-/} ( dom[fieldsOf (d{G\ Gr») Vz e {\..n]-{G\} h f,- OK in c(Gi,...,G^}

isClass{d{G\,...,Gr» V y E {l..p}- h mef/zj OK in c(G\,...,Gq) q>r> 1

h class c { fi /i; ...; /„; methi... methp } OK

T-MET e:u mri : t\,...,varn: î„,this:5 cr

[Git{ji,...,jp\) => (0 = readonly) (GI E {yi,...,yp}) => {8 = e)

DT=depTable({Gi,...,Gq},0) u=$t CT{c) = class c{G\,...,G'q) extends d(G'v...,G'r) { ... }

override{m,d(G\,...,Gr),t\x ... xt„ —• ?, {YI,...,Tp}) {GI,...,GQ} t- F OK in C(GI,...,G9>

Vz e {1..p\-ji E |G] G,} Vz E {l..n!-{yi,...,yp} h ff OK in c{G\,...,Gq)

h t m(t\ vari,..., tn varn ) writes { e } OK in c{G\,...,Gq)

T-ASP

Vz E {l..r} • H depi OK in a{G\,...,Gq) DT = depTable ( {Gi,...,G

Vz E {l.-pI'DTK advi OK in a{G\,...,Gq) q > 1 Vz e {l..n}-{Gi( h t/ OK in ti(Gi,...,Gq>

h aspect a

T-DEP £ yi {Gl,...,Gq} Y2 E {Gi,...,Gq\

l-yi varies with j2 OK in a{G\,...,Gq)

T-ADV

T h pcd:^. uq.{u\,...,u p). u.f.V. V V = {var\ varn\ f Q {yi,... ,yr}

{yi yr} ç depCloseDT (y) r, this : a{G\,... ,G^), proceed :{uox ...xup w).{yi,...,yr} \i,Te:s

s =4 t u {G\,...,Gq} h ? OKin a{G\,...,Gq) VZ' E {l..r} - ji E {Gi,... ,Gq\

Vz E {!..«} -{yi,...,yr} h f,- OK in a(G\,...,Gq) F = van : h,...,varn : f«,Gi : domain,...,G^ : domain

DT h £ around( var\,...,tn varn ) writes : pcd { e } OK in a{G\,...,Gq)

Figure 4.14 Static Semantics of Declarations in MiniMAO] 175 reflexive relation on the set of all public concern domains. Because all public domains are writable, no other pairs are needed in the dependency table.

CLASS TYPING The T-CLASS rule threads the concern domain variables of the class declaration through the field-lookup (fieldsOf) and class-table-checking (isClass) auxiliary functions (see Figure 4.9 on page 167 and Figure 4.15 on the following page, respectively). The concern domain variables are also used in typecheck­ ing each method (see the description of T-MET below) and each field type.

The checks on field types are new in MiniMAOg. Figure 4.16 on the next page gives the rules for checking the validity of a type given the concern domain variables in scope, Gi,.. .,Gq, and the set of writable concern domains for the context in which the type appears, y'j,... ,y'r.

The T-TYPE rule (in Figure 4.16) says that a write-enabled type is only valid if the home domain of the type, yi, is in the set of writable domains. Furthermore, all of the concern domain variables used in the type must be in scope. The T-TYPERO rule removes the restriction on the type's home domain when the type is read-only.

T-CLASS checks type validity for the fields of a class, considering only the home domain of the class GI to be writable. Through this mechanism, the T-CLASS rule prevents the capture of write-enabled, interdomain pointers by requiring that fields containing interdomain pointers be read-only.

Finally, T-CLASS requires that the declared class have at least as many concern domain variables as the class that it extends.

METHOD TYPING Of the declaration typing rules, T-MET and T-ADV (described below) change the most from MiniMAOi.

The body expression, e, of a method is checked in an environment where all the concern domain variables,

Gi,...,G^, of the surrounding class are in scope. The environment also sets the read-only status, 5, of the special this variable based on whether or not the method's effects clause allows the home domain of the host class to be mutated (see the second and third hypotheses of T-MET). The last hypothesis of T-MET verifies that any formal parameters that point to non-writable domains are read-only; analogous to my treatment of the this variable.

The set of writable concern domains used for typechecking the method body comes directly from the effects clause of the method. Another hypothesis ensures that every concern domain variable in the effects clause is in scope. The override auxiliary function (see Figure 4.15 on the following page) is extended to ensure that, should the method override another method, then their effects clauses match.2 (The T-MET hypothesis

2For behavioral subtyping it would be sufficient to require that the set of writable domains contains no additional elements; that is, overriding methods could safely write to a subset of the writable domains specified 176

Valid method overriding:

methodType{c{G\ ,...,Gq),m) = r writable{c(G\,... ,Gq) ,m) = f

override{m, c(Gi,...,Gq},r,f)

CT{c) = class c(G[,...,G'q) extends d(G[,...,G'r) {field* methi... methp }

3i e {l..p\ • methi = t m{... ) eff { e } override^m,d(G\,...,Gr),T,y)

override(m,c{G\,... ,Gq) ,t,f) overrideim,Object(G), T,y)

Writable domains dependency closure:

depCloseDT (y) = {j' • 3y e y • (y, y') e DT},

c where DT : u &var) —• (^ U Svar) is reflexive and transitive, and Vy e y • (y, y) e DT

Valid class:

CT(c) = class C(GI,...,G9> extends d(G\,...,Gr) { ... }

isClass{8 c{G\,...,Gq)) isClass(ô Object(G))

Binding typing:

T-BIND (a - var>—• v) => {vart V\ {var}) Vz e {0..rc} • (Pi = rar) => (twC V\

Vvare V-{V t dom{T)) V = var(b) b = {a,Po,...,pn)

ThbOK

J {var}u{Pi-i e {0..ni,/5,- ^ -} ifa=rar~z/ where var({a,Po,...,Pn)} - < |{Pi • i e {0..fi}, Pi -£ -} otherwise

Domain variables lookup:

CT{c) = class c{G\,...,Gq)... CT{a) = aspect a{G\,...,Gq)...

domains{c) = {Gi,...,Gq} domains(a) = (Gi,...,Gq)

Figure 4.15 Auxiliary Functions for Static Semantics of MiniMAO]

T-TYPE T-TYPERO

yi e {y'v...,y'r} Vz e {!..»}-y, e {Gi,...,Gfl} Vz e {!..«} • yf e {Gi,...,Gq}

r {r\,...,r'r\ !" OK in S {y'v...,y'r}' h readonly r OK in S

Figure 4.16 Auxiliary Typing Judgments for Declarations in MiniMAO] 177 that appeals to the class table, CT, is used to determine the number, q, of concern domain variables to include in the override judgment.)

The dependency table used for typechecking the method body is just the reflexive relation on the concern domain variables of the class; no dependency declarations are in scope with which to extend the relation.

Finally, T-MET checks the validity of the method's return type given the in-scope concern domain variables and without restriction on the read-only status of the return type. Returning a pointer into a concern domain does not mutate that domain; thus, the read-only status of the return type is not related to the effects clause of the method.

ASPECT TYPING The first hypothesis of the T-ASPECT rule checks that all concern domain variables appearing in the aspect's dependency declarations are in scope (see also T-DEP).

The hypothesis of T-ASPECT that checks advice declarations uses a dependency table formed from the dependency declarations of the aspect. The concern domain variables of the aspect declaration are also used.

Like T-CLASS, T-ASPECT requires that all fields pointing to other domains be read-only. T-ASPECT also checks that the aspect has at least one concern domain variable so that it may be instantiated.

ADVICE TYPING T-ADV checks the validity of the advice's formal parameter and return types as in T-MET, discussed above. Also like in T-MET, T-ADV includes the in-scope concern domain variables in the type environment and uses the effects clause to determine the set of writable concern domains when checking the advice body. T-ADV ensures that all concern domains listed in the effects clause of the advice specify concern domain variables that are in scope, again like T-MET.

T-Aov uses the dependency table supplied by T-ASP to check the advice body.

MiniMAO] extends the pointcut typing judgment to track the set of concern domains, y, named by writes pointcut descriptors within the pointcut. Section 4.3.2.4 describes these changes in more detail. For the present discussion it is useful to consider how the writable domains, f, matched by the pointcut should be related to the effects clause of the advice and to the host aspect's dependency declarations. Two hypotheses of T-ADV mediate these relationships.

The hypothesis f s {y i,... ,yr} says that the writable domains of code matched by the advice must be a subset of those that the advice is declared to (possibly) mutate. This relationship ensures that the effects clause of the advice accounts for any mutation that might occur should the advice proceed to the advised code.

The hypothesis {y i,... ,y r} ç depCloseDT (f ) says that the effects clause of the advice may only list by the overridden method. Similarly, a formal parameter of an overriding method could be made read-only even if the corresponding parameter of the overridden method was write-enabled. I have not investigated the implications for advice matching of either relaxation. 178

— concern domains in the effects clause of code matched by the advice and

— concern domains for which a dependency declaration gives the advice permission.

How is this? Figure 4.15 on page 176 gives the definition of depCloseDT (f), the dependency closure of y in

DT. The dependency closure here includes every element of y. For any concern domain, y', named in the effects clause of the advice, but not in the effects clause of matched code, there must be some sequence of dependency declarations such that y' "varies with" a writable concern domain, y, of the matched code. But why is this the right notion? Intuitively, the dependency declarations tell a programmer that when this aspect is present in a program, calling a method that modifies y may trigger advice that modifies y'. The hypothesis of T-ADV prevents other concern domains from being modified.

An interesting consequence of these two hypotheses restricting the effects clause of advice is related to

"pure" methods, methods whose effects clauses are empty [93]. The dependency closure of the empty set, depClose(0), is empty for any dependency table. Thus, the effects clause of advice on a pure method must be empty; only pure advice may bind to pure methods.

4.3.2.3 Expression Typing

The expression typing rules for MiniMAOg appear in Figure 4.17 on the following page. Because of the large number of expression typing rules, and the fact that many of them change in similar ways, I structure this discussion based on the sorts of changes made to the rules versus MiniMAOI. The T-TAG rule is new with

MiniMAO^; I discuss it in terms of the role it plays in the changes. Figure 4.18 on page 180 shows a class with several ill-typed expressions that serves as an example throughout this discussion.

PROPAGATING INFORMATION In most rules, the set of writable concern domains and the dependency table in the judgment must be passed along to subderivations. For several rules, this is the only necessary change. These mostly unchanged rules are T-VAR, T-GET, T-SEQ, T-PROC, and T-UNDER. Other rules that include this and other changes are T-CALL, T-EXEC, T-SET, T-CAST, T-CHAIN, and T-JOIN. The T-TAG rule uses the dependency table of its judgment in the hypothesis for typing the contained expression.

CHECKING CONCERN DOMAINS IN TYPES The static semantics must check the concern domains named in the expressions that explicitly give types—object instantiation and casts. Thus, MiniMAO^ adds checks to

T-NEW, T-OBJ, and T-CAST that any concern domains named in their expressions are in scope. T-NEW, and implicitly T-OBJ, also check that the number of concern domains named in the object instantiation expression match the number from the class declaration. 179

T-NEW

domains{T) = (G\,...,Gq) Vz'e {l..<7}-r(y;) = domain yi ef

r.f ^rnew T(ji,...,Yq)():T(Yi,...,Yq)

T-OBI T-VAR T-LOC T-NULL r(y) = domain y E y T{var) = t T{loc) = t te ST

r.y \-DT new Object(y)(): Object (y) T.f^rvar-.t r.y hpr Zocg : <5 ? r.y h^j-nullg :d t

T-CALL

r.y fyre0:5 T0 Vz E {l..«}-r.y : ut

methodType{8 7b(yi,...,yp>,m) = ?ix...xtn — f writable(8 7b(yi,...,yp>,ra) =y'

depCloseDT (y') g y (ô = readonly) ==> (y' = 0) Vz e |1..«) • m,- 4 f(-

r.yhôreo-'«( ei,...,e„):t

T-EXEC e:s s r,varo:tQ,...,varn:tn.depCloseDT(f') h)T ^t Vz E {0../î}-T.y 1 Vz E {0..n}-uj =4 ti depCloseDr (f ) G Y [readonly{uq) = readonly) =» (F' = 0) T = ZO x... x /„ F

r.y ^(fun m(varo,...,varn).e:T.f' (e0,...,e„)):t

T-SET T-GET R.y^EI:T yi E y T-CAST = t r.y^7-^:5 fieldsOf(T(Yi,...,Yn))(f) r.ylyTe:s readonlyis) - 8' fieldsOf{s)(f) = t Y.fk>Te2-s s=4t Vz E {l..g}-r(y;) = domain

r.ylore./:f r.y = e2:s T-y^cast ô r e:ô8' T{Y\,...,Yq)

T-PROC T-SEQ VZ E {O-.ZÎ} - r.y HYJ-E; :M,- T-UNDER r.y iôrei :s r.y ^63: t r (proceed) = to* ...xtnt Vz £ |0..«j • ^ r.y h^re: f

r.y lyrei; eg: f r.y fyTeo.proceed( e\,...,en):t r.y Founder e: ?

T-CHAIN Vz £ {0..«} - r.y HOJ-e^. : VZ E {0..n} • ==: f;

depCloseDT[f') (readonly(u'0) = readonly) => (y' = 0) Vz E {l..p}-T h bj OK

Vz E {l..p} -r,this:r(/oc(),proceed:T, typeBind{T,bi, (to,...,tn)).depCloseDT(jj) ^rre/ :s •

Vz E {l..p}-SJ t Vie {],.p|• depClose[rr(f'j) GdepCloseDT(f') t = t^x ... xtn ->• î

r.yhôrchain HZ?î',/ocz,e,',y;,T',Tjli-e{L.p!,_,T,y'D( eo,...,e'„ ): ^

T-JOIN

VZ'E )0..zz}-r.y tqyjei-.Ui Vi e {0..N} • z/,- 4 Z7 depCloseDT(f) GF T-TAG

(readonly(uo) = readonly) => (y' = 0) F.depCloseDT(y') \~DTe\t

[v0pt = locg) =» ('oce dom{T)) depCloseDT (y') ç y

F-f brjoinpt — î),y'P(eo,...,en):f T .f f

Figure 4.17 Static Semantics of Expressions in MiniMAÛ2 180

/ class Rogue(what, who) extends Object(what) { readonly Book(what, who) roBook; J Book(what, who) weBook; // write-enabled

s Book(what, who) abusingEffectsClauseQ writes <) { //pure method 6 this.weBook.title = null; //error! 7 this.weBook.setTitle(null); //error! s new Book(what, who)() //error! i }

a void(what) abusingReadonlyO writes (what, who) { i2 this.roBook.title - null; //error! is this.roBook.setTitle(null); //error!

a }

i7 Object(what) castAway(readonly Object(what) cantTouchThis) writes () { is cast Object(what) cantTouchThis H error!

Figure 4.18 Sample Expression Type Errors in MiniMAO^

ENFORCING WRITABLE CONCERN DOMAINS WITH RESPECT TO STORE MODIFICATIONS The type rules for expression that may explicitly modify the store—object instantiation and field set—must enforce the writable concern domains permissions. In T-NEW, the hypothesis j\ E y says that the home domain of a new object must be writable. That is, instantiating an object within a concern domain requires write access to the domain. A similar hypothesis appears in the T-OBJ rule. Line 8 of the code in Figure 4.18, demonstrates code that is disallowed by T-NEW. The effects clause of the method abusingEffectsClause is empty. Since (what € 0), the expression cannot be typed.

This restriction may not be strictly necessary: in order for the instantiation to affect other code, the new object would have to be passed as a result or parameter, or else stored in a field and then subsequently dereferenced. All these uses could be checked. This would be equivalent to the handling of newly allocated objects in the pointer analysis of Rinard et al. [146]. For conceptual consistency, I am not allowing the allocation of new objects in non-writable domains. This also simplifies the statement of the meta-theory of effects in

Section 4.4.3, because I do not have to account for allocated but unreferenced objects—no "garbage collection" on the store.

For the T-SET rule, I add an hypothesis, YI E Y, that says that the home domain of the target object for the set must be writable. Line 6 in the sample code runs afoul of this hypothesis. The target object for the 181 set expression, this.weBook, has its home domain represented by the concern domain variable what. Again

(what t 0), so the expression cannot be typed.

ENFORCING WRITABLE CONCERN DOMAINS FOR METHOD CALLS MiniMAOz also includes a number of changes to enforce writable concern domains for method calls.

The T-CALL rule has two hypotheses for this purpose. One uses the writable auxiliary function (see Fig­

ure 4.9 on page 167) to look up the writable domains, f', of the called method, m. Another new hypothesis,

depCloseDT [f) G 7, ensures that any concern domains that might be mutated by the call are in the set of writable concern domains. In Figure 4.18, line 7 violates this rule, assuming the declaration of Book from

Figure 4.3 on 155. The setTitle method can write the what concern domain. The expression cannot be typed, because {what} g 0.

Why use the dependency closure of the method's writable concern domains? This ensures that the rule considers effects on public concern domains of any advice that might bind to the method's call or execution.

For static typechecking, the dependency table for checking methods is just reflexive, so the dependency closure does not matter. But it becomes necessary in the subject reduction proof.

I also add the hypothesis depCloseDT (F') G 7 to each of T-JOIN, T-CHAIN, T-EXEC, and T-TAG to propagate writable concern domain information through the stages of advice binding and execution. The method body and advice bodies in the T-EXEC, T-CHAIN, and T-TAG rules are checked using a set of writable concern domains that is the dependency closure of the declared set. This is a convenience for the proofs of the meta-

theory—fun application, chain, and tagged expressions do not appear in the user syntax—but is intuitively

correct. To wit, the set of domains that might be modified by executing a method or advice body is, by definition,

the dependency closure of the method's or advice's effects clause. The T-CHAIN rule also has an hypothesis that

relates the effects clause of matching advice to that of the matched method, taking the dependency closure of

both sets of concern domains. Again, this is a convenience for the proofs of the meta-theory.

ENFORCING READ-ONLY ANNOTATIONS The handling of readonly in the expression typing rules is moti­ vated, in part, by the Universes type system [52,117].

As discussed in Section 4.3.1.2 on page 163, in the operational semantics the read-only status of a pointer

is combined with the type of the object to which it points to determine the type of the pointer. The T-Loc and

T-NULL rules in MiniMAOg use the same technique for typing locations and null. MiniMAOg also updates the

typeBind auxiliary function to use this technique for typing binding terms (see the first rule in Figure 4.19 on

the next page). The T-TAG rule uses a similar trick, but here the enclosed expression is not yet reduced to a value. 182

typeBind (r,( var >— locs,fi{ ,f>n),(to tp)) = var:ô F (loc), (var j : tj)je{(i.JI}.pi=mri if n< p

typeBind(r,(-,/30,..,tp))= (van : ti)i€[0.M].pi=mri if n < p

typeBind (T,(a, Po,...,p n) ,(to,...,tp)) is undefined if n > p

Figure 4.19 Binding for Type Environments

The T-SET rule, besides restricting the home domain of the target object, also checks that the target object is not read-only. This is through the hypothesis that gives the type of e\ as T(j\,... ,y„>; notice the lack of a read-only annotation on the type. So line 12 in Figure 4.18 on page 180 cannot be typed. The target of the set has a read-only type and so is not matched by this hypothesis.

The static semantics must also prevent mutation through method calls on read-only pointers. With the hypothesis (5 = readonly) => (f ' = 0), the T-CALL rule only allows calls to pure methods when using a read­ only pointer to the target object. (Here 5 is the read-only annotation on the type of eo.) Line 13 is in conflict with this "purity hypothesis". It may be possible to relax the purity hypothesis; technically we would only need to ensure that the target object's representation was not mutated. But because an object's representation may extend into other concern domains (as in the Book example from Figure 4.1 on page 151), it is not immediately obvious how to relax this requirement. I leave the study of this to future work.

As with writable concern domains described above, I add hypotheses to T-JOIN, T-CHAIN, and T-EXEC to push the purity hypothesis of T-CALL through the proofs of the meta-theory.

Finally, the T-CAST rule concatenates any read-only annotation from the type of its expression and the type to which that expression is being cast. This statically ensures that the read-only status of an expression cannot be "cast away". For example, in line 18 of Figure 4.18, the variable reference cantTouchThis has type

readonly Object(what). Thus the type of the cast is also readonly Object (what). So, the expression cannot be used as the result type of the method.

4.3.2.4 Pointcut Typing

Figure 4.20 on the following page gives the typing rules for pointcuts in MiniMAOg. A pointcut typing

judgment is of the form:

T h pcd:û.û' .U .û" .f_L .V1.V2 where û, û', U, û", V\, and V2 are unchanged from MiniMAO1 (see Section 3.2.3.2). Only fx is new in Mini-

MAO2. It gives the writable concern domains for any code under a join point matched by pcd, or is _L if that information cannot be determined from pcd. 183

U:: = {t*) |1 u::=f|± fi :: = y | -L Ve&>{7)

M u1 = F< -Lu û = M Uu±= U ±uU =U f±ul= f± -L u yi = fj_

T-CALLPCD Vz e |l..<7}-r(y,-) = domain

TI— cali( <5 T z'dPtif(..)):±.±.±.d T{j\,...,yq) .L.0.0

T-EXECPCD Vz e {l..<7} - r (yf) = domain

T hexecution(ô T{ji,...,jq) idPat(,.)):±.l.l.ô T{j\ yq).1.0.(,

T-WRTPCD T-THISPCD Vz' e {!..«} -r(y;) = domain Y(var) = t

r H writes( yi,...,y„ ) : ±.1. _L. ±. {yi,...,y„}. 0.0 r h thisU rar ) : f. ±. ±. ±. ±. {var]. {rar}

T-TARG PCD T(rar) = f

r H target( f mr):±. f.±.±.±. {var\.{t-ar}

T-ARGSPCD

Vz e {!..«}• (r(rarz-) = Vz e {l..n}- (Vy e {1..n} \ {i} • (vari # varj))

Y h args( t\ var\,...,tn varn ):±.±. (t\,... ,tn). L .{var\,... ,varn] .{var\,... ,varn]

T-UNIONPCD

R h pcdx -.û.û' .U .û".f i_.V\.V{ Y h pcd2 : û.û' . f/. û". f±. V2 • V2' T-NEGPCD

F = I*! n y2 V' = V[ u V2 Y h pcd : û. û'.U. û" .f.V. V'

Y\-pcdx II pcd2 : û.û!. U. û" .f±.V. V' Y H ! pcd:± .±.±.±.±.0.0

T-INTPCD 1 rh pcd] :û\. û\ .U\. û'I.fxj . Vi.V[ Y h pcd2 : û2.u 2.U 2. Ag • f±2 % • ^2

M = Û| U Û2 ù! = M] LJ û'2 U = U\\J U2 û" — w" LJ Û2

f± — yxj u yx2 Vj' nV2 = 0 V = Vi L) V2 V' — Vj' uV 2

Yhpcdi && pcd2:û.û'.U.û".f±.V.V'

Figure 4.20 Static Semantics of Pointcuts in MiniMAO^ 184

The basic pointcut typing rules from MiniMAOi—T-CALLPCD, T-EXECPCD, T-THISPCD, T-TARGPCD, and T-ARGSPCD—are changed as might be expected: they place a _L symbol in the writable concern domains slot of the pointcut type. Additionally, T-CALLPCD and T-EXECPCD include hypotheses that verify that any concern domains named in the pointcut descriptor are in scope.

The new T-WRTPCD rule types writes pointcut descriptors. Like the preceding rules, T-WRTPCD verifies

that any concern domains named in the pointcut descriptor are in scope. T-WRTPCD also records the writable

concern domains in the pointcut type.

MiniMAOa extends the typing rules for the recursive pointcut descriptors in a straightforward way. The

T-UNIONPCD rule requires that both combined pointeurs have the same set of writable concern domains.

The T-INTPCD rule requires that at most one of the combined pointcuts is not _L. As in MiniMAOi, this level

of exactness for the union and intersection rules is needed for type safety. Finally, T-NEGPCD is updated in

the expected way.

4.4 Meta-theory

All the meta-theory from MiniMAOi must be updated to deal with concern domains, effects clauses, and

read-only pointers. Besides this, I also introduce the meta-theoretic properties that derive from the new language features. These new properties include:

— Effects clauses are effective. Effects clauses, plus the configuration information given by aspect instantia­

tion instructions and dependency declarations, are sufficient for determining the concern domains that

may be modified by a method call or advice execution, even in the presence of other aspects.

— Code cannot mutate an object's representation by dereferencing a readonly pointer to the object. This is

slightly different than the first property. This property says that a read-only pointer to a writable domain

may not be used for mutation.

The conditions required to prove the second claim point out that reasoning challenges still exist for aspects

as powerful as those in MiniMAOg. But the results point the way to a solution—spectators. I discuss this more

in Section 4.4.3.2.

I begin the exposition of the meta-theory by stating the auxiliary definitions and lemmas used in the proofs

of the more interesting theorems. A subsequent section updates the type safety results for MiniMAOg. A final section then gives the meta-theory for concern domains, effects clauses, and read-only pointers. 185

4.4.1 Auxiliary Definitions and Lemmas

This section presents the auxiliary definitions and lemmas of the meta-theory. I preface each updated defi­ nition or lemma with a few words describing how it has changed. For lemmas, I also highlight any interesting bits from the proof.

DEFINITIONS MiniMAOz has one new definition and several updated definitions that are used in the type safety proof. (A few other new definitions appear in Section 4.4.3 describing the meta-theory for concern domains, effects clauses, and read-only pointers.)

The one new definition here says that a type environment is "concern complete" if all concern domains in the program are in scope according to the environment. Static typechecking does not use concern-complete type environments, but they are used in the proofs which deal with program evaluation.

I l Definition 4.2 (Concern-Complete Environments). Given a well-typed program P with concern domains

g, we say that a type environment f is concern complete if

Vgeg-F(g) = domain.

For MiniMAOg, I update the definition of environment-store consistency to account for read-only annota­ tions on field types. This change only affects part 1(d) of the definition.

I 1 Definition 4.3 (Environment-Store Consistency). A type environment F and a store S are consistent, and

we write r » S, if all of the following are satisfied:

1. V/oce^f • S(loc) — [t.F] =>

(a) T{loc) = t and

(b) dom{F) = dom[fieldsOf{t)) and

(c) rng{F) ç dom{S)u {null} and

(d) V / e dom(F)-[[F{f)= lod and fieldsOf(t)(f) = u and S (loc1) = [f'.F']) => S t' =4 u), where S -

readonly{u)

2. V loc e • {loc e dom{T) => locedom{S))

3. dom{S) G dom{T) 186

The join point abstraction in the definition of stack-store consistency gets an additional slot corresponding to the set of writable concern domains at the join point. However, the value in that slot does not matter for this definition. The loc slot in the join point abstraction also gets a read-only annotation, Ô, but that is also ignored.

I l Definition 4.4 (Stack-Store Consistency). A stack / and a store S are consistent, and we write J ~ S, if

e /-locedom{S).

In MiniMAO] a valid store contains a single instance of every aspect declared in the program. Rather than having one instance of each aspect, MiniMAOg includes aspect instantiation instructions. I update the definition of a valid store accordingly.

I 1 Definition 4.5 (Store Validity). Given a well-typed program P with aspect instantiation instructions

USe Cl\ (^1,1> • • •'Si,pi )' USe an{gn,\, • • • >&n,Pn^ >

we say that a store S is valid if both of the following hold:

1. Vie {l..n}-{3loce££-S{loc) = [ai(giii,...,giipi). P})

2. gr-r = s

LEMMAS The type safety proof for MiniMAOg requires two new lemmas. All lemmas from MiniMAOI also

receive some tweaks.

The first new lemma says that if one set of concern domain names and variables is a subset of the depen­

dency closure of another, then the dependency closure of the first is also a subset of the dependency closure of

the second. The essential reason for this is that the same dependency table is used throughout. Figure 4.21 on

the next page gives a Venn diagram that may be helpful when reading the proof of the lemma.

I l Lemma 4.6 (Dependency Closure Inclusion). LetP bea program with concern domains g and evaluation

dependency table DT. Iff Qg,f G g, and f £ depCloseDT (f ), then depCloseDT (f) ç depCloseDT (f).

Proof. Because DT is constant throughout the proof, I elide it where practical. Let y' be an arbitrary

element of depClose[y'). By definition of depClose, there exists y e f such that (y,yr) e DT. But y E y'

implies y e depClose [y) by the assumption of the lemma. So again by the definition of depClose, there 187

depCloseDT (f)

Figure 4.21 Venn Diagram Illustrating Lemma 4.6

exists y" e y such that (y",y) e DT. Now DT is reflexive and transitive, so (y",y') e DT. By the definition of

depClose, j" E y => y' e depClose (f).

So every element of depClose(f ) is also an element of depClose(f). • i i

The second new lemma says that a typing judgment that holds with a given set of writable concern domains and a given dependency table, also holds using a new dependency table that is a superset of the first. However, the set of writable concern domains in the new typing judgment must be the dependency closure (over the new dependency table) of the original set. I use this lemma in the subject reduction proof to lift the separately typechecked derivations for method and advice bodies into the evaluation, where the whole-program evaluation dependency table must be used.

I 1 Lemma 4.7 (Dependency Table Extension). If e includes only user syntax, F.f \~DTe'. t, DT ç DTz, and

Vy e y • (y,y) e DT2, then

F. depCloseDT2 (y) V-DTz e: t.

Proof. The proof is by structural induction on the derivation of F. y \~DTe: t. The base cases are T-NEW,

T-OBJ, T-VAR, and T-NULL. (We do not need to consider T-Loc, because locations are not part of the user

syntax.) For all of these, the judgment does not depend on DT, so the claim holds.

The remaining expression typing rules constitute the induction steps. The induction hypothesis is that 188

the claim of the lemma holds for all derivations smaller than the one under consideration. For T-GET,

T-SET, T-CAST, T-SEQ, T-PROC, and T-UNDER, the claim is immediate from the induction hypothesis.

All but one of the hypotheses of T-CALL hold immediately by the induction hypothesis. The one

hypothesis from the derivation of F. f \-pr e : t that we must consider is depCloseDT (f) Ç 7, where f is the

set of writable domains from the effects clause of the called method. The corresponding hypothesis from

the derivation of F. depCloseDI-2 (f) hpj-2 e : t is depCloseDT .Z [f) c depCloseDT2 (7).

First, note that depCloseDT (f') Ç f implies f Ç 7. To see this, take 7' e f. By definition,

7' E depCloseDT (7')

and thus 7' £ 7.

Next, note that f'çfimplies depCloseDTl (f) Ç depCloseDT2 (7). To see this, take 7' e depCloseD1-2 (f).

Then there exists 7E7' such that (7,7') e DTz- But 7' G 7 then implies that there exists 7 e 7 such that

(7,7') eDT2. So 7' e depCloseDI,2 (7).

Thus, by T-CALL F. depCloseDT2 (7) \~jyrz e : t, and the claim holds for this case.

The remaining expression typing rules—T-EXEC, T-CHAIN, T-JOIN, and T-TAG—do not apply to user

syntax. Thus, the claim holds. • I I

The Substitution lemma uses the new expression typing judgments, with their sets of writable domains and dependency tables, but these are consistent throughout the statement of the lemma. Otherwise the statement of the Substitution lemma is unchanged from MiniMAO1.

I I Lemma 4.8 (Substitution). IfT,van • ti,...,varn:t n.j\~DTe:t andVi e {l..n} -r.fhDTei: si where si ^ £/

thenT .j^-DTe\e\l var\,...,e n! varn\: s for some s =

z Proof. Let F = F, var\ : t\,...,varn : tn and let 1èl var\ represent \e\! var\,...,enl varn\. I omit the DT sub­

script for the remainder of the proof, with the understanding that the same dependency table is used

throughout.

The proof proceeds by structural induction on the derivation of F h e : f and by cases based on the last

step in that derivation. The base cases are T-NEW, T-OBJ, T-NULL, T-LOC, and T-VAR. In the first four of

these cases, e has no variables and s= t. 189

In the T-VAR base case, e - var, and there are two subcases. If var t {var\,...,varn} then T'(var) =

T[var) = t and the claim holds. Otherwise, without loss of generality, let var = var\. Then e\ël var\ — e\,

T h e\ël~vâr\:s\, and si ^ t\ = t.

The remaining cases cover the induction step. The induction hypothesis is that the claim of the lemma holds for all sub-derivations of the derivation being considered.

Case 1—T-CALL. Here e = e'().m( e\,e'p ). The last type derivation step has the following form:

F'.fhe'0:ô To(yi,...,yq) Vi e {l..p}-r'.f I- e\ : u\

methodTypeiô T0(Yi,...,Yq),m) =u\ x ... xup — t writable(S Ta{y\,...,Yq), m) = f'

depClose[f') Q f (<5 = readonly) => (f' = 0) Vz e {l..p} • w- ^ «,•

r'.f he:?

Let e'! = e'i\el~var\ for i e \0..p\, then e\ël~vïïr\ - e^.m( e\' ,...,e"p ).

We show next that T-CALL also gives F H e\ël~vcïr\ : s for some .v ^ t. By the induction hypothe­ sis, T h EFT : Mq, where U'G =<: Ô TO(JI,...,YQ}. By the definition of subtyping, u('j = 8' T'Q{J \,... ,J R) with

( (5 = readonly), Tg(Yi,...,Yr) 4 TO , and r > q by T-CLASS.

Now suppose ô' - readonly. Then 5 = readonly and

methodType{Ug,m)= methodTypeiô 7b(yi,m)

by the definitions of methodType and override.

Otherwise8' — e and methodType(u'g,m) = u\ x... xup — s, where readonly s= t (i.e., sis twithout a readonly annotation) if Ô -readonly and s-totherwise. In either case s^t.

To discharge the remaining hypotheses, we note that writableiu'g, m) = y\ again by the definition of override. Furthermore (5' = readonly) => (8 = readonly) => (f = 0). Also by the induction hypothesis

Vi e \ l..p\ • T H e" : u'! and a'! =4 u't. Finally, Vz E {l..p} • u'! =< M, by transitivity and thus the claim holds.

J Case 2—T-EXEC. Here e = (fun m(var 0,...,var'p}.e' :r.f ( e{v...,e'p ) ), where r = u'Qx... xu'p ->• f. The last 190 derivation step is:

J J r,vai 0:u'0,...,vai p:u'p.depClose(f')\-e':s' s'=4t Vz e {0..p} • I'. y h e- : w, depClose [f') Qf

(readonlyiuo) = readonly) => (y' = 0) Vz e {0..p| • w, M• T = u'Qx ...xu'p ->• t

r'.y h e: £

As in the preceding case, let e" = e(|ë/for z e {0..p}. Also let e" -e'\el var\, then

J J ejë/IwrS = (fun m(vai 0,...,vat p).e":t.f (eQ,...,ep)).

By the induction hypothesis, for i E {l..p}, T. y he": u" where u'[ =4 Uj. Also, if readonly [u'Q) = readonly then readonlyiiiQ) = readonly (by the definition of subtyping) and y' = 0 (by hypothesis of T-EXEC above).

Finally, by T-EXEC and transitivity of subtyping, T. y H e\ël vïïr\ : t.

Case 3—T-GET. In this case e - e' .f.The last step in the type derivation for e is

r'.y he': M fleldsOf(u)if) - t

r'.y h e'.f:t

Nowejê/I«?} - e'\ë! var\.f, and by the induction hypothesis T h e'\elvar\:u', where 11' =4 u. Consider subcases on whether u' is a class or an aspect type.

If isClassiu1), then by the definition of fleldsOf and by the first hypothesis of T-CI.ASS, fieldsOfi u')(/') = s=4 t = fleldsOf iu)if), where ô s — t for some <5. In this case, F h e\ël uar\ : s and the claim holds.

On the other hand, if u' is an aspect, then u' = u (since an aspect is only a subtype of itself and Object, and u # Object because fleldsOf (u) # 0). So fleldsOf («')(/) = fleldsOf(«)(/) - t, l'h ejë/ va.r\:t, and again the claim holds.

Case 4—T-SET. Here e= (e'x./ = e'2) and the last step in the type derivation is:

r'.y h e\ : T\{j\,...,jp) yi Ey fleldsOf p}) if) = u T'.f\-e'2:t t^u

Now ejêlvïïr\ - (e'x {ëlmr\.f = e'2iëlmf\). By the induction hypothesis r.y h e[iëlvâfl : T[{yi,...,Yq),

T[{ji,...,Yq) 4 T\(yi Yp) and T .y h e'2\êl~vïïr\ : t', t' 4 t. 191

If TJ is a class, then by the definition of fleldsOf and the first hypothesis of T-CLASS, we have

fleldsOf [T[<7x,...,yqj) (/) = fleldsOf (7i <71,... ,yp>) (/) = u.

On the other hand, if T[ is an aspect then, by the same argument as in the T-GET case, T'{ - T\, p ~ q, and again fleldsOf ( T[ (71,... ,7q }) (/) = fleldsOf (7'i <71 y,,)) (/) = u.

In either case, by transitivity t' =4 u. Therefore, F. 7 h e\ê! var\ : t', where t' 4 t and the claim holds.

Case 5—T-CAST. In this case, e = cast t e', where t = 8 T{71,...,7 q). Here the last derivation step is:

T'.f\-e:u readonly(u) = 8' Mi e {l..q) - T (7/) = domain

T'.fh cast t e':5't

By the induction hypothesis, T. 7 V- e'\ël var\ : u' where u' 4 u. Let readonly[u') - Ô". We need to show that

<5 8" T{y\,...,jq) =488' r<7I,...,7,?>. If 5 = readonly this holds by idempotency of read-only annotations.

If 8 — e, then we must show

g" r

If 8" = e this holds. If<5" = readonly, then by the definition of subtyping 8' = readonly. So (4.1) holds.

Case 6—T-SEQ. In this case e - e'y e'2 and the last step in the type derivation is:

r'.7 h e[ : s F'. 7 h e'2 : t

r'.7h e'j; e'2:t

Now e\ë! var\ - e'^èluarl; e'2lë/vâr\. By the induction hypothesis, F.fh e'x\êl var\:s',T.y \- e'2\ë! var\\t', and t' 4 t. Therefore, T.7 h e\èl~vâr\\t', t' 4 t, and the claim holds.

Case 7—T-PROC. Here e ~ E(',.proceed! e\,...,e'p ) and the last derivation step is

Vi e {O..p) -r'.f h e- : u't r' (proceed) = uqx. ... xwp — t Vz e {0..p} • u'{ 4 Ui

T'.f\-e'0.proceed( e[ e'p):t

Let e" - e'^ëlvâfl for all i e {o..p}. Then e$ë/vârl = eQ.proceed( e",...,e'p ). Now T(proceed) = 192

T' (proceed) = uq X... x up t and by the induction hypothesis

Vi e {0..p} • (r. f h e'[ : u", where u" 4 u't 4 m,-) .

Thus, by T-PROC, T.7 H e$ë/vârl : t and the claim holds.

Case 8—T-UNDER. Here e = under e' and the last derivation step is

r'. 7 h e' : t

T'.fl- under e': t

The claim is immediate by the induction hypothesis.

Case 9—T-CHAIN. Here e = chain BAk, vopt, mopt,l opt,{uo*...xu p — t),f'U e'0,...,e'p ). The last deriva­ tion step for the judgment T'.7 h e : t is by T-CHAIN, with three of the hypotheses being:

Vz £ {0..p} -r'.f h e\ : u\ Mi £ {0..p] • u't =4 w, [readonly(u'n) = readonly) => (7' = 0)

Let e'! - e'^el uar\ for all i e \0..p}. Then

e||ël mr\ = chain ÉAk,vopt,mopt,lopt,{uox ...x«p-> t),f'\)(eQ,...,ep).

Substitution does not recurse into the advice list, B, or the join point abstraction.

As in the T-PROC case, the induction hypothesis gives Vi e \0..p\ • (r.f H e'l : u'!, where u" 4 u'i 4 Uj).

Also {readonly{ug) = readonly) => (readonly(u'Q) = readonly) ==> (f = 0). Because substitution does not replace variables within Ë or within the join point abstraction, the remaining hypothesis of T-CHAIN are unchanged in the type derivation of e\ë! mr\, except for using I instead of F'. This fact does not change the judgments, since none of the variables in the statement of the lemma are free in the tuples of B. Thus,

T.fhelë/vâfl : t.

x x Case 10—T-JOIN. Here e = joinpt (&, vopi,mopt,lopt, (wo ••• "p — r),Y'[)( e'0,...,e'p ). The proof is like that for Case 9. 193

Case U—T-TAG. Here e - (e')g ^i and the last step in the type derivation is

r'.depClose [f') h e':t' depClose(j) c y

r'.fh(e')Sf:t

where t-8 t'. Now e\ët var\ = (e'lëlmr\)Sji. By the induction hypothesis T. depClose (f') h e'\ëlTmi : s'

where s' =4 t'. Consider two cases.

If 8= e,then t-t' and, by T-TAG, r.f h e\ët var\ : s' and the claim holds.

On the other hand, if 8 = readonly, then by T-TAG r.f I- e\ë/vâr\: readonly s'. By the definition of

subtyping readonly s' =4 readonly t' = t, thus the claim holds. • 1 1

The Environment Extension lemma holds the set of writable concern domains and the dependency table constant.

I 1 Lemma 4.9 (Environment Extension). IfY.f\j,Te: t and at dom{Y), then T,a:t' .f\-DTe:t.

Proof. The proof is by a straightforward structural induction on the derivation of r.f tyTe: t.

For the base case, the last step in the derivation is T-NULL, T-NEW, T-OBJ, T-VAR, or T-Loc. In the first

case, the type environment does not appear in the hypothesis of the judgment, so the claim holds. For

T-NEW and T-OBJ, a £ dom(Y) implies that no hypotheses change, so the claim holds. For the T-VAR case,

e = var and Y(var) = t. But a t dom{Y), so var # a. Therefore (r, a : t') [var) = t and the claim holds for this

case. The T-Loc case is similar.

The remaining typing rules cover the induction step. By the induction hypothesis, changing the type

environment to Y,a \ t' does not change the types assigned by any hypotheses. Furthermore, because

a € dom(Y), we have Vy • T (y) = domain => (T, a : t') (y) = domain. Therefore, the types assigned by each

rule are also unchanged and the claim holds. • 1 1

Like Lemma 4.9 (Environment Extension), the Environment Contraction lemma holds the set of writable concern domains and the dependency table constant. The lemma states that unused type mappings may be dropped from the type environment in a typing judgment without changing the judgment. The lemma does not allow domain mappings to be dropped from the environment, though in principle this could be done if the dropped domain variable did not appear in the writable domains of the environment. 194

Lemma 4.10 (Environment Contraction). IfY,a\t'.y hDTe: t, a is not free in e, and t' ^ domain, then

Y.y\-me:t.

Proof The proof is by a straightforward structural induction on the derivation of T, a : t'. y hpT e : t.

For the base case, the last step in the derivation is T-NULL, T-NEW, T-OBJ, T-VAR, or T-Loc. In the first

case, the type environment does not appear in the hypothesis of the judgment, so the claim holds. For

T-NEW and T-OBJ, t' # domain implies that no hypotheses change, so the claim holds. For the T-VAR case,

e- var and (Y,a: t'){var) = t. But a is not free in e, so var ^ a. Therefore F(var) - t and the claim holds for

this case. The T-Loc case is similar.

The remaining typing rules cover the induction step. By the induction hypothesis, changing the type

environment to F does not change the types assigned by any hypotheses. Furthermore, because t' ^

domain, Vy- [Y,a: t') (y) = domain => F (y) = domain. Therefore, the types assigned by each rule are also

unchanged and the claim holds. • i I

In MiniMAOg, the Replacement and Replacement with Subtyping lemmas allow subexpressions to be typed using a subset of the writable concern domains from the outer typing judgments. This is necessary to allow substitution within tagged expressions, for example.

I 1 Lemma 4.11 (Replacement). If T. y \-DTt\e] : t, F. f \~DTe: t', and T. f \-DTe' : t' for some f G y, then

Y .y \-DTE[e'} : t.

Proof. By examining the evaluation context rules and corresponding typing rules, we see that F.f ^ e: t'

must be a sub-derivation of Y. y hDT E[e] : t. Now the typing derivation for F. y hur E\e'\ : t" must have

the same shape as that for E[e\\t, except for the sub-derivation for F. f' lj)Te' : t'. However, because this

sub-derivation yields the same type and uses the same environment as the sub-derivation it replaces, it

must be the case that t" = t. •

Lemma 4.12 (Replacement with Subtyping). IfY.y lyrE[e] : t, F.y' t~DTe: u, andY .f \-DTe' :u' where

u' 4 u and f G y, thenY . y \QTt\e'\ : t' where t' 4 t.

Proof. The proof is by induction on the size of the evaluation context E, where the size is the number of

recursive applications of the syntactic rules necessary to build E. In the base case, E has size zero, E = -,

f = y, and t' - u' 4 u= t. 195

For the induction step we divide the evaluation context into two parts so that E[—] = Ei [Eg [-]], where

Eg has size one. The induction hypothesis is that the claim of the lemma holds for all evaluation contexts smaller than the one considered in the induction step, and therefore holds for Ei. We use a case analysis on the rule used to generate £2- In each case we show that if T.f " Y-DT Eg [e] : s then F. f" V-DT E2 \e'\ : s' where s' 4 s and 7' ç 7" ç 7, and therefore the claim holds by the induction hypothesis. I omit the DT subscript for the remainder of the proof, with the understanding that the same dependency table is used throughout.

Case 1— E2 = -.m( e\,...,en). The last step in the type derivation for E2[e] must be T-CALL: .

F.f" h e:ô T{yi,...,yp) Vz'e {\..n} -r.f" h e, :

methodTypeiô T(j\,... ,jp), m) = s\x ...xsn -* s writable{8 T{j\,...,jp),m) = fm

depClose(fm) Ç 7" (ô = readonly) => (f m = 0) Vz' £ {!..»} • Uj 4 s;

F.f"hE2[e]:s where u = ô T{71,... , jp) and 7' = 7". By the definitions of override and writable,

writable{u, m) - writableiu', m).

By the definition of subtyping, u' = 8' where =4 T{j\,...,jp).

There are two possibilities depending on the value of 8'. If 8' = readonly, then by the definition of subtyping 8 = readonly too. So by the definitions of override and methodType, methodType{u', m) = methodType{u, m). The remaining hypotheses are unchanged, so T-CALL gives r.f" I- E2\e'} : s.

On the other hand, if 8' = e, then methodTypeiu', m) - s\ x... x sn — s', where 8 s' -s.The remaining hypotheses all hold, so T-CALL gives F.f" h Ez\e'] :s'. Regardless of the value of 5, s' 4 s, so the claim holds.

Case 2—E2 = VQ.m( v\,...,vp-\,-,ep+\,en) where p e {!..»}. The last step in the type derivation for E21 e\ must be T-CALL, with f = f":

r.f" h vo'-S To(yi,...,"Yq)

Vz £ 1)} -r.f" \- Vi'.Ui r.f" h e:u Vz e {(p+ l)..zz}-F.f" h e, : M,-

methodType{8 To(jit...,Yq),m) ~ s\x... xs„ — s writable{8 To(ji,...,jq),m) -fm

depClose(fm) Ç f" (5 = readonly) (fm = 0) Vz £ {!..«} \ {p} • m,- ^ s, m

F.f"hE2[e]:s 196

Now u' 4 u4 sp, so by T-CALL r.f" h E2 [e'] :s.

Case3—E2 = ( I ( VQ,...,Vp-i,-,ep+i,en) ) where p e {0..n}. The last step in the type derivation for E2[e] must be T-EXEC (where u = up and f = f "):

r, varo:so,...,varn:sn. depClose (f m ) h e" : u," u" 4 s Vz £ {0..(p- 1)} -r.f" h Vi : m,-

F.f" h e: Mp Vz £ {(p+l)..n}-T.f" \- ei:Ui \/i e{0..n}\{p\• Ui 4 Si

up 4 sp depClose(fm) Q f" (readonly(uq) = readonly) => (fm = 0)

T .f"hE2[e]:s

where Z = fun m{varo,...,varn).e": (so* •••*s„ — $) ,fm. Now u' 4 u= up 4 sp. If p- 0, then

(readonly[u') = readonly) => (readonly(ua) = readonly) => (fm = 0).

So by T-EXEC, T. f" h E2 [EZ] : s.

Case 4—E2 = The last step in the type derivation for E2|e| must be T-GET (with f = f"):

r.f" h e: u fields()f( u)(f) = s

T. f" t- E2 [e] : s

If u' is read-only, then because u' 4 u, the definition of subtyping says that u is also read-only. By the first hypothesis of T-CLASS and the definition of field lookup, fieldsOf(u') (/) = fleldsOf {u){f). Thus, by T-GET, r.f"hE2[e']:s.

On the other hand, if u' is not read-only, then fleldsOf (u')(f) - s', where Ô s' = s for some 5, and by

T-GET, r.f" I- E2(E'] : s'. Now s' 4 s, so the claim holds.

Case 5—E2 = cast ô S(yi,...,yn) -. The last step in the type derivation for E2[e] must be T-CAST (with

r.f"he:u readonly(u) = 5' Vz e {\..n} • T (y,) = domain

T. f" h E2 le] : s where s-ÔS' By assumption T. f" h e' : u', u' 4 u. Let readonly (u') =Ô". By T-CAST T.f" H

E2le'] :ô Ô" S(yx,...,yw>. We need to showô ô" 4 ô ô' S(yi j„). This follows from u' 4 u, as argued in Case 5 of the proof of Lemma 4.8 (Substitution) (see page 191). 197

Because r.f" h e':u', R.f" H E2[e'] :sby T-CAST.

Case 6—E2 = e". The last step in the type derivation for E2 [e] must be T-SEQ (with F = f"):

F.f" \- e:u T.f" \- e" : s

r.f"hE2[e]:s

Thus, also by T-SEQ, T.f" I- E2[E'] :s.

Case 7—E2 = (-./ = e"). The last step in the type derivation for E21e] must be T-SET (with u - and f = f"):

T .7" I- e: T{j\,...,Yn) 7ief" fleldsOf ,7 „)){f)-u" T.f"he":s s=4u"

T.f" b- E2 le] : s

Because u! 4 u, the definition of subtyping says that u' is read-only and u! - SX71,jp) where p > n. By the first hypothesis of T-CLASS and the definition of field lookup, fleldsOf («')(/) - fleldsOf (u){f). Thus, by

T-SET, T.f" bE2[e']:s.

Case 8—E2 - ii'o-f = -). The last step in the type derivation for Ei\e\ must be T-SET, letting s = u and f = f":

T.f" vo:T(ji,...,jn) 71 s f " fleldsOf j n)) (/) = u" T.f"\-e:u u=4 u"

T.f"hE2[e]:s

Now u! =4 u 4 u", so let s' - u' and T.f" E2\e'] : s'.

Case 9—E2 = The last step in the type derivation for E2M must be T-TAG:

r.depClose (ft) I- e:u depClose (ft) Q f"

T.f" h Ezle] :s where, by the assumptions of the lemma, f - depClose [ft) and s - ô u. Let s' - Ô u', then T-TAG says

T. f " h E2 [e'] : s'. Because u! =4 u, s' 4 s, and the claim holds. 198

Case 10—Ez = joinpt 1 k, vopt, mopt, lopt,(s0 x ... x s„ -» s), f m D f v0,...,vp-\,-,ep+i,en ) where p e {0..«}.

The last step in the type derivation for E2 [E] must be T-JOIN (where up = u and f = F"):

Vz e {0..(p-1)} -F.f" H vi : u\ F.f" h e: u Vz e {(p+l)..n)-T .j" h g, : u,-

Vz e {0..n} \{p}- ut 4 ll up sp depClose{fm) G y"

[readonlyiuo) = readonly) => (ym = 0) (vopt = locs) => (locedom{T))

r.y"hE2[e]:s

Now u! 4 u = up 4 sp. If p = 0, then (readonly(u') = readonly) => (refldonZy(Mo) = readonly) =*

(ym - 0). So, also by T-JOIN, T.f" h E2[e'] :S.

Case 77—E2 - under The proof for this case is immediate from T-UNDER with s = u and s' = u'.

Case 12—E2= chain B,j( vo i'P-\,~,ep+\,en ) where p e{0The proof is like that for Case 10, but

using T-CHAIN instead of T-JOIN. The additional hypotheses of T-CHAIN, beyond those of T-JOIN, are

unchanged in the type derivations for E2 [e] and E2 !

The Environment Subtyping lemma also holds the set of writable concern domains and the dependency table constant.

I 1 Lemma 4.13 (Environment Subtyping). LetY,var:t.f\j,Te:s. Then for all t' 4 t, there exists some s' 4 s

such that, F, var: t'. f hDT e : s'.

Proof Let var1 be a variable reference such that var1 g dom{T), var1 ^ var, and var1 is not free in e. Then by

the assumption of the lemma and Lemma 4.9 (Environment Extension) on page 193, F, var'-.t', var.t.f \~DTe:s.

1 By Lemma 4.8 (Substitution) on page 188, F, var :t'.f \-DTe\var'/ var\ : s' for some s' 4 s. Finally, by a-

converting var1 to var (relying on the correspondence of ^-conversion with capture avoiding substitution

of one variable reference for another), we have F, var: t'.y V-DT e : s' for some s' 4 s. • 1 1

The Binding Soundness lemma now handles sets of writable concern domains in join point abstractions and advice body tuples. A new consequent asserts that the dependency closure of the writable domains of matching advice is a subset of the dependency closure of the writable domains of the matched join point abstraction. I suspect that the two sets could be proven equal, but the given claim is strong enough for the use of the lemma in the subject reduction proof. The last consequent of the lemma is also updated to include a set of writable concern domains: the dependency closure of the set from the advice declaration. 199

Lemma 4.14 (Binding Soundness). Let P be a well-typed program with evaluation dependency table

x x DT. Let S be a valid store for P and J - J...,Uo ••• tn — t),f D + /' be a stack consistent with S. IfÊ =

adviceBindU, S), then V \[b, loc, e, y', T, r'j] e B the following conditions hold:

Consequent 1. depCloseDT (f) s depCloseDT (f)

Consequent2. T' = to x... x tn —<-1

Consequents. 0 h b OK

Consequent 4. For concern-complete F = S, the judgment

r, this : r (loc), proceed : T', typeBind (!',/), (

holds for some t' 4 t.

Proof. I will use a common setup and some common meta variables throughout the proof.

Pick an arbitrary element of B, \[b, loc, e,f',r, T'J] . Let the advice corresponding to \[b, loc, e,f,T, T'JI be

s" around(5j vars"} varp) writes

with advice table entry (loc,pcd,e,f, Let this advice be declared in an aspect a with concern domain

variables G\,...,Gqi and dependency declarations dep\,dep/x. Let S(loc) - \a{g\,...,gqi) .F^. We will

consider the typing derivation for this advice, which must exist because the program is well typed. However,

we will a-convert the entire derivation, replacing G,- with g, for all i e {l..q'\.3

To simplify the notation, I will write lg/Gf for \g\! G\,...,gqi! Gq/\. Let s - s"\g! G[, Vz e {l..p} •

Si = s'Jlg/Gl, Vz e {l..r} -7j. = j"\g! G|, Vz e {l..x} -rfep,- = dep't\gl G\, and T' = vari\s\,...,varp-.sp,gi :

domain,...,gy : domain. By the construction of AT, T - s\X... xsp — 5, e = e"\g I G\, pcd = pcd"\gl G|,

and f' = {j'v... ,j'r\. Let the dependency table of the advice typing be

DTa = depTable^gi,... ,gq*|, {dep l,... ,depx} j.

This comes from T-ASP, with concern domain variables replaced by concern domain names.

3This is an «-conversion at the meta-level. One might also think of it as sort of a ^-conversion, replacing concern domain variables with concern domain names, if one were so inclined. 200

Meta-variable Bindings:

\[b,loc,e,f',T,T'W e B

S{loc)= [a(gi gq')-Fj

T = 5iX ... XSp —• 5

t' = Mo x ... x Uq —* U

T' - van : varp :sp,g\: domain,..., gqi : domain

Advice Type Derivation (with domains reified):

T' h pcd : . UQ .(u\,... ,Uq).U .f pcc| .V .V V = [van,..., varP\

f pcd f G depCloseDTa (ypcdj r'.this : a(gi,... ,gqi),proceed : (w0 x... x Uq — u). f' bbTa e: s'

s' 4 s 4 u gi,-..,gq> h sOKin a{gi,...,gqi)

VzE{l..r}'%yE jgi,...,g^| \/ie{l..p}-j[,... ,j'r h st OK in a(gi,... ,gq>)

DTa h s around( si van,...,sp varp ) writes (j'v... ,j'r) : pcd { e } OK in a(g\,...,gqi)

Figure 4.22 Setup and Common Meta-variable Bindings Used in the Proof of Lemma 4.14

Plugging this notation into the «-converted derivation from T-ADV gives:

T' h pcd:^.UQ.(ui,...,Uq).u.fpcci'V.V V = {van,...,varp}

g Q x f pcd f' f' depCloseDTa (fpcd) F', th is : a(gi,... ,gq>), proceed : (w0 ... x uq — u). f' \-DTa e: s'

s' 4s4u gi,--.,gq> I- sOKin a(gi,...,gq<)

Vz e {\..r\-y\ e jgi,...,g^,} Vi e {l..p}-yj,...,y'r H st OK in a(gi,...,gqi)

DTa H s around( si var\,...,sp varp ) writes (y'i,...,y'r) : pcd { e } OK in a{g\,...,gq>) (4.2)

By the construction of AT, T' = UQ X ... x UQ — u.

For convenience, Figure 4.22 summarizes the setup of the proof and the use of these meta-variables.

Because a well-typed pointcut descriptor in MiniMAOg must consist of multiple primitive pointcut

descriptors, it is difficult to prove the consequents of the lemma using a single inductive argument. Instead,

I propose and prove a series of simpler subclaims. Each subclaim is proven via a structural induction on

the pointcut type derivation. A well-typed pointcut descriptor that matches J will satisfy the antecedents

of all the subclaims, and the consequents of the subclaims will imply the consequents of the lemma.

Consequent 1 on the preceding page relates the writable domains recorded in the join point abstraction

to those recorded in the advice body tuple. We know that YPCC| G f by an hypothesis of T-ADV in (4.2). By the 201 definition of adviceBind, H>, loc, e, f,t, T'JI E B implies matchPCD(J, pcd, S) # 1. By T-ADV, the writable domains slot of the pointcut type for pcd is not _L The following subclaim says that in this situation f Ç depClose(y).J\\us by Lemma4.6 (Dependency Closure Inclusion) on page 186, depClose[f) Ç depClose(f) and consequent 1 holds.

Subclaim 1. Assume T' h pcd: Û. u'o. U.û'. 7pcd.V'. V" (i.e., fpcc| # J_). Then

matchPCDU, pcd, S) ^ A. => f' G depClose(y)

Proof of subclaim.

— pcd = call(... ). Subclaim assumption cannot hold (because 7pcd = _L).

— pcd = execution!... ). Subclaim assumption cannot hold.

— pcd - writes( )• By T-WRTPCD, fpccJ = {71 ywj. By the definition of matchPCD,

matchPCDU, pcd, S) ^ J_ => 7 = fpcc|

To see that the subclaim holds, let 7' be an arbitrary element of f.

If 7' e fpccj, then 7' £ 7 and, by definition of depClose and the fact that DT is reflexive, 7' £ depClose(7).

On the other hand, if 7' € fpcc| then, by the depClose hypothesis of T-ADV in (4.2) on the preceding

page, there exists 7e fpcc| such that (7,7') £ DTa. But 7 £ fpcc| implies that 7 £ 7. By the construction

of DTa (in T-ASP) and Definition 4.1 (Evaluation Dependency Table) on page 172, (7,7') e DT. So by

the definition of depClose, 7' £ depClose (7).

Thus f G depClose (7).

— pcd = this(... ). Subclaim assumption cannot hold.

— pcd - target(... ). Subclaim assumption cannot hold.

— pcd = args(... ). Subclaim assumption cannot hold.

— pcd = pcd] 11 pcd2. By T-UNIONPCD, F' h pcdï : û\ .û[ . ll\ . û". fpcd . U, . V[ and T' h pcd2 : àz. û'2 .

U2. û'2 . fpcc|. V2. V2. By the induction hypothesis, matchPCD(J, pcdi ,S) # J_ ==> f Q depClose (7)

and matchPCDU,pcd2, S) # ± => 7' ç depClose [f). By the definition of matchPCD,

matchPCD(J,pcd, S) # _L => malchPCDij,pcd,,S) # _L or matchPCDU,pcd2,S) # _L

=> 7' Q depClose (7) 202

— pcd = pcd\ && pcd2. By T-INTPCD and the definition of u, one of the following hold:

- T' h pcdy : MI . M,.U\. û".fpcd.V] . V,' and T' h pcd2 : u2 • û'2.U 2. m^' • • V2 •^

- T' h pcd ^ : MI .M' X . U\. û" .L.V\.V[ and F' h pcd2 : û2. û'2. L/2. MG.f pcd. V2 - V2

So the induction hypothesis holds for the type derivation of at least one of pcdi and pcd2. By the

definition of matchPCD,

matchPCDU,pcd,S) # _L => matchPCDU,pcd]tS) # _L and matchPCDU,pcd2,S) #1

=> f' G depClose [f)

— pcd = ! pcd^. Subclaim assumption cannot hold.

Subclaim-d

Consequent 2 on page 199 relates the proceed type of the advice, r', to the function type in the join point abstraction. The proceed type, T' = MO X ... x uq — u, is constructed from the pointcut typing for the advice, pcd :L_,.MO.(MI,,..,M(?).f pcd.V. V. To satisfy the consequent we must show that T' = to x... x tn — t.

We use three separate subclaims, one for each pertinent position in the pointcut typing. The subclaims let us show:

— Mo = to,

— q-n,\/ie {1 ..n] • ui = tt, and

— u=t

Subclaim 2. Assume F' h pcd : û. uo • U. û' ,f±.V'. V" (i.e., the "target type" is not _L). Then

matchPCDU, pcd, S) ^ ± => MQ - to

Proof of subclaim.

— pcd - call( ... ). Subclaim assumption cannot hold.

— pcd= execution(... ). Subclaim assumption cannot hold.

— pcd = writes(... ). Subclaim assumption cannot hold.

— pcd = this(... ). Subclaim assumption cannot hold. 203

— pcd — target( t" var" ). By T-TARGPCD, t" - UQ. By the definition of matchPCD,

matchPCDU, pcd, S) ^ _L ==> to = t"

=> UQ - to.

— pcd = args(... ). Subclaim assumption cannot hold.

— pcd = pcdx 11 pcd2. By T-UNIONPCD, F' pcdx : û\. MO • U\. û\. FJ^ • V\. V[ and F' H pcd2 : Ag .

no. 6/g. «2 • f ±2 • ^2 • tg- By the induction hypothesis, matchPCDU, pcd\, S) # _L ==> MQ = h) and

matchPCDU, pcd2,S) f _L => MQ = to. By the definition of matchPCD,

matchPCDU,pcd,S) # -L => matchPCDU,pcdl,S) ^ ± or matchPCDU,pcd2,S) ^ _L

'* MQ — to

— pcd = pctij && PCDG. By T-INTPCD and the definition of u (in Figure 4.20 on page 183), one of the

following hold:

- F' h pcdY :ûi.uo.Ui.û[.f±1.Vi.Vj and F' h pcd2: Û2 • -L • U2 • û'2. f±2 .V2. V'2

- F' h pcd y :«].!.U\ . û'} .fx,. V]. V[ and F' h pcd2 :112 • uo • U2 • û'2. f j_2. V2 • ^

So the induction hypothesis holds for the type derivation of at least one of pcd^ and pcd2. By the

definition of matchPCD,

matchPCDU, pcd, S) ï -L => matchPCDU, pcd\, S) ^ _L and matchPCDU, pcd2, S) + 1

=> MO = to

— pcd - ! pcd 1. Subclaim assumption cannot hold.

Subclaim-D

Subclaim 3. Assume F' \- pcd: û.û' . (u\,...,Uq). û" .f ±. V'.V" (i.e., the argument type sequence is not _L).

Then

matchPCDU, pcd, S) ^ _L => [q = n and Vi e \l..n} • u, - tj)

Proof of subclaim.

— pcd = call(... ). Subclaim assumption cannot hold. 204

— pcd = execution!... ). Subclaim assumption cannot hold.

— pcd — writes(... )• Subclaim assumption cannot hold.

— pcd = this(... ). Subclaim assumption cannot hold.

— pcd = target(... ). Subclaim assumption cannot hold.

J — pcd = args( t" vai x,t"v var"u, ). By T-ARGSPCD, W = q and V i e {\..q\• w, = t". By the definition of

matchPCD,

matchPCDU, pcd,S)^ 1 ==> w = n and Vz e \l..n\ • r,- = t"

=> q - n and Vi e {1..n} • u; = ti

— pcd = pcdx 11 pcd2. By T-UNIONPCD, T' h pcd^ : û\. û\. (u\,...,uq). û" .fxj. V\.V{ and T' h pc

u «2 • «2 • ( i, • • •,Uq ). «2 • f ±2 • ^2 • By the induction hypothesis, matchPCDU, pcd1 ,S)^ 1 => <7 =

M and Vz e \l..n\ • w, = t( and similarly for matchPCDU, pcd2, S). By the definition of matchPCD,

matchPCDU, pcd, S) 5^ J_ => matchPCDU, pcd y, S) ^ _L or matchPCDU, pcd2,S)^ ±

=> q = n and Vz e {l..n} • m, = f;

— pcd = pcd y && pcd2. By T-INTPCD and the definition of u, one of the following hold:

- F' h pcdy : û\. M'J .{u\,...,uq). û".f±l.V\ . Vj' and F' h pcd2 :62.û' 2.±.û'2. f±2. V2. V2'

- F' h pcdy : zîi. m'j .1. Mj.fxj • Vi. Vj' and F' h pcd2 : û,2.û'2.{u\ Uq) .û'2.f_i2 . V2 • V2'

So the induction hypothesis holds for the type derivation of at least one of pcdy and pcd2. By the

definition of matchPCD,

matchPCDU,pcd,S) ^ _L => matchPCDU,pcdltS) •£1 and matchPCDU,pcd2,S) 1

=> q = n and Vz e {l..n} • Ui = tt

— pcd = ! pcdy. Subclaim assumption cannot hold.

Subclaim-•

Subclaim 4. Assume F' h pcd : u. û'. IJ. u.f±.V'.V" (i.e., the "return type" is not _L). Then

matchPCDU, pcd, S) # _L => u = t 205

Proof of subclaim.

— pcd = call( t" idPat{..) ). By T-CALLPCD, t" = u. By the definition of matchPCD,

matchPCDU, pcd, S) ^ J_ => t - t"

=> u—t.

— pcd = execution! t" idPat{..) ). Similar to previous case, but by T-EXECPCD.

— pcd = writes! • • • )• Subclaim assumption cannot hold.

— pcd = this!... ). Subclaim assumption cannot hold.

— pcd = target!... ). Subclaim assumption cannot hold.

— pcd - args(... ). Subclaim assumption cannot hold.

— pcd - pcdx 11 pcd2. By T-UNIONPCD, T' h pcd1 : û\. û[.U\. u. f±1 . V\. V[ and T' h pcd2 : û2 .

û'2. U2 . u. f_L2 • ^2 • V2- By the induction hypothesis, matchPCDU, pcdx, S) ^ 1 => u = t and

matchPCDU, pcd2,S) £ 1 => u = l. By the definition of matchPCD,

matchPCDU,pcd, S) •£ _L => matchPCDU, pcdj,S) ^ ± or matchPCDU,pcd2,S) # J_

=> u—t

— pcd - pcdi && pcd2. By T-INTPCD and the definition of u, one of the following hold:

- T'H pcdj \ûi.û'l.U\.u.Yi.X'Vi.V[ and T' (- pcd2 :û2.û'2.U2.L. f±2 .%. V 2

- T' h pcdx :MI. M',. (/i.-L. f J_J . V\.V{ and T' h pcd2 :û2.û'2.U2.u. f±2 .%. V2'

So the induction hypothesis holds for the type derivation of one of pcd^ and pcd2. By the definition of

matchPCD,

matchPCDU, pcd, S) ^ _L => matchPCDU,pcd\,S) # ± and matchPCDU,pcd2,S) # _L

=> u = t

— pcd = ! pcd y. Subclaim assumption cannot hold.

Subclaim-n 206

With these three subclaims we can now prove consequent 2 on page 199. The first hypothesis of T-ADV

(see (4.2) on page 200) is:

T' h pcd:l_j.u0.{ui,...,uq).u.fpcd.v. V

Thus, the target type is not J_, nor is the argument type sequence, nor the return type. So the assumptions of the first three subclaims all hold. Furthermore, by the definition of adviceBind, (1b, loc, e, f,T,T'J1 e Ë implies matchPCDU, pcd, S) # 1. Thus:

T'= WOX ••• *Uq — u by construction of AT

= to x u\ x... x Uq -* u by Subclaim 2

x x = to x t\ ... tn — u by Subclaim 3

= ?o x... x —<• u

= to x... x tn —• t by Subclaim 4

We next turn to consequent 3 on page 199. We can this prove consequent with a single subclaim. We use a subclaim that is stronger than the consequent, partly so that the induction hypothesis is sufficientiy powerful. The stronger subclaim will also be useful in proving consequent 4. In the subclaim, var{b) means all variables appearing in b (as defined in Figure 4.15 on page 176).

Subclaim 5. Assume f' h pcd: û.û' .U. û". f±.V'. V". Then matchPCDU, pcd, S) — b = (a,/}o ,---,Px) implies all of the following:

0 b feOK (4.3a)

V' Ç var(b) <= V" (4.3b)

û — 1. <=> a = — (4.3c)

û' = _L <=> Po-~ (4.3d)

U = ± => x = 0 (4.3e)

U^ -L => x=n (4.3f)

U = 1 <==> Vz E \l..x}-(5i - - (4.3g)

Proof of subclaim. 207

— pcd- call( t" idPat{..) ). By T-CALLPCD, F' H pcd: 1.1.1. t".1.0.0. By the definition of matchPCD,

matchPCDU,pcd,S) = b = (a, /Jo,... ,/3x) => b= <-,-)

==> 0h b OK

V' - 0 Ç var(b) Q0 = V"

û = 1 and a - - so (4.3c) holds

û! =1 and = -so (4.3d) holds

U = 1 and x = 0 so (4.3e) holds

U - 1so (4.3f) holds

U = 1 and V i E {1..01 • j8,- = - vacuously, so (4.3g) holds

— pcd = execution( t" idPat(..) ). Similar to the previous case, but by T-EXECPCD.

— pcd = writes(... ). Similar to the first case, but by T-WRTPCD.

— pcd = this( t" var" ). By T-THISPCD, F' h pcd : t". 1.1.1.1.{var"}. {var"}. By the definition of

matchPCD,

matchPCDU, pcd, S) = b = (a,Po,...,f)x) => b = ( var" <— v,-) for some veT

0 h b OK

V - {var"} ç var(b) Q {var"} = V"

û •£ 1 and a - so (4.3c) holds

û' = 1 and Po = - so (4.3d) holds

U = 1 and x = 0 so (4.3e) holds

U - .L so (4.3f) holds

U= 1 and Vi e {1..0Î • f5/ = - vacuously, so (4.3g) holds

— pcd = target( t" var" ). By T-TARGPCD, f' h pcd : _L. t" .1.1.1.{var"} .{var"}. By the definition of 208

matchPCD,

matchPCDU, pcd, S) = b = {a, fio, • • • >Px ) => b = var")

0\- b OK

V' - {var"} ç var(b) g {var"} -V"

û = 1 and a = - so (4.3c) holds

Û' # -L and fio^-so (4.3d) holds

U = -L and x - 0 so (4.3e) holds

U = 1 so (4.3f) holds

U= 1 and Vi e {1..0} • = - vacuously, so (4.3g) holds

1 — pcd - args( t" var ^ ...,t'^ var"w ). By T-ARGSPCD, R' h pcd:±.l.(t",.,.,t'^) .L.L.V'.V" where

1 1 V' = V" = {var ..., var'{v\, and all var ! are unique. By the definition of matchPCD,

J l matchPCDU,pcd,S) = b = (a,Po,---,Px) => b = (-,-,var {,...,var lu)

=> 0\- b OK

V' c var{b) ç I/"

m = _L and a = - so (4.3c) holds

«' = _L and )6o = - so (4.3d) holds

t/^ J- so (4.3e) holds

(/^ J_ and x-w- n by Subclaim 3, so (4.3f) holds

U ^ -L and 3z e {1..0} -/S, ^ - so (4.3g) holds

— pcd= pcdx 11 pcd2. By T-UNIONPCD, let

T' H pcdj :ûi.û\.Ui.û". f J.J. Fi.V(

r' h pcd2 : Û2 . M2 • ^2 • «2 • f x2 • ^2 • V"2

Also let matchPCDU,pcdx,S) — r\ and matchPCDU,pcd2,S) = r2.

By elementary set theory, V' = V\ n V2 => V' Q t/| and V' Ç V2- Dually, Vj Ç V" and V2 Ç V". By the

definition of matchPCD,

matchPCDU,pcd,S) -b= (a, fio fix) ==> b = 1or b= r2 ^ -L 209

Without loss of generality, let b = r\. Then the induction hypothesis gives:

matchPCDU, pcd, S) - b-(a,po, • • • ,Px) \~ b OK

V'QViQ var{b) S V[ S V"

[û = -L <=> a = -)

(û' - 1 <=> - -)

{U = _L => x = 0)

((Y JÉ _L ==> x = n)

([/ =!<=> Vie{l..*}-/3/ = -)

— pcd=pcd± && pcd2. By T-1NTPCD, let

F' I- PCDJ :ZÎI .Û'Y . T/I.Û". FXJ. V].V[

r' h pcd2 :Û2.Û'2.U2. û2. f±2. Va•

Also let matchPCDU, pcdt, S) = n and matchPCDU, pcd2, S) = r2. By the definition of matchPCD:

matchPCDU,pcd, S) = b = (a,/3Q,.. ,,/3x) => n ï L,r2^ _L, and b = r\\^r2

Thus, all the consequents of the subclaim hold for pcd^ and pcd2 Assume matchPCDU, pcd, S) = b-

(a,p0,...,px),let

'"1 =

''2 = (0=2, A),2,2)

and consider each consequent of the subclaim.

- By T-INTPCD, Û = «1 u û2. By the definition of u,

Û = _L => Ml = J_ = Û2

=> a\- -,a2- - by induction hypothesis

=> a = -u- = -by definition of id 210

On the other hand,

«/I => ûj + _L or «2 # -L, but not both

Without loss of generality, let û2 = _L

wi / _L and «2 = -L => «i ^ -,«2 = - by induction hypothesis

=> a = a1 # - by definition of u

So u — — <=> a = --, and (4.3c) holds.

- Similarly, û' = - <==> PQ--, and (4.3d) holds.

- By T-INTPCD, U -U\ U U2. By the definition of u,

U = _L ==> U\ = .L = U2

=> x\ = 0 = X2 by induction hypothesis

=> x = 0 by definition of w

=> Vi e {1..XÎ • /3j = -, vacuously

On the other hand,

U ^ -L => f/j ^ -L or U2 # ±, but not both

Without loss of generality, let t/2 = -L

C/i ^1 and U2 - -L ==> JCI -n,x2= 0,3i e \l..n] • /3;,1 # - by induction hypothesis

=> x-n,Mie {l..xi -/6,• = by definition of w

=> 3i e )] ..x} • fii 7^ —

So {U = — => x = 0), (U ^ — => x = n), and [U — — <=> Vie {l..x}• /6,; = —).Thus, (4.3e), (4.3f),

and (4.3g) all hold.

- The above arguments also demonstrate that var{b) = t,'«r(n) u var[r2), since at each position

at most one of n and /'2 is not Thus, there are no collisions that could cause w to drop a 211

variable that appears in rg- By the induction hypothesis, V\ G var(r\) G V,' and Vg ç var{r-i) Ç V2'.

By T-INTPCD,

VJ' n V^' - 0 wir(ri) n varfo) = 0

=> 0 H FC OK

Thus, (4.3a) holds.

- Finally, T-INTPCD, the induction hypothesis, and some set theory gives

V' - Vi u V2 G var[ri) u varfo) = var{b).

and

var{b) = var(r\) u varir-i) G V[ u V'2 - V"

Thus, V' s var(b) G v" and (4.3b) holds.

— pcd = ! pcdl. By T-NEGPCD F' h pcd: J_. J L. _L. ±.0.0. By the definition of matchPCD,

matchPCDU,pcd,S) = b = {a,pQ,...,px) => b = (-,->

=> 0 b OK

V' = 0G var{b) G0 = V"

û - 1 and a - - so (4.3c) holds

û' - ± and fa = -so (4.3d) holds

U = 1 and x = 0 so (4.3e) holds

U = 1so (4.3f) holds

U = ± and V i e {1..0} • = - vacuously, so (4.3g) holds

Subclaim-•

By T-ADV, the assumption of the subclaim holds. Therefore, consequent 3 on page 199 holds by (4.3a).

Consequent 4 is more complex. To prove this consequent, it will suffice to show that

typeBind{T ,b, (to, • • • ,tn» = var\ :s\,...,uarp:s'p where V i e {l..p\• s- ^ s; (4.4)

We will see that this juxtaposition of tj in typeBind and Sj in the result is resolved by the pointcut descriptor 212 typing rules and matchPCD, which will impose constraints on the types. We use a final subclaim to this end.

Subclaim 6. Assume F' h pcd : û. û'.U. û". f±.V'. V", where V" c j var\,..., varp[. Then

matchPCD{J,pcd,S) = b^ ±

=> Vvare var{b) • (3ie {l-p},^ e 3~• [var = vari, typeBind{T,b,(to,...,tn)) [vari) = s-, and s- 4 s/))

Proof of subclaim. The assumption of this subclaim implies the assumption for Subclaim 5 on page 206; we will make free use of the earlier result.

— pcd = call( ... ). By T-CALLPCD, V' = V" = 0. By (4.3b) on page 206, matchPCD{J,pcd,S) = b ^ _L

implies var(b) = 0, satisfying the subclaim.

— pcd- execution(... ). Similar to the previous case, but by T-EXECPCD.

— pcd~ writes(... ). Similar to the first case, but by T-WRTPCD.

— pcd = this( t" var" ). By T-THISPCD, V' = V" = { var"}. By the subclaim assumption,

var" E {varvarp).

Without loss of generality, let var" = vary. By the hypothesis of T-THISPCD and the definition of F',

t" = S\.

matchPCDU, pcd, S) = b^ ± => b-( var\ •->• loc's, -)

for some loc'^ in /, where

loc' E dom{S) by / ~ S,

S (loc') = [sj. F],5 s| ^ s|, by definition of matchPCD, and

F (/oc') = i''| by F ~ S.

Thus,

typeBind{Y,b,(tQ,...,tn)) - var\ :Ô Sj where ô s[ 4 si.

— pcd - target( t" var" ). By T-TARGPCD, V' = V" = {var"}. By the subclaim assumption, var" E

{var\,...,varp}. Without loss of generality, let var" = var\. By the hypothesis of T-TARGPCD and 213

the definition off', t" - S|.

matchPCDU,pcd,S) = b^l => b= (-,var\)

where to = t" by definition of matchPCD. So % - -si and

typeBind(T,b,{to,...,tn)) - var\ :$\.

— pcd= args( t" var1^,...,^ var). By T-ARGSPCD and the subclaim assumption, all var'! are unique

J and V' = V" = {vai ^ c {var\,...,varp\. Thus,

Mi e • (3!j e {l,.p\ • (t" - sj and var" = varj)) (4.5)

The definition of matchPCD gives

matchPCDU,pcd,S) = b^ 1 => b = (-,-, var",..,,var"w)

where n = w and Vz e |l..w} • (t'! = ti). So

typeBind(I\ b, (to, •..,tn)} = var'l : l" va.r"w : t'^

Let vare var(b). Without loss of generality, let var = var". Now

7 typeBind(T,b,{to,...,tn)) (far /) = t'{.

By (4.5), there exists j such that var*[ = varj and t" = sj, thus the subclaim holds.

— pcd = pcd} 11 pcd2• By T-UNIONPCD and the subclaim assumption, let

r' h pcd^ : zîi. û[.U]. û".f Xj.V\. V[ matchPCDU, pcd} ,S) = r\

r' I- pcd2 : Û2. û'2. Ui. «2 • f±2 • Va • matchPCDU, pcd2,S) = r%

By the definition of matchPCD,

matchPCDU,pcd,S)-b^ ± => b = r\ ^ ± or b = r-z ^ -L 214

So either

typeBind(T,b,{to tn)) = typeBind{\\ r\,(U),•••,tn))

or

typeBind (T,b,(ta,...,tn)) = typeBind [T,r2,(to,...,tn)).

As noted in the corresponding case of the proof of Subclaim 5, £ V" and V2 £ V". Thus, we can

apply the induction hypothesis to the type derivations for pcd\ and pcd2, and the subclaim holds.

— pcd — pcd1 && pcd2. By T-INTPCD and the subclaim assumption, let

r' b pcd] :û\. û\ .U\.û". fx|.V\. V[ matchPCDU,pcd1,S) = r\

r' h pcd2 : fi'2. u2.U 2 • û2 . f±2. V2.V 2 matchPCDU, pcd2, S) = ^

By the definition of matchPCD,

matchPCDU,pcd,S)-b^± => ^ J_ and r2 # J.

As argued in the corresponding case of Subclaim 5, var{r\) and var{r2) are disjoint. Also, since

V" = I/,' u V2', we have V[ £ F" and similarly for V2. Thus, the induction hypothesis is applicable to

the type derivations for pcd\ and pcd2. Let vare var(b). By definition of the union of bindings, var is

in exactly one of var{r\) and var{r2). In either case, the claim holds by the induction hypothesis.

— pcd - ! pcd]. By T-NEGPCD and subclaim assumption, V' = V" = 0.

matchPCDU, pcd, S) = b^ ± => b - {-, -)

=> var{b) = 0

Subclaim-d

With this last subclaim in hand we can now prove the final consequent of the lemma. The first two hypotheses of T-ADV (see (4.2) on page 200) are:

r I pcd. ^ • UQ • ^ ll\,...,llq ^ • II « Y pcd • V • ^

V = {vari,...,varp} 215

By definition of adviceBind, \[b, loc, e,f,T , T'JI E B implies matchPCDU, pcd, S) ^ _L. We first use Subclaim

5 and Subclaim 6 to prove equation (4.4) from page 211.

V = {vari,...,varp) by T-ADV

=^> var{b) = {var\,...,varp} by(4.3b)

=> Vi E{l..p}-3Sj. £5"-

[typeBind(T, b, (to,...,t„)) (varj) = s'v s'. 4 s,) by Subclaim 6

Thus, all vare V are bound appropriately. By examination of the definition of typeBind, we see that

dom(typeBind{T,b,(to,...,tn))) = var{b) = V.

Thus, no additional variables are bound and (4.4) on page 211 holds:

typeBind(T,b, (to,.= van '• s\varp :s'p where Vi e {l..p} • s- Sj

T-ADV gives:

var\ :si,...,var p : sp,th is : a(g\ gq>), proceed : T' , gi : doma i n,... ,gqi : doma i n. f \-DTa e : s'

==> by Lemma 4.13

van :s[,...,varp: s'p, this: a(g\,...,gqi), proceed :r',gi : domain,..., gqi : domain, f \-DTae\s"

where s" ^ s' and Vi E {l..p}• s'. 4 s,

=> by (4.4)

th is : <Î(gi,... ,gqt), proceed : T', typeBind(T, b,(to,...,tn)},g\ : domain,...,g qt : domain, f h-DTae:s"

=> by Lemma 4.9, with appropriate «-conversion of b and e

r,this:ti(gi gqi), proceed : r', typeBind [T,b, (to,...,tn)),g\ : doma in,..., gqi : domain, f \-DTa e : s"

=> by concern-completeness of T, Vz E {l..<7'} -R(GI) = domain

T, this : a(gi,... ,gqi), proceed : T', typeBind (F, b,(to,.. .,tn)). f \-DTa e : s"

By the definition of evaluation dependency table (see Definition 4.1 (Evaluation Dependency Table) on

page 172), DTa c DT and Vy e f • (y, y) £ DT. The advice body expression e contains only user syntax, by

the construction of AT. Thus Lemma 4.7 (Dependency Table Extension) on page 187 gives:

T.this : a{g\,... ,gqi), proceed : t', typeBind (T,b,(to,...,t„)). depCloseDT (f) \~DTe: s" 216

Another hypothesis of T-ADV gives s' =4 s ^ u. By transitivity of subtyping s" =4 u - t. Thus the final

consequent holds. • I I

The Advice Chaining lemma handles sets of writable concern domains in join point abstractions and advice body tuples. The basic claim—replacing all proceed subexpressions in a well-typed expression with appropriate chain expressions does not change the expression's type—remains unchanged.

I I x x Lemma 4.15 (Advice Chaining). Let T, proceed :T .f I-DTe:t, j = (L,L_J,,_1,1_1,T,y"D, T = ?o tn — t,

(readonly(to) - readonly) => [f" — 0), andforall \[h, loc, e', f', r', rj] e B let

— Y, this \T {loc), proceed : t , typeBind {Y,b,(to,...,tn)). depClose (7') e':s',

— T\-b OK,

— depClose(f) G depClose(f") G y, and

— s' =4 t.

ThenT.f\pT({e))Sj:t.

Proof. The proof is by structural induction on the type derivation for e. In the base case, the type derivation

for e is by one of T-NEW, T-OBJ, T-VAR, T-LOC, or T-NULL. For all of these rules e does not contain a

proceed expression. Therefore, «e» g : = e and the claim holds by Lemma 4.10 (Environment Contraction)

on page 194.

The induction hypothesis is that the claim holds for all type derivations smaller than the one for e. For

all the remaining expression typing rules but T-PROC, the claim follows immediately from the induction

hypothesis. So the only interesting case is for

e= eo.proceed( e\,...,en ) and

((e))B,J = chain B,j( «eo»Bj,...,«e„»Sj- )

Assuming that F, proceed:!.Y L-GJ e\ t, we need to show that F.y \^T ((e))^ . : t. The latter must be by T-CHATN,

so we must establish the hypotheses for that rule. Now the last step in the type derivation for e must be

T-PROC:

VZ e j0..ZZ} -F,proceed:T.y \-DTei : M; VZ e {0..nj • U{ =4 tf

F, proceed : T .y eo-proceed( e\,...,en):t 217

By the hypotheses of this judgment and the induction hypothesis, we have:

Vi e {0..rc} T ((ei))g j : M; where ut 4 f,

The remaining hypotheses of T-CHAIN hold by the assumptions of the lemma regarding B and j, thus

T.fhDT{(e))Éij:t. •

Finally, the Join Point Abstraction lemma also handles sets of writable concern domains.

Lemma 4.16 Uoin Point Abstractions). In a MiniMAOi program evaluation, if a join point abstraction, j,

appears in the expression of an evaluation triple, then one of the following hold:

1. Either j = flexec, v, m,l,r,fP and I = fun m ( var^varn }.c:t .f, or else

2. j = flea//,-,m,-,Uo x ... x t;n — r),f|), methodType{to, m) = t\ x... xtn — t, and writable(to,m) =f.

Proof Join point abstractions are not part of the user syntax of MiniMAOi. By inspection, the only eval­

uation rules that can introduce new join point abstractions in the expression of an evaluation triple are

EXECA and CALLA. Only EXECA introduces exec join point abstractions, and these abstractions satisfy part

1 of the lemma. Only CALLA introduces call join point abstractions. By the definition of origType, these call

join point abstractions satisfy the part 2 of the lemma. •

4.4.2 Type Safety

As for MiniMAOi, I prove the soundness of MiniMAOg's static type system using the standard subject reduction and progress technique.

I update the statement of the Subject Reduction theorem to consider the public concern domains declared in the program, a set of writable concern domains, and the evaluation dependency table. The proof differs substantially from that for MiniMAOi, as one would expect given the magnitude of the changes to the static semantics. The greatest difficulty is handling the evaluation steps that introduce tagged expressions, ExECg and ADVISE. The typing rule for tagged expressions, T-TAG, uses a different set of writable domains for typing the contained expression. I leverage the various subset relationships on sets of writable concern domains (and their dependency closures) to handle these cases. 218

Theorem 4.17 (Subject Reduction). Given a well-typed program P with public concern domains gcW, for an expression e, a valid store S, a stack J consistent with S, a concern-complete type environment Y consistent with S, a set of public concern domains fGg, and the evaluation dependency table, DT, ofP, if r.f t and (e,J,S) •— (e',J',S'), then ]' » S', S' is valid, and there exist concern-complete Y' « S' and t' =4 t, such that F'. f ^,T e' : t'.

Proof The proof is by cases on the evaluation rule applied. We note that the evaluation rules obey a monotonicity property with regard to the store: none of evaluation rules remove a location from the domain of S, nor do they change the type of the object in any store location. By the monotonicity property,

S valid implies that part 1 of Definition 4.5 (Store Validity) on page 186 holds for S' in each case of the proof. Based on the reduction step, in each case we demonstrate how to construct a F' consistent with S' that witnesses to the validity of S' and satisfies the claim. I omit the dependency table subscript on type judgments and uses of the depClose auxiliary function, unless the dependency table used differs from DT.

Case 1—NEW. In this case

e = E[new c()]

e' = E [loc]

loc £ dom{S)

/' = /

S' = S©(/oc-» [c(gi,...,g„>.F])

, F={/ -»null-/e dom[fieldsOf(c(g\,...,gn}))}.

LetY' -Y,loc:c{gi,...,gn).

By the monotonicity property of the store, J' — J => J' ~ S'.

We now show that F' = S'. Because loc t dom{S), (F » S) => loc £ dom{Y) by part 2 of Definition 4.3

(Environment-Store Consistency) on page 185. Thus part 1 of the definition for F' = S' holds for all loc' e Jzf, lod # loc. Now S'(loc) = [c(gi,...,g„).F], Y'(loc) = c(gi g„>, dom(F) - dom[fieldsOf{c{gi,...,gn})), rng(F) = {null} G dom{S) u {null}, and 1(d) holds vacuously. So part 1 of r' ~ S' holds. Parts 2 and 3 hold because F =s S, loce dom(Y'), and loce dom[S').

We now show that F'.f h E[/oc]:f. By Lemma 4.9 (Environment Extension) on page 193 and loct dom(Y), we have F'.f h E[new c(gi,...,g„>()] : t. Now F'.f h new c() : c(gi,...,g„> (by P well-typed 219

and r' concern complete) and F'.f h loc:c{g\,...,gn), so by Lemma4.11 (Replacement) on page 194,

T'.f HE\loc\:t.

Case 2—CALLa. Here

e = E[locg.m( v\,...,vn )]

e' = Eljoinpt (|call,-,m,-,(s0x... xsn — s),f'6( locs, v\,...,vn )]

S(loc) = \u.F]

methodType{so, m) - si x... x sn ->• s

writable(s{), m) = f'

origType(8 u, m) - so / = /

S' = S

Let r' = T. Clearly Fz = S' and /' = S'.

We now show that F.f h e':t. The judgment F.f h e: t implies that locg.m( vn ) and all its subterms are well typed in F. Let F.f h Vj : tj for all z e \\..n\. By part 1(a) of T ~ S and T-Loc, F.f h locg-.Ô u. The type judgment for locg.m( vi,...,vn) must be by T-CALL with Vz e {1 ,.n] • F, = (f = 0). By the definition of origType, ô u ^ T-JOIN gives:4

F. y h locg : 8 u vt:ti depClose[f')Gf

5 u^,so Vz E {l..n} • tj =4 Sj (5 = readonly) => (f' - 0)

r.fh joinpt (]call,-,z7i,-,(sox... xs„ — s),f'D( locg, v\,...,vn):s

Therefore, Lemma 4.11 (Replacement) on page 194 gives T .j\- e' :t.

Case3—CALLB- Heree = E[chain •,Ocall,-,M,-,T,f'D( locg, v\,...,vn )],

S(loc) = [ to. -F] and methodBody{5 ZO, m) - /), /' = /, and S' = S.

Let r' - T. Clearly F' = S' and /' = S'.

4 I omit the v0pt hypothesis because is not a location. 220

We now show that T.f h e' : t. Let = chain • Jcall,-, M,-,T,f'|)( loc§, v\,...,vn). The judgment

T.f I- e:t implies that C|EFT and all its subterms are well typed. Let F.f H v, : f; for all i E (],.n) and let

F.f h 6|eft : s. By part 1 (a) of F «S and T-Loc, F.f h Iocs :5 to. The type judgment for must be by

T-CHAIN with T of arity n +1 and return type s. Let T = SO*... xsn —• S. Then T-CHAIN gives ô to 4 so, ti = (f = 0).

By Lemma 4.16 (Join Point Abstractions) on page 217, it must be the case that methodType{so, m) = si x... x sn —» s. By the correspondence between the definitions of methodType and methodBody, it must be the case that I = methodBody{6 to, m) =fun m(this, var\,...,varn).e" : [u x sj x... xs„ — 5) .f, for some u,ôto=4 u- Now8 = readonly implies F = 0 (from T-CHAIN) and readonly{u) = readonly (from definition of subtyping). By T-CLASS, T-MET, and override, we have r, this : u, var\ : s\,...,varn : sn. f \-DTm e" : s' for some s' s and V (7,7') £ DTm - 7 = 7' (where we are relying on the hypotheses of T-MET that relate readonlyiu) in this judgment to whether or not 7' includes the home domain of the self object, and hence whether or not 7' is empty). By the definition of the evaluation dependency table, Vg £ g • (g, g) £ DT. So

DTm Ç DT. Because e" is a method body, it only contains user syntax. Thus, by Lemma 4.7 (Dependency

Table Extension) on page 187, r,this : u, var\ \ s\,...,varn \ sn .depClose DT (f) \-DTe" :s'

Thus, T-EXEC gives

r, this : u, var\ :s\,...t var„ : sn.depClose (7) h e" : s'

s' =4 s R .7 h locg'. 5 to V Z E {1.. M} • r. 71- Vj: tj

ô to =4 u Vie • ti 4 s,- depClose(f') G 7 (5 = readonly) => (f' = 0)

F. 71- (fun m(th\s,vari,...,varn).e" :(u x si x... xsn — s).f' ( locg, v\,...,vn))-s and Lemma 4.11 (Replacement) on page 194 gives F.7 h e' : t.

Case 4—EXECA. Here e = E[( l ( vo,...,vn ) )] (where Z = fun m{varo,...,varn).e" : (SQ x ... x SN s) .f), e' = Eljoinpt {exec, v0, m, Z,(s0x... xs„ — s),f'|)( v0,...,vn )], J' -J, and S' = S.

Let F' = F. Clearly F' = S' and ]' ~ S'.

We now show that r.7 h e':t. The judgment F.f h e:t implies that ( l ( ('o v„ ) > and all its subterms are well typed. Let F. 7 h vt : ti for ail i e |0..»}. The type derivation of( l ( vo,...,vn)) must be by T-EXEC with F. 7 h (I (vo,...,v„)):s, ti 4 Si for all i e {0..«}, depClose{f) G 7, and [readonlyi to) = readonly) =>

(7' = 0). If VQ is a location, then F.f h VQ: to must be by T-Loc, so the location of VQ is in dom(T). Thus,

X x F.f I- joinpt (exec, VQ, m, Z,(SO ••• sn —• S),F'D( vo,...,vn):sby T-JOIN. Lemma 4.11 (Replacement) on page 194 gives T.7 H e' : t. 221

Case 5—EXECB- Here

e = Elchain », (exec, v,m,l,{s0x ...*sn — s),f'|)( v0,...,vn )]

I =fun m{varo,...,varn).e": (so*... x.sn — s).f'

e' = E[under (e"lvo/ varo,...,vnl varn\)ôiy]

readonly(s) - 5'

]'— (this, vo, — D + /

Let T' = T. Clearly r' = S'.

x x We now show that /' = S' = S. Let e|eft = chain «Jexec, v, m, I, (so • • • sn — s),f'D( vo,...,v„ ). Because

e is well typed, it must be the case that e\(^{ and all its subterms are well typed. Let F.f h (/,- : t, for all

i E If vo = null then no new locations are added to the join point stack, so / ~ S'. On the other

hand, if vo = loc§ then the judgment F.f h locg : to must be by T-Loc with loc e dorn(Y). By F = S, we have

loc E dom(S). Because J ~ S and loc is the only potentially new location in we have that /' = S.

To complete the case, we will next see that T. f H e' : t' for some t' =4 t. Rule T-CHAIN must be the last step in the type derivation for g|eft with F.y h : s. The second hypothesis of T-CHAIN says that tj =4 Sj

for all i £ {0..n}.

= :5 Let e^ight under {e"\vo! varo,...,vnl varn\)Si^i. We now show that F.f h erjght ' for some s' =4 s.

That is, we want to show:

F .depClose(f') h e"\vo! varo vnt var,,}: u depClose(f') G y T-TAG

F.f h {e"lvo/ varo,...,vn! varnl)si ^:ô' u ' T-UNDER F-f I- ®right • ^ where s' = ô' u. The hypothesis depClose(f) G f in this derivation is an hypothesis of T-CHAIN. We will appeal to the Substitution Lemma to show the other hypothesis. To do this we must first show that

T, varo'• so,..., var n : sn. depClose (f) I- e":u for some u such that 5' u = s' ^ s. No fun terms may appear

in user programs; they can only be introduced by the evaluation rules. By examination of the evaluation

rules, we see that the only rule that introduces a new fun term is CALLB- The term it introduces is provided

by the methodBody auxiliary function. By the definition of methodBody and by T-MET it must be the case 222

z that varo:so,...,varn:sn.f \-DTm e" : u, where u -4 S and V (y,y ) E DTm-j-y' (i.e., DTm is just reflexive).

As in Case 3, Lemma4.7 (Dependency Table Extension) gives varovar,,: .depClose(f) ly,-, e": u.

We need to show 8' u^, s. But readonly(s) = 5', so by the idempotency of read-only annotations s = ô' s.

Thus {u =4 s) => [ô' u =4 S' s = s).

By «-conversion and Lemma 4.9 (Environment Extension) on 193 we have F, varo '• so,...,var,, : s„.

depClose (f) e" : u. Thus, by Lemma 4.8 (Substitution) on page 188,

F. depClose (y') h e" jVQ / varo ",i / var,,| : u' where 8' u' =4 8' u =4 s. So Lemma 4.12 (Replacement with Subtyping) on page 194 gives T. y I- e' : t' for some t' ^4 t.

Case 6—GET. In this case e = E [locg.f], e' = E[f^] (where S{loc) = [T(j\,...tjn).F], F(f) = v, and

readonly (fieldsOf (8 T) (/)) = Ô'), / = /, and S' = S.

Let T' = F.

Clearly F' = S' and ]' ~ S'.

We now show that F.y h Eli>s'} : t' for some t' ^ t. If v = null, then this is immediate by T-NULL

and Lemma 4.11 (Replacement) on page 194. So assume v - loc'. Let F.y h locg.f:s. The last step in this

derivation must be T-GET. By T ~ S, we have F(/oc) = T{ji,...,jn). By the second hypothesis of T-GET,

/ fieldsOf (ô T{j\,...,jn>) (/) = s= 5' S(y'1,...,y p) for some Sandy^,...,y^. Also by T » S, S (loc?) -\ u' .F']

and F (loc/) - u!. Thus, F.y h loc'g, :8' u'. It remains to be seen that 8' u' =4 s.

Now there are two subcases depending on the values of 8 and readonly (fieldsOf (T(j\,...,j„)) (/))—

call this later value 8". Note that 8" is the read-only status of the field as declared, ignoring the value of

8.

Subcase l.IfS = e and 8" = e, then part 1(d) of F = S gives u' =4 s. Furthermore, by the definition of fieldsOf, 8' = e. Thus 8' u' =4 s.

Subcase 2. If 8 = readonly or 8" - readonly, then by the definition of fieldsOf, 8' - readonly. By part

1(d) of F a S, 8" u' =4 s. Finally, by idempotency of readonly and the definition of subtyping, 8' u' =

readonly u' = readonly 8" u' =4 s.

So in either case, Lemma4.12 (Replacement with Subtyping) on page 194 gives F.f h E{loc'g,} : t' where

t' =4 t. 223

Case 7—SET. In this case e = E[locg.f = v). Because e is well typed, we know from T-SET that 8 — e, so we can omit it for the remainder of the case. Also e1 = E [v],j' = j, and S' = S® (Zoc— [u.F © (/ >— v') ] ), where

loc' if v = lod5, S{loc) - [u.F] and v' — < null otherwise

Let f = r.

By the monotonicity property of the store, )' - J => J' ~

We now show that T ~ S'. S' only changes in its mapping for loc. To see that part 1 of the consistency

definition holds, note that S'{loc) = [u.F® (/— v')\. For part 1(a) I [loc) = u, since S(Zoc) = [ u. F\ and

F ~ s. For part 1(b) dom [F © (/ -- v')) - dom [fieldsOf (u)), since loc.f = v is well typed.

For part 1(c), rng(F© (/ —» u')) - mg{F) u {v'\. Now since loc.f = v is well typed, we have either

v = nullg, or else v = loc's, and lod e dom{Y). In the latter case, by F = S, we have lod e dom(S). And

lod e dom(S) implies lod e dom(S'). So in either case rng(F) u {v'} s dom[S') u{null}.

Part 1(d) holds for all /' e dom(F), f # /. Part 1(d) holds vacuously for / if v = null^/. Otherwise, by

T-SET and T-Loc, F(f') =4 fieldsOf (u)(f). Part 1(d) holds because (F© (/•-» v'))[f) — v' and ô" F(c) 4 fieldsOf {u)[f) for all values of 8" (by the definition of subtyping).

Parts 2 and 3 hold since dom(S') = dom(S).

To see that F.y H EM : t, let F .fh loc.f = v : s. By T- SET, F.y H V:S and by Lemma 4.11 (Replacement)

on page 194, F.y h El^] : t.

Case8—CAST. Here e = E[cast t" locg], e' = ElZocgj, ]' = J,S' = S, S{loc) = [u.F], and 8 u ^ t".

Let r' = F.

Clearly F' « S' and /' = S'.

To see that F.y h E[locg] : t' for some t' -4 t, note that F(Zoc) = u by consistency of F with S. Thus

F.y h locg :8 u. By T-CAST, F.y h cast t" locg :8 t".

If 8= readonly, then 8u=4 t" implies readonly (t") = readonly. By idempotency of read-only annota­

tions, 81" = readonly t" = t". If 5 = e, then ô t" -et"- t". In either case, 8 u -< t" = 8 t", so by Lemma4.12

(Replacement with Subtyping) on page 194 we have F.y I- E\locg\ : t' where t' 4 t.

Case9—NCAST. Here e = E[cast 8 T(j\,...,jn) nullô/], e' = E[nullô/], J' = J,S' = S, and either8 = readonly

or 8' = £.

Let R' = r. 224

Clearly T' = S' and / ~ S'.

NowF.y I- cast <5 T{y\,...,yn) null5/:Ô T(yi,...,yn>. By T-NULL, Y.y H nullg, :8' t" for any t" E S". We want 8' t" =4 8 T{y\,...,yn). If <5 = readonly, then let t" - readonly T{ y\,...,yn)'< by idempotency of read­

only annotations, the value of Ô' does not matter. On the other hand, if 8' = e, then let t" = ô V'(yi,... ,yw).

In either case, by Lemma 4.12 (Replacement with Subtyping) on page 194, F.y h E|null5/| : t' for some

t' =4 t.

Case 10—SKIP. Here e = E[v; e"], e' - E[e"], /' = /, and S' = S.

Letr' = r.

Clearly T' = S' and /' = S'.

Since T.y\~W\v, e"\ : t, let F. y I- v; e" : t". This derivation must be by T-SEQ, the second hypothesis of

which says F. y h e": t". By Lemma 4.11 (Replacement) on page 194, T.y h E|e"l : t.

Case 11—BIND. Here:

e = Etjoinpt OA:, vopt,mopt,lopt,{so*...xsn — x),f'[)( v0,...,vn )]

e' = E[under chain Ë,<\k, v0fH ,mopt, lopt, (s0x ...*sn^ s),y'U v0,...,vn)\

x x B - aduiceBindUk, vopt, mopt, lopt. (so • • • sn •— s),y'|) + /,S)

J' = Hk, vopt,m0pt,l0pt,{sQX ...xsn s),y'H J

S' — S

Let F' = F. Clearly F' = S'.

We will see that /' = S'. Let

C|eft — joinpt dk, vopi, rrioptt lopt> (SQx ...xsn —> s),y D( VQ,...,vn ).

Because e is well typed, it must be the case the e|ol> and all its subterms are well typed. The typing derivation

for E|EFT must be by T-JOIN with F. y h :s. Thus, if vopt is a location it must be in dom{D and so /' = S'.

It remains to show that F. y I- e' : t. Let

e — x x right chain B, dk, VoPt> wiopti lopt> (so • • • sn —• s), y D( VQ,..., vn ). 225

so we (By T-UNDER, ERIGHT has the same type as under e^GHT' can focus on the smaller expression.) The

typing judgment for E^GHT must be by T-CHAIN. SO we next show that all the hypotheses of T-CHAIN are satisfied for eright-

By the well-typedness of

ti =4 Si for all i e {0..n}, depClose(f') Qf, and (readonly{uo) = readonly) => (f = 0).

The remaining hypotheses of T-CHAIN are related to the elements of the advice list, B. Let

B - \[b,loc,e" ,f" ,T,T' FT

be an arbitrary element of B. By the definition of adviceBind, it must be the case that there exists a piece of

advice with advice table entry ( loc, pcd, e" ,j" ,x,r') such that matchPCDU', pcd, S) - ±. By Lemma 4.14

(Binding Soundness) on page 199 we have:

depClose(f") Ç depClose(f1)

T' = 50X ... XSn —• S

0I-6OK

F, this : F(/oc), proceed : T', typeBind{T, b, (so s „)). depClose (f') h e" : s' for some s' -4. s

By appropriate a-conversion of b and e", we have F h b OK. The remaining hypotheses of T-CHAIN are

satisfied directly by the results of the lemma. Thus, F.f h e^ight: 5 and by T-UNDER and Lemma 4.11

(Replacement) on page 194, T.f t- e' : t.

Case 12—ADVISE. Here

e = Etchain \[b,loc,e",f ,T',T"J\ + É,j( v0,...,vn )]

e' = E[under (((e"))§jlloclth\s\l{vo,...,vn)/ b\)s>f\

readonly (T') =8

/' = (this, loc, + J

S' = S

Let T' = T. Clearly F' = S'. Because il-j] terms can only be added to a program by the auxiliary function

adviceBind called by BIND, we know from the definition of adviceBind, and the validity and monotonicity 226

of S, that loce dom(S). By V = S, we know loce dom(T). Thus, /' = S'.

It remains to be shown that T. f h e' : t' for some t' ^ t. Let

eleft ~chain fib,loc,e",F',T,T'J1 +B,J'{VQ v„) and

erjght = ((e"))Èj$loclth\s\Uvo,•••,vn)l bl

Because e is well typed, we know that e\e^ and all its subterms are also well typed. The type derivation

for E|EFT must be by T-CHAIN. Let the last two elements of j be to X... x tn ->• tm and YM. Then by T-CHAIN

the proceed type t' = tox... x tn — tm, depClose(fm) G y, and F.f h : tm. We want to show that

F.f h under ô,f : u for some « ^ tm. That is, we want to show:

: l z F. depClose (f') h en„ht 'm depClose (f ) G f T-TAC, r.y h (^right^ô.f 'Ô 4n T-UNDER

F.f h under (eright>ô^ :ô t'm (4.6)

where Ô t'm ^ tm. From the hypotheses of T-CHAIN, depClose(f) G depClose{fm) G f. So the second

hypothesis of the above derivation holds. The first hypothesis will require a bit more effort.

From the hypotheses of T-CHAIN, we have

T, this : F(Zoc), proceed : (to x... x tn —• tm), typeBind (F, b,(to,...,t n)). depClose[f) e" : s

where S ^ tm. The constraints on B and j imposed by T-CHAIN satisfy the conditions of Lemma 4.15

(Advice Chaining) on page 216, so we have

F, th i s : F ( loc), typeBind (T,b, (to, •••,!„}). depClose (f') h ((e")) y j: s (4.7)

Next we will appeal to the Substitution Lemma. To do so, we will need to expand typeBind so that we

can demonstrate that the conditions for the lemma hold. Let b- (a,/5o,---,Pp). Assume a - va/ <-« loc'f;

5 and (3q - varo. Then (4.7) expands to

1 F, this : F(/oc), var : ô F (loc'), (vart : U)ia\[)..p\-fii=vari • depClose(y') b ((e"))gj : s. (4.8)

5The argument connecting typeBind to binding substitution is similar if a (resp. /3Q ) is but with typings and substitutions for var1 (resp. varo) omitted. 227

The binding substitution in erig|lt expands to give

e fright = « "»jsj S lod this, loc'gl var* ,(Vil vari)i€{0 p].p.=var. g. (4.9)

By the hypotheses of T-CHAIN in the typing of 6]eft we have Vi e \()..n\ • (F.y h Vj : u! where i/. ^ r,-).

Each of these typing judgments must be by T-Loc or T-NULL, neither of which uses y in its hypotheses. So

6 we have V i e ([)..«} • (F. depClose (f) H Vj : u'i where u'i =4 tj). Using these judgments, along with (4.8) and

: (4.9), Lemma 4.8 (Substitution) on page 188 gives F. depClose{f) h e^ight 4n where t'm =4 s =4 tm.

Now suppose 8 = e, then 8 t'm = t'm =4 tm.

On the other hand, suppose 5 = readonly. Recall that readonly{tm) = 8, thus readonly Zm = tm. So

8 t'm = readonly t'm - readonly tm = tm.

So (4.6) on the preceding page holds. By Lemma 4.12 (Replacement with Subtyping) on page 194,

r.f\-e':t'ioT some t' ^4 t. Whew!

Case 13—UNDER. Here e= E[under v],e' = E[v], J = j + j' for some j, and S' = S.

Let r' = r.

Clearly F' ~ S'. Since the set of location is ]' is a subset of those in J,J' ~ S'.

We now show that F. y I- e' : t. The judgment F.y h e: t implies that under v is well typed. Let F.y h

under v: This judgment must be by T-UNDER with the hypothesis F.y H v: t'. So by Lemma 4.11

(Replacement), we have F.y I- e': t.

Case 14—TAG. Here e = ElM&fl, e' = /' = I, and S' = S.

Let T' = F.

Clearly F' = S' and /' ~ S'.

We now show that Y. y h e' : t. Because e is well typed, it must be the case that is also well typed.

Let F. y h {v)s^r.8 s. This must be by T-TAG with F. depClose [f) H v : s and depClose(f) Çy.

If v = NULL#/, then T-NULL gives F.y H Vg:8 s. On the other hand, if v = locgi then F. depClose(f) H v: s

must be by T-Loc: with loce dom{S). So T-Loc gives F.y h vg:8 s. In either case, Lemma4.11 (Replacement)

gives r.fl-e':f.

6 Intuitively, the values Vj in these judgments were generated by either the code that created the join point j, or by a previous piece of advice in the chain. In either case, they may have been generated using a different set of writable domains. That does not matter for execution of the advice, just as we do not care about the writable domains used to generate the actual arguments to a method call. 228

The remaining evaluation rules reduce e to some exception, which is not an expression. Thus, those

rules are not applicable to the theorem. • I I

The statement of the Progress theorem includes the public concern domains declared in the program, a set of writable concern domains, and the evaluation dependency table. It also considers that values may now have read-only annotations. These changes do not affect the result, or the proof, in a substantial way.

I 1 Theorem 4.18 (Progress). Given a well-typed program, P, with public concern domains g c (/j, for an

expression e, a valid store S, a stack J consistent with S, a concern-complete type environment T consistent

with S, a set of public concern domains fQg, and the evaluation dependency table DT, such that the triple

(e,}, S) is reached in the evaluation ofP, ifT. y \-DT e: t then either:

— e- locg for some Ô and loce dom(S),

— e = nulls for some 8, or

— one of thefollowing hold:

- (e,J,S) (NullPointerExceptionj' ,S')

-

1 Proof If e - Iocs, then T.y \-DTIocs '• by T-Loc. This means that loce dom(T) and, since r ~ S we have

loce dom{S).

lie - nulls, then the claim holds.

Finally, when e is not a value we consider cases based on the current redex of e. Cases where the redex

matches NEW, ADVISE, EXECA, SKIP, BIND, TAG, NCALLA, NCALLB, NGET, and NSET are trivial. For the

remaining cases we must show that the side conditions hold for the relevant evaluation rules, and that the

join point abstractions are of the correct form. I omit the DT subscript for the remainder of the proof, with

the understanding that the same dependency table is used throughout.

Case I—e = E[locg.m( v\ vn /]. Because e is well typed, F.y h locg : ô s for some type s. Thus, loce

dom{T), and part 2 of F = S implies loce dom(S). Let S(loc) = [s'.F], Now s' = s by part 1(a) of F = S.

Because locg.m( v\,...,u„ ) is well typed, we know by the hypotheses of T-CALL that methodType{8 s, m)

yields an rc-arity method type and writable(8 s, m) is well defined. By the definition of origType, we know

that origType{8 s) = to, where 8 s -< to. By T-CLASS, T-MET, and override, we know that methodType{to, m)

also yields an n-arity method and writable(to, m) is well defined. Thus, {e,J, S) evolves by CALLA- 229

Case 2—e = E[chain B,j( vq vn )|. If B is non-empty, then evolves by ADVISE. Otherwise, we must consider cases based on the value of j. By Lemma 4.16 (Join Point Abstractions), there are two cases:

— j - (exec, v, m, Z,T,y'D: By Lemma 4.16, Z = fun m(varo,...,varn}.e: x . f. Thus, (e,],S) evolves by

EXECB.

— j = (call,-,m,-,T,y|): There are two subcases. If vq = null#, then (e,J,S) evolves by NCALLB to a

triple with a NullPointerException. Otherwise, vq is a location. Let vq - loc§. Because e is well typed

u we have F.y Iocs'.S q for some u'Q; this is by T-Loc with loce dom{T). By T ~ S, S{loc) = [ u'{). F]. Let

X x T = FO ••• tn —• t, where the arity is n+ 1 by T-CHAIN and the well-typedness of e. By Lemma 4.16,

methodType(to, m) = t\x... x-tn •— t. Also by T-CHAIN, Ô u'{) ^ Iq. By the correspondence between the

definitions of methodType and methodBody, and by the definitions of T-CLASS, T-MET, and override,

it must be the case that there exists a fun term Z such that methodBody{8 u'0,m) = I. Therefore, (e,J, S)

evolves by CALLB in this subcase.

Case 3—e = E[locs-f]. As in Case 1, e well typed implies S(loc) = [s. F\ where F(loc) = s. Now locs-f well typed implies f e dom [fieldsOf {8 s)) by the hypotheses of T-GET. Finally, part 1(b) of F = S gives

/ e dom{F], so (e,J, S) evolves by GET.

Case 4—e = E[Zocg./ = v[. Similar to the preceding case.

Case 5—e = E[casf t' Iocs1- As in Case 1, e well typed implies S{loc) = [s.F], where T(loc) = 5. If 8 s =4 t', then (e,J,S) (E[Zocg],/,S) by CAST; otherwise (e,J,S) (ClassCastExceptionJ, S) by XCAST.

Case 6—e = E[cast 8 T{j\ y„) null5'[. If 8 = readonly or 8' = e, then (e,J,S) •— (E[nullg,],/,S) by

NCAST. Now

-i(

= {8 = E and 8' -readonly).

So if (e,J,S) does not evolve by NCAST, it must evolve to (ClassCastException,/, S) by NXCAST.

Case 7—e = Elunder v\. In this case, we only need to argue that the stack, J, is not empty. Note that under expressions are not part of the user syntax. These expressions are only introduced during the evaluation of a program, by rules BIND, EXECB, and ADVISE. Each of those rules also pushes a join point abstraction onto the stack. The UNDER rule removes the under expression and pops the stack. Thus, 230

the size of the stack corresponds to the number of under expressions present in the expression. The

presence of an under expression in the evaluation context implies that the stack is non-empty. Therefore,

(E[under v],j + J,S) ^ by rule UNDER. • i i

In MiniMAOg, the Type Safety theorem considers that values may now have read-only annotations. This change does not affect the result. I update the proof to establish the conditions under which the main expression of the program is well typed. This is slightly more involved than in MiniMAOi, where the T-PROG rule typechecks the main expression in an empty environment. In MiniMAOg, T-PROG typechecks the main expression using a judgment that has a non-empty type environment, a set of writable concern domains, and a dependency table that does not match the evaluation dependency table used in the Subject Reduction and Progress theorems. However, after establishing the appropriate initial conditions, the proof follows immediately.

I I Theorem 4.19 (Type Safety). Given a program P, with main expression e, concern domains g, h P OK, and

a valid store So, then either the evaluation ofe diverges or else (e, •, So) •— (x, J, S) and one of the following

hold for x:

— x= locg for some ô and loce dom(S),

— x = nulls for some ô,

— x = NullPointerException, or

— x= ClassCastException

Proof If e diverges then the claim holds. If e converges, then note that the empty stack is consistent with any

store, the validity of So implies the existence of an initial type environment consistent with So, and h P OK

implies F. g hD7p e: t for some t, where DTP = Ugeg (g>g)- Let DT be the evaluation dependency table

for P. By Definition 4.1 (Evaluation Dependency Table) on page 172, DTP ç DT and Vg e g • (g, g) e DT.

Because e is the main expression of the program, it only contains user syntax. Also, because g includes

every concern domain in P, g = depCloseDT (g). Thus, by Lemma 4.7 (Dependency Table Extension) on

page 187, Y.gY~DTe\t.

The proof (by induction on the number of evaluation steps) follows from Theorem 4.17 (Subject

Reduction) on page 218 and Theorem 4.18 (Progress) on page 228. • 231

4.4.3 Effects Properties

MiniMAOz includes features that let programmers control effects in two ways. With read-only annotations,

programmers can write code that captures object references, while keeping that code from mutating the

referenced objects or their representations. With concern domains and effects clauses, programmers may specify the domains that a piece of code is intended to modify. These specifications allow the type system

to help the programmer by pointing out code that differs from its specified intent. These specifications also serve to document the possible side effects of a code block during maintenance. In this section, I show that

the features of MiniMAOa really do allow such control of effects. In particular, I show that a reado n I y pointer

cannot be used to mutate the object to which it points, or any object reached through that pointer. I also show

that, given the aspect instantiation instructions and dependency declarations for a program, for any code

block (either a method or piece of advice) the only domains that may be mutated by executing the block are

those listed in its effects clause, plus those domains that vary with the listed domains.

4.4.3.1 Effects Clauses

I treat effects clauses first. I begin by introducing a notation for describing the portion of a store that

appears in a given concern domain.

I I Definition 4.20 (Concern Domain). Let S be a valid store for a well-typed program P. For any concern

domain name g, the concern domain g in the store S, written S|g, is:

S|g = {(/oc-» [r.f]) eS-gi =g}.

The following lemma says that the expression typing rules in MiniMAOa obey a monotonicity property:

any writable domain set used in the environment of an hypothesis is a subset of the writable domain set used

in the judgment.

I l Lemma 4.21 (Expression Typing Monotonicity). IfT.fbj)Te: t, then for any subderivationY' .f hoTe' : t',

it is thecase thatf s f.

Proof The proof is immediate by inspection of the typing rules. • I I

Consider a tagged expression (e)gtf. Intuitively, such an expression is introduced to the evaluation triple

when a method or piece of advice begins executing. Theorem 4.23 (Tag Frame Soundness) below states that 232

the evaluation of such an expression may only mutate the concern domains in the dependency closure of f. All other concern domains are immutable until the tagged expression has been reduced to a value. The following lemma is useful in proving the theorem.

I I Lemma 4.22 (Domain Preservation). LetP be a well-typed program with concern domains g and evalua­

tion dependency table DT. Suppose the evaluation step (Et(e)g,yl, /, S) ^ (E[e'],/',SZ) occurs in an evalua­

tion ofP. Then Vge(g\ depCloseDT (f )) • S|g = S'|g.

Proof. By h P OK, Theorem 4.17 (Subject Reduction), and Theorem 4.18 (Progress) we know that E[( e)s,f]

is well typed. Therefore (e)s,f is also well typed. This must be by T-TAG. By the hypotheses of that rule,

there must be some Y and t such that Y. depCloseDT (f) ij)re: l.

Let e" be the current redex of E[5,f] = E[

Lemma 4.21 (Expression Typing Monotonicity), Y.depCloseDT(f) hDTe:t implies that there exists f G

depCloseDT (f ) such that Y.f hpT e" : s for some type s.

We must consider all of the possible evaluation rules that might generate the evaluation step assumed

by the theorem. For all rules except NEW and SET, S' = S and the claim holds.

For NEW, let e" = new c(gi,...,g„>. S' = S© (loc-* [c(gi,...,g„> .F]), where loct dom{S) and rng(F) =

{null}. For all ge g such that g ^ gi, we see that S'lg = S|g. Now S'lgi # S|gi, but we will see that gi must

be in depCloseDT(j). The type judgment F.f \j)T e" : s must be by T-NEW or T-OBJ. In either case G] e f,

and f G depCloseDT (f) implies gi e depCloseDT (f). Thus the claim holds.

For SET, let e" = [loc6.f=v), where S{loc) = [r

s' = s® (/oc— [r.F®(/— z/)]),

where ,/= lod if v = lod5x, null otherwise

For all ge g such that g # gi, we see that S'lg = 5|g. Now if F(/) ^ then S'lgi ^ S|gi. But again we will

see that gi must be in depCloseDT (f ). The type judgment Y .f \-DT e" : s must be by T- SET with hypotheses

c L• f' h)Tl° - T(gi,...,gn) (by F ~ S) and gi e f'. As for NEW, gi e depCloseDT (f) and the claim holds. • 233

Theorem 4.23 (Tag Frame Soundness). LetP be a well-typed program with concern domains g andevalua-

tion dependency table DT. Suppose the evaluation triple (E\(e)g,f],J,S) appears in an evaluation of P. Then

either the evaluation diverges or (E\(e)s,Y},J,S) (ElV],J', S'), whereVg e (g \ depCloseDT (f)) • S|g = S'lg.

Proof. By inspection of the semantics, to reach a value with the tagged expression removed the evaluation

must be

The claim holds for the last step of this evaluation since the store is unchanged by the TAG rule. The claim

holds for each of the other steps in this evaluation by Lemma 4.22 (Domain Preservation) on the preceding

page. • I i

This theorem is sufficient for reasoning about the concern domains affected by a method. To reason about the execution of a method one must know the method's signature including its effects clause, the concern domains of the target object, and the configuration of aspects in the program, as represented by the aspect instantiation instructions and dependency declarations.

In the operational semantics of MiniMAOg, the execution of a method begins when the method body is inserted in the evaluation context, substituting actual arguments for formal parameters. This only occurs in the EXECB rule, where the method lookup occurs in CALLB and the fun term representing the method is threaded through joinpt and chain expressions unchanged. Execution of the method ends when the method body has been reduced to a value. In EXECb, method execution begins with a tagged expression where the writable domains set is that of the method's effects clause. So by Theorem 4.23 (Tag Frame Soundness), only public concern domains in the dependency closure of the effects clause may change.

Similarly, Theorem 4.23 (Tag Frame Soundness) is also sufficient for reasoning about the concern domains affected by a piece of advice, where advice lookup occurs in the BIND rule and advice execution begins in the

ADVISE rule.

4.4.3.2 Read-Only Annotations

Next I deal with the properties of read-only annotations in MiniMAOg. Read-only annotations are associ­ ated with pointers in the operational semantics. Their meta-theory can be described in terms of the pattern of location references in the store. I begin with some definitions to help formalize this notion. A small, illustrative example follows the definitions. 234

reps{loc) = L, where Gs(loc) - (L,E) domains^(loc) = {gi,... ,g«}, where S(loc) = [T(gi,...,gn).F]

Figure 4.23 Auxiliary Functions for the Meta-theory of MiniMAOa

The first definition gives the reachability relation for a store. Intuitively, one location may reach a second location if a sequence of field accesses beginning with the first location eventually yields the second location.

I I Definition 4.24 (Reach). Let 5 be a valid store occurring in the evaluation of some program. The reach of

S, denoted reach[S), is the reflexive, transitive closure of the set

{(null,null)} u{(loc, v) • loce dom(S), S(loc) = It.F], and 3/•((/'— v)eF)}.

The next definition refines the notion of reach to include locations reachable by accessing a sequence of write-enabled fields.

I l Definition 4.25 (Writable Reach). Let S be a valid store occurring in the evaluation of some program. The

writable reach of S, denoted writeReach(S), is the reflexive, transitive closure of the set

{(null,null)}u

{(loc, v) • loce dom(S), S(loc) -[t.F], and 3/- ((/' — v) e F and readonly (fieldsOf(t)(f)) - c)}.

A third definition lets me discuss the "value" of an object in terms of the values of its fields.

I Definition 4.26 (Object Graph). Let S be a valid store occurring in the evaluation of some program, and

let loc be a location, loce dom(S). The object graph of loc in S, denoted <&s(loc) = (L,E), is the least fix point

of the following pair of mutually recursive functions:

Eo-0 Ei =| [loc' « t/j • loc' e S (loc') = [t.F], and (/ v) e F j

Lo-{loc} L, =| v- |a/, i/j e Fjj or ^3/,loc' • |/oc' « vj e F;||

It is sometimes useful to refer directly to the set of locations in the object graph of some S(loc). I define the

auxiliary function reps(loc), see Figure 4.23, for this purpose. 235

locP locT [Book.{ title » locT, [StringBuffer. authorl locA1,

locA1 locN [Author. [StringBuffer.{ name >—+ locN,

Figure 4.24 Schematic View of a Sample Store, S

Table 4.1 Reach and Writable Reach for the Store, S, of Figure 4.24

Source Elements of reachiS) Elements of writeReachiS)

From pointers (null,null), (locP,locT), (null,null), (locP,locT), (locP,locA1), (locA1,locN), (locA1,locN), By transitivity (locP,locN), By reflexivity (locPjocP), (locT,locT), (locP,locP), (locT,locT), (locA1,locA1), (locN,locN) (locAl ,locA1 ),(locN,locN)

Figure 4.24 shows a small MiniMAOg store. Table 4.1 compares reachiS) and writeReach(S) for the store,

S in the figure. Because the authorl field of Book is read-only, the pair (locP, locAl ) that appears in reach{S) does not appear in writeReachiS), nor does the transitively induced pair (locP, locN).

Below is an example derivation of the object graph of the Book object in S, GS(locP):

LI

0 0 {locP}

1 |flocP IOCT],flocPau£?rl locAl] 1 LoujlocT,locAl]

2 £i u j|locA1 locNj j- Li u {locN}

3 i?2 L2 236

locations [new c (...){)) = 0 locations(var) = 0 locations {r\uU s) = 0

locations{eo.m(e\,...,e„))- (J locations{ei) locations(e.f)~ locations{e) ze{0..ni

locations (eo.f=e\) = locations(eo) u locations{ei) locations (cast t e) = locations{e) locations (eo; e?i ) = locations (eo) u locations (e\ ) locations (eg.proceed{ e\ en )) = [J locations (ej) i£{0..n}

locations(locg) = {locg} locations{{ I ( eo,...,en ) )) = locations{l) u (J locations{e{) ie{0..n}

locations[(e)s,f) - locations(e) locations^]ointpt j (eo,...,en)) = locations(j)u (J locations (ei) i€{0..n!

locations[urder e) - locations{e)

locations(chain É, j(eo,...,en)) = locations(B)u locations(j)u [J locations{e{) ze(0..nl

/orations(fun m(...).c:t.f) - locations{e) locations^•) = 0

locations(\[b, loc,e,._,J] + 8) = locations(b) u {/oci u locations(e) u locations(B)

locations{{a, ...)) = locations(a) locations (var >— /0C5) = {/ocg} locations{—) = 0

Figure 4.25 Recursive Definition of the Locations Included in an Expression

Thus,

Gs(locP) = (L2,£2)

= |{locP,locT,locA1,locN}, j|locP loclj,|locPauïî?rl |ocA1 j,|locA1 ~e locNj|j

In addition to these definitions about pointer patterns in the store, I use a notion of the locations "included" in an expression. Intuitively, any loc that appears syntactically in e is included in e—whether the loc appears in an expression, in a join point abstraction, or in an advice body tuple. This is formalized by the following definition and associated figure.

I 1 Definition 4.27 (Included Locations). Given an expression e, the set of locations included in e, denoted i locations(e), is given by the recursive definition in Figure 4.25. {

Finally, I formalize the notion of home domain.

I 1 Definition 4.28 (Home Domain). Given a store, S, and a location, loc, with loce dom{S) such that

S(loc) - [T{gi,...,gn) .F], the home domain of loc in S, denoted homegiloc), is gy. 237

The next theorem asserts that, for a certain sort ofMiniMAOg program, no mutation is possible by deref­ erencing a readonly pointer. This property is different than that of Theorem 4.23 (Tag Frame Soundness) in that this property says that a read-only pointer may not be used for mutation even if it points to a writable domain. This theorem ensures that code in the right sort of MiniMAOg program cannot change the value of an object to which it does not have a write-enabled pointer. I will come back to the issue of the sorts of MiniMAÛ2 programs considered by the theorem.

As for Theorem 4.23 (Tag Frame Soundness), I first state a lemma for a single evaluation step and then extend it for a sequence of steps. (The restriction on the domains of the object in the statement of the lemma, and subsequent theorem, is trivially satisfied for MiniMAOg, because all concern domains are public. I include the restriction here so that the theory is also applicable to MiniMAOg in the subsequent chapter.)

I l Lemma 4.29 (Read-only Preservation). Suppose the evaluation triple (E[e],J,S) appears in the evaluation

of a well-typed program P. Let loc be a location in dom{S) such that domainss(loc) c (/j, i.e., S{loc) only

names public concern domains. LetGsiloc) = (L,E), and let thefollowing assumptions hold:

Assumption 1. VÔ • (locg e locations(e)) => (5 = readonly). (Intuitively, no write-enabled pointers to the

object of interest appear in the expression.)

Assumption 2. \/loc'g e locations{e) •( (Vlod' e reps{loc) • [loc', loc") i writeReach(S}). (Intuitive­

ly, the expression does not contain any write-enabled pointers that reach into the graph of

the object of interest.)

Assumption 3. V loc' E dom(S) • S [lod) = [r.F] => isClassl t). (No aspect instances appear in the store.)

(ELLAS'), f/wm

Consequent 1. V5 • (loc$ e locations(e')) => (ô = readonly)

Consequent2. Vloc's e locations(e') • ( (Vloc" e reps(loc) • (loc', lod') € writeReach{S'))

Consequents. \/lod e dorn(S') • S' (loc') = \ t.F\ => isClass{t)

Consequent4. Gsdoc) ~ Gs>{loc),

Z Proof. Let e\e^ be the current redex of E[e], Let E H be defined such that E|e| = E[E'[e]eft]]. (That is, E' is

the unique evaluation context matching the expression e down to the current redex.) Let e^ght be such that

E[E'[erighf]i = E[c'|. By h P OK, Theorem 4.17 (Subject Reduction), and Theorem 4.18 (Progress), we know

that E[E'[e|eft]] is well typed. Therefore e|c|-, is also well typed. 238

Consequent 2 implies consequent 1. To see this note that loc e L by the definition of Gs(loc), and

{loc, loc) e wnteReach(S') by reflexivity. Thus if locg e locations (e'), then ô = readonly.7

So we must show that consequents 2, 3, and 4 hold. For each of these, we must consider all of the

possible evaluation rules that might generate the evaluation step assumed by the theorem. For each rule

we must show that these consequents of the lemma hold in the result.

Case 1—NEW. = new t(), e^GHT = loc", lod' £ dom{S), S' = Se [loc" >—• [f.F]), and rng{F) = {null}.

Because lod' is fresh and S' only differs from S by the addition of a mapping for lod', [loc, lod') £ reach(S').

Therefore lod' is not a node in Gs'(loc), and consequent 4 holds. Because rng{F) = {null}, consequent 2

holds. Syntactically, only classes may be instantiated by expressions, so consequent 3 holds.

Case2—CALLA- Here S' = S and locations[e\eft] - locations\er[ght], so all the consequents hold.

Case3—CALLB- = chain •,dcall,-,M,-,T,fD( lod'ô,vi,...,vn ), e^GHT = ( ' ( keg, v\,...,vn ) ), and S' = S.

Because S' = S, consequents 3 and 4 hold. Now locations^jg^t) = locations^) u locations[e\eft). But I is

retrieved by the methodBody auxiliary function and locations{l) is just the set of locations in the body of

some method. Method bodies are typed using an environment without any locations. Thus locations{l) = 0,

= locations fright) locations (e|eft), and consequent 2 holds.

Case 4—EXECA- Here S' = S and locations(e\ejt) = locations^e^^, so all the consequents hold.

Case5—EXECB- e|eft = chain *,<\exec,v,m,l,T,fU vo,...,vn ), Eright = under (e"lvo/ varo,...,vnl varn\)s'ty,

and S' = S. Because S' = S, consequents 3 and 4 hold.

s The expression e" in erjght' the body of the method from I. Substituting into e" could cause some

of vq i'n to drop from e^ght- Also v from the join point abstraction does not appear in eright. No new

locations are added. So we have locations {er\ghtj Ç locations (e|eft) and S' - S. So consequent 2 holds.

Case 6—GET. E|EFT = lodg.f, ENG|LT = vSi, S [lod') = \T(...).F], readonly [fieldsOf {ô T (...)) (/)) = 8', F(f) =

v, and S' = S. Because S' = S, consequents 3 and 4 hold. For consequent 2, let

readonly (fieldsOf (T{...»(/)) = 8"

^Technically, I could omit assumption 1 (and consequent 1). However, it is useful to make the fact of this assumption explicit. 239

(the declared read-only status of the field). Then by the definitions of readonly and fieldsOf:

readonly if 8 = readonly or 8" = readonly 8' = < e otherwise

Now if v = null, consequent 2 holds trivially.

If v = loc, then [lod', loc) e reach(S). By the assumptions of the lemma, either 8 = readonly or else

[lod', loc) t writeReach(S), which implies 8" = readonly. In either case 8' - readonly and consequent 2 holds.

Finally, suppose v = loc' # loc. If 8' = readonly, consequent 2 holds trivially. On the other hand, if 5' = c we must show that (lod, loci) £ writeReach{S) for all loci e L = reps(loc). But 8' = e implies 8 = 8" = e. Be­ cause v = lod, we know (lod', lod) e reach{S). Because 8" = e, we know that (loc", lod) e writeReach(S). For purposes of showing a contradiction, choose an arbitrary loci e L and suppose (lod,loci) e writeReach{S).

Then, because writeReach is transitive, (lod', loci) e writeReach(S). But this contradicts assumption 2 of the lemma, so it must be that (lod, loci) C writeReach{S) and consequent 2 holds.

Case 7—SET. = (lod'.f=v), e^ght = v, S (lod') = [t.F],S' - S® (lod' ^ [(.F® (/•—• f')]), and

loc' if v = loc's,

null otherwise

(Since is well typed, we can omit any ^-subscript on lod'.)

The only object changed in S' versus S is S (lod'). Its type is not changed, so consequent 3 holds. To prove consequent 4, it suffices to show that lod' €L = reps{loc). Suppose not, i.e., suppose lod' e L. This implies, by assumption 2 of the lemma, that (lod', lod') € writeReach(S). But because S (lod') has a write-enabled field, /, we know 3 v" • (lod',v") e writeReach(S). By reflexivity of writeReach, (lod', lod') e writeReach[S).

Thus our supposition leads to a contradiction, lod' € L, and consequent 4 holds.

For consequent 2, we have a modified store and writeReach(S') differs from writeReach[S). If v' = null, then (lod',nul I) is the only element possibly in writeReach[S') \ writeReach{S), so consequent 2 holds. If v' = lod and 8' = readonly, then by T-SET and the definition of subtyping, readonly (fieldsOf{t){f}) = readonly. So writeReach{S') \ writeReach{S) - 0 and consequent 2 holds. Finally, if v' ~ lod and 8' - e, then writeReach(S') is the reflexive, transitive closure of writeReach(S) u (lod',lod), less whatever pairs 240

were induced by the pair (lod',F{f)). Suppose this process results in a pair (loce, loci) e writeReach(S')

that violates consequent 2. Then it must be the case that this pair is induced by the transitive closure with (loce, lod') and (lod, loci) both in writeReach(S). This second inclusion violates assumption 2 of the lemma, since v = lod E locations(e). By this contradiction, there exists no pair (loce, IOCL) e writeReach(S')

that violates consequent 2, and the claim holds.

Case 8—CAST. Here S' = S and locations(e\ e^) = locations [e^^, so all the consequents hold.

Case 9—NCAST. Here S' = S and locations (E^) = locations FRIGHT)-80 all the consequents hold.

Case 10—SKIP. e\e^ = (v; e), e^g^ = e,S' = S. Because S' = S, consequents 3 and 4 hold. Also

locations |eright] G locations (e|eft),

so consequent 2 holds.

Case 11—BIND. e\e^ = joinpt j ( vo,...,vn ), E^JGHT = under chain Ë,j ( vo,...,vn ), B = adviceBindij + /),

and S' - S. Because S' - S, consequents 3 and 4 hold.

For explanatory purposes, I briefly consider the case as if assumption 3 did not hold. Then

locations (erightj - locations (e\ejt).

By the definitions of locations and adviceBind, locations\er\^) includes the locations of the aspects of any

matching advice. Advice body expressions in B do not contribute any locations, by a similar argument to

that for method bodies in Case 3. The other possible source of new locations for locations\erjg^j is the

binding terms in B. In particular, the left-most join point abstraction in j + J of the form

may contribute v to locations^jg^j because of a this pointcut descriptor.

But by assumption 3 and the validity of S, there can be no matching advice—there is no advice at all.

Thus, B = •, locations\e= locations(e\ejt), and consequent 2 holds. 241

Case 12—ADVISE. Here

e|eft = chain \[b,loca,ea,f,T,^+B,j (v0,...,vn)

Bright - under <«ea>)ByjllocaltbisU(vo,...,vn)lb\)Sif

readonlyir) - ô

S' = S

Because S' = S, consequents 3 and 4 hold. Examining the definitions of advice chaining and binding substitution, we see that no new locations are introduced. Some locations may be dropped if not all formais appear in ea. So locations^jg^t] G locations[e^), and consequent 2 holds.

80 Case 13—UNDER. Here S' = S and locations(e\^) = locations[erJGHT)> all the consequents hold.

V Case 14—TAG. Eright - S> and S' = S. Because S' = S, consequents 3 and 4 hold. The only way in which locations^erigj-,tj ^ locations [e\ejt) is if v = lod and ô = readonly. Then

= {Keadonly}'

Clearly consequent 2 holds. •

Theorem 4.30 (Read-only Soundness). Suppose the evaluation triple (E[e\,J,S) appears in the evaluation

of a well-typed program P. Let loc be a location in dom(S) such that domainssiloc) c , i.e., S(loc) only

names public concern domains. Let G.s ( loc) = (L, E), and let thefollowing assumptions hold:

Assumption 1. \/ô-[loc$ e locations(e)) => (<5 = readonly).

Assumption 2. Vloc'^ e locations(e) • (<5 = c) => (VZoc" e reps{loc) • [lod, lod') £ writeReach(S))

Assumption 3. \flod e dom{S) • S[lod) - [f. F] => isClass{t).

If(E[e],J,S> '->• (Elv],j',S'), thenGs(loc) = GS'(loc).

Proof. Immediate by appealing to Lemma 4.29 (Read-only Preservation) at each step in the evaluation. • 242

Theorem 4.30 (Read-only Soundness) on the preceding page allows aliasing in the analyzed code, so long as all the aliases are read-only. With a more general ownership type system, such as that of Aldrich and Chambers

[9], the restrictions on aliasing might be relaxed. But the theorem imposes another condition that is quite restrictive: no aspects can be used in the program!

The basic issue is that aspects can "leak" pointers into the computation without being explicitly referenced.

(In the proof of Lemma 4.29 (Read-only Preservation) on page 237, this leakage would be in the advice list, B; see Case 11.) Thus the restrictions on aliasing in assumption 2, which are sufficient without aspects, are not sufficient in the presence of aspects. One might think that a design that makes all pointers to aspects read­ only might solve the leakage problem. Unfortunately, that would render all aspects immutable. Alternatively, assumption 2 of the theorem might be changed to let locfg range over all locations included in e, plus the location of every aspect. This would prevent the problems that arise in the BIND case of the proof of the lemma and would correspond to the sort of reasoning required with explicitly accepted assistance (as discussed in

Chapter 2). In the subsequent chapter, I show how spectator aspects, appropriately defined, avoid the leakage problem. The problem will remain for regular (assistant) aspects, but that seems to be a price of their greater expressive power. Adding a full-blown alias control system to MiniMAO might allow more control over aliasing between assistant aspects and base program objects. On the other hand, the power of assistant aspects might break the more powerful alias control system also. I leave that investigation to future work.

4.5 Related Work

Aldrich and Chambers [9] present an ownership type system that is decoupled from the encapsulation relation in a program. Their system allows very fine-grained specification, and static typechecking, of the aliasing relationships in a program. The system replaces the traditional owners-as-dominators property of ownership type systems with a link soundness property. The link soundness property says that the only interdomain aliases are those between "ownership domains" that are explicitly given permission to hold such aliases. These permissions are closely related to my concern domain dependency declarations. The authors' ownership domains are significantly more fine-grained than my concern domains, with each object having its own member domains. Their system includes a single global domain, called "shared", to which objects belong by default. Other global domains can be declared in their system by using public member domains within singleton objects. Such global domains are necessary for the reasoning I want in MiniMAOg.

I considered just adopting their type system for MiniMAOg. However, the design of MiniMAOg, lacking static fields, does not allow singleton objects to be coded in a natural way. Furthermore, their system is not designed to control mutation and does not distinguish between read-only and write-enabled pointers. 243

Ownership domains is, perhaps, the most elegant of a large class of ownership and alias control type systems

[9,10,25,35,116,117,118,121], Aldrich and Chambers [9] provide a solid summary of the work in this area.

Dantas and Walker [48] present a calculus for "harmless advice", based on an extension of the typed lambda calculus, with references and objects added in the style of Abadi and Cardelli's imperative object calculus [1].

Dantas and Walker use a type system with "protection domains" to keep aspects from altering the data of

the base program. In keeping with this non-interference property, they do not allow advice to change values when proceeding to the base program. They borrow the lattice-ordered protection domains from the secure

programming languages community [119, 139] to prevent lower integrity data, such as that generated by

advice, from interfering with higher integrity data, such as that from the base program. These protection

domains in their core calculus are more expressive than my concern domains. Protection domains define a

partial order on data, whereas concern domains define a partition.

While the protection domains in the core calculus of Dantas and Walker are more expressive than concern

domains, this expressiveness is relinquished in their user-level calculus. Their user-level calculus generates a

single protection domain for the base program and a separate protection domain for each declared aspect.

Thus the protection system is tied to the program structure and, unlike MiniMAOz, cannot represent designs where the protection domains cross-cut the modularity structure of the program. (In the terms of Chapter 2,

they cannot represent surprising assistants.) They also do not include classes in either their core calculus or

user-level language, making their calculus a poor match for studying reasoning issues in Aspect!-like languages.

Leino [97] introduces data groups as a mechanism for abstractly expressing frame conditions for methods in

a way that is compatible with both modular verification and subclassing. Data groups are programmer-defined

hierarchical sets. Fields are declared to belong to a data group. A method declared to modify a particular data

group may modify all fields in that data group and in any data groups in the downward closure. Subclasses can

add fields to existing data groups and override methods to modify the new fields.

Leino's data groups abstract from the set of possible side effects inside a given module. My concern domains

decouple Leino's abstraction over effects from the module hierarchy. This is analogous to the decoupling in

Aldrich and Chamber's ownership domains relative to previous ownership type systems.

Techniques like concern domains have been used to attack reasoning issues in object-oriented languages

more directly. Leino and Nelson [99] describe the use of static and dynamic dependencies in the Extended

Static Checker project for -3. Their specification language allows abstract, behavioral specification of

methods. Key to this is the use of abstract variables [96], which are directly related to data groups [97]. But rather

than just restricting the state that may be mutated by a method, as in data groups and concern domains, Leino

and Nelson's specification language allows pre- and postconditions to refer to the value of the specification 244 variables. These values are calculated using representation functions, which describe how to calculate the value of an abstract variable from the concrete state of a module. Static and dynamic dependencies are the key to avoid exposing the representation function of an abstract variable. These dependencies are "abstraction(s) of abstraction function(s)" (§13). The dependencies describe which fields are used in the representation function of the abstract variable. This explicit declaration of dependencies seems to be necessary for modular verification. This paper introduces a notion of "scope monotonicity"—any property proven in some scope is provable in any larger scope—as the key property in its notion of modular reasoning.

The language feature of abstract variables, and their static and dynamic dependencies, is orthogonal to concern domains. Concern domains are used to describe the large-scale structure of a program. Abstract variables are used for finer grained specifications. It is interesting to consider combining the two features. For example, what are the implications of declaring abstract fields as belonging to a particular concern domain?

Leino et al. [100] describe a technique for "specifying and statically checking the side effects of methods" in a modular way. Their core language, OOLONG, includes annotations for specifying data groups (i.e., static dependencies, inclusions (i.e., dynamic dependencies), and modifies lists (i.e., frame axioms). Two rather draconian referencing restrictions, pivot uniqueness and owner exclusion, are used to avoid problems that arise because of aliasing. However, with these restrictions, they are able to modularly and soundly verify methods. The modularity property is based on scope monotonicity [99].

Leino and Millier [98] describe a small language, with specification constructs, in which it is possible to modularly verify object invariants in the presence of aliasing. The system builds on Universes [117] to separate objects into hierarchical ownership contexts. Representation objects are confined within the context of a single owner object. However, Leino and Millier add a notion of "ownership transfer" to allow code to move objects between ownership contexts. The ownership transfer mechanism is cumbersome, involving packing and unpacking object graphs so that whole subcontexts are moved. An object cannot be owned by two other objects simultaneously. It is interesting to consider how their work might be combined with

MiniMAOg, particularly since the readonly annotations introduced in MiniMAOg are a simplification of those from Universes.

Besides these approaches that, like concern domains, restrict the flow of data in programs, there are other approaches that focus on limiting the join points to which advice may attach. Among these are Open Modules

[8] (discussed in Section 3.3) and Aspectual Collaborations [102] (discussed in Section 2.6).

Another approach is to analyze and classify the sorts of interaction that may occur between aspects and the base program, but without applying any a priori restrictions on the sorts of interaction. The approach is exemplified by the work of Rinard et al. [146]. That paper presents a system that uses a simple control flow 245 analysis, and a global pointer and escape analysis, to classify the interactions between advice and advised methods. The pointer analysis generates a "scope" for each code block describing the fields that are read or written by that block. The granularity is per-class, not per-object. The paper is a direct extension of the ideas presented by Leavens and me [39]. Its contributions are the implementation of a static analysis and a more fine-grained classification system. Concern domains and effects clauses in MiniMAÛ2 can be viewed as lifting the per-method and per-aspect information from their static analysis into the type system. Dependency declarations lift their globally detected interference into the type system. Instead of detecting the interference as a global property of a program, MiniMAOg lets the programmer explicitly specify the planned interaction of concerns. The type system then verifies the programmer's intent. The analysis of Rinard et al. [146] also considers interference by analyzing the pattern of read access to the heap. It would be straightforward to add read clauses to methods and advice in MiniMAOz to lift this analysis into its type system. Though intuitively the concern domains of the self object for a method or piece of advice (modulo dependency closure) place an upper bound on the readable concern domains. Static typechecking ensures that no other concern domains may be mentioned in the code. I leave the proof of this property and an investigation of the utility of explicit reads clauses to future work.

Lam and Rinard [88] present an object-oriented system, implemented as a Java extension, that lets program­ mers annotate objects with "tokens" and methods with "subsystem" designations. Multiple objects may have the same token and separate instances of the same class may have different tokens. A simple whole-program analysis can determine token propagation and referencing patterns, and subsystem interactions. Based on this analysis several sorts of design summary graphs can be produced, including:

— an abstract object model, which abstracts away the details of component objects into single nodes;

— a call/return model;

— a subsystem access (to token) model; and

— a heap interaction model, which details how subsystems communicate through shared objects.

The generated models are sound: only interactions shown in the models may actually occur at runtime. The analysis is completely static: no token or subsystem annotations are used at runtime. Given their system's whole-program analysis, one would expect that it should accommodate subtyping, but the presented formal type system does not seem to address this.

The concern domains in MiniMAO^ are a generalization of Lam and Rinard's design tokens. Their work does not focus on the enforcement of concern separation, but on generating abstract models of concern 246 interactions. Their subsystems partition the control flow graph of a program. In its current incarnation, Mini-

MAO2 does not address control flow graphs. However, one can imagine an extension in which concern domains are treated as a generalization of both tokens and subsystems. Subsystems in their work are not polymorphic; i.e., every instance of a class belongs to the same subsystem. It may be that subsystem polymorphism is necessary in an aspect-oriented system. For example, if we are advising collection class objects, we may need to differentiate between the subsystems to which these objects belong. Lam and Rinard [88] simply omit subsystem annotations on such general purposes classes; the subsystem attribute of a control flow simply retains its previous value when control passes to an instance of an annotation-free class.

Rajan and Sullivan [141] introduce "classpects", which confound classes and aspects, in their Eos-U language. Because classpects contain advice-like constructs and can be instantiated, Eos-U bears some similarities to MiniMAOg with its aspect instantiation instructions. However, because classpects can be dynamically instantiated throughout the execution of a program, they do not confer the modular reasoning benefits of MiniMAOa.

In MiniMAOg, I introduce the writes pointcut descriptor, which allows advice to match based on the data that a method might mutate. This provides a kind of "semantic" pointcut [78], matching more on the meaning of the method than on the pattern of names in its signature. Several others have proposed mechanisms for more semantic pointcut descriptors [34, 56, 67,107], though none of these considers the frame conditions as an advice matching criteria.

Another line of work related to concern domains is what Reynolds [143] termed "separation logic". Separa­ tion logic is related to the logic of "bunched implications", introduced by O'Hearn and Pym [126]. These two ideas were brought to bear on the problem of local reasoning by O'Hearn et al. [127]. Separation logic extends

Hoare logic [71] to reason about programs with mutable storage. The central idea in separation logic is to separate the predicates in a "spatial conjunction" so that each refers to an unconnected, disjoint subset of the heap, where "unconnected" means the absence of pointers from one subset to the other. This unconnected- ness requirement is related to the restrictions on aliasing in Theorem 4.30 (Read-only Soundness). Because concern domains make the connections between subsets in a partitioning of the heap explicit, it seems that they might provide a useful substrate for applying separation logic to aspect-oriented programming languages.

I leave that investigation to future work. O'Hearn et al. [127, §8] also discuss a notion of "memory faults", run-time errors that are signaled when code accesses a portion of the heap outside of the subset described in the specification of the code. A proof of correctness for the code must ensure that such memory faults cannot occur. The static type system of MiniMAÛ2 can ensure this property for write access. And, as discussed above,

MiniMAÛ2 also intuitively places an upper-bound on the set of domains that may be read by a piece of code. 247

Work related to separation logic continues. Reynolds [144] provides a nice summary of the early work. More recent work related to concern domains includes that of Bornât et al. [23] and Parkinson and Bierman [131].

An interesting point made in the latter paper, is that pointers in separation logic can equivalently be treated as access permissions. This bolsters my assertion above that the concern domains of an object relate to methods of that object having "read" permission to those concern domains.

I discussed Kicazles and Mezini's "aspect-aware interfaces" [80] in Section 2.6. These interfaces are gen­ erated from a global configuration, which is outside the scope of the language. In the current work, concern domain declarations and concern annotations on fields and methods, serve to define this global configuration, but within the language. Unlike Kiczales and Mezini's work, concern domains also allow tool support to enforce the separation of concerns designated by the programmer. With explicit acceptance of assistance, via my proposed hierarchical concern maps, a finer-grained configuration would be obtained.

4.6 Conclusion

I conclude this chapter by revisiting some claims from its introduction.

CLAIM 1 MiniMAOg enables efficient static detection of tangled code by lifting cross-cutting concerns from the program implementation into the type system.

This claim rests on the assumption that programmers can define the concerns in a program by separating the program's state into concern domains. If that assumption is true, then cross-cutting concerns are tangled in exactly those declarations that reference multiple concern domains. It is not yet entirely clear that the assumption holds, however. Future work includes extending the ideas of MiniMAO^ to a practical programming language so that full-scale case studies can be carried out.

CLAIM 2 The type system enforces a non-interference property so that a global, signature-level search can identify all the code that might mutate a particular concern domain.

As discussed in Section 4.4.3, Theorem 4.23 (Tag Frame Soundness) says that given

— the signature of a method or advice,

— the concern domains of the target object, and

— the configuration of aspects in the program (as represented by the aspect instantiation instructions and

the dependency declarations), 248 one can determine all the concern domains that might be mutated. To do so, one must just take the dependency closure of the method or advice's effects clause. No additional code analysis is required, beyond the separate typechecking of the static type system. In my proposed language with concern maps and explicit acceptance of advice, the search scope could be further narrowed.

CLAIM 3 Read-only pointers serve as a proxy for the reasoning issues involved in combining more general alias-control type systems with an aspect-oriented language.

The read-only annotations in MiniMAOg are a simple alias-control mechanism. Rather than preventing aliasing, they prevent aliases from being used to "do harm". Lemma 4.29 (Read-only Preservation) on page 237 demonstrates that this simple alias-control system is sound in the base language. But the proof of the lemma provides convincing evidence that the system can fail in the presence of aspects if those aspects are ignored.

This also provides theoretic motivation for spectators, which are the primary subject of the subsequent chapter. 249

CHAPTER 5. MiniMA03: SPECTATORS REALIZED

In the previous chapter, I introduced concern domains in MiniMAOg and proved that they effectively partition the store, allowing the type system to enforce the separation of concerns. I also introduced a simple alias-control mechanism in MiniMAOg: readonly annotations. I proved that this alias-control mechanism is effective for programs without aspects. I argued that the problems in the alias-control system created by introducing aspects demonstrated the reasoning difficulties concomitant with AspectJ-style around advice.

In this chapter I describe MiniMA03. Mi ni M AO3 formalizes spectator aspects as discussed in Chapter 2.1

give the formal definition of MiniMAOg (as a set of differences versus MiniMAOg) and prove that the meta- theory for MiniMAO^ also holds for the new calculus. More importantly, I prove that the alias-control mech­ anism of MMMAO2, which is ineffective in the presence of regular aspects, is effective in the presence of spectator aspects. This demonstrates that spectator aspects, unlike regular aspect, do not interfere with this reasoning property. Furthermore, I demonstrate that because spectators belong to private concern domains, one does not need to know about the spectators present in a program in order to reason about the program.

Spectators can be used non-invasively without sacrificing modular reasoning.

5.1 Differences Versus MiniMA02

MiniMAOg has three main additions as compared to MiniMAOg: spectator aspects, "surround" advice, and

private concern domains. Spectator aspects are as described in Chapter 2. They provide a restricted form of advice that is statically known to not affect the code that they advise, in a well-defined way. To distinguish regular aspects and spectator aspects in this chapter, I will refer to the former as assistants and the latter as spectators.

I call the restricted form of advice for spectators, surround advice.1 Surround advice is a form of around advice with limited capabilities. These capabilities correspond closely to those of "harmless advice" [48]. The

body of a piece of surround advice consists of a before part and an after part. The following shows a simple

piece of surround advice:

xThe name "surround advice" is due to Lisa Laxson. 250

surroundO : call( Object(loggee) *(..) ) { this.log.append("beforez/); II before part proceed; // mandatory proceed to advised code this.log.appendC'after: " + reply) IIafter part }

As the names imply, the before-part expression in a piece of surround advice is evaluated before the advised code, while the after-part expression is evaluated after it. The operational semantics, discussed below, ensures that surround advice always proceeds exactly once to the advised code (or subsequent advice), unless the before-part expression diverges. Furthermore, the arguments passed to the advised code are the original arguments. Surround advice cannot mutate the arguments and cannot pass along new arguments. The result returned from executing a piece of surround advice is the result of the advised code (or subsequent advice).

The after-part expression has read-only access to the result value. Surround advice may capture the arguments to, and results from, the advised code, but only in read-only fields. From these restrictions it follows that the before- and after-parts of surround advice are evaluated solely for their side effects. Another way to think of surround advice is as paired before and after advice.

MiniMAOa also includes private concern domains. The operational semantics places each instance of a spectator its own, unique private concern domain. Only the spectator instance and any objects it creates, whether directly or transitively, may refer to the spectator's private concern domain. This notion is formalized in Definition 5.15 (Privacy Respecting Store) on page 283.

As in previous chapters, I describe the syntax, operational semantics, and static semantics of MiniMAOg by reviewing the differences versus the previous calculus.

5.1.1 Syntax of MiniMAOg

Figure 5.1 on the following page gives the differences in the user syntax from MiniMAÛ2 to MiniMAOg.

As would be expected, the syntax includes declaration forms for spectators and surround advice. A spectator declaration looks like an assistant declaration except for two changes: (1) the first concern domain variable is the special self variable, which represents the private concern domain of an instance of the spectator, and

(2) instead of declaring around advice, the spectator declares surround advice.

Surround advice declarations also look like their counterpart in MiniMAOz except for three differences. As mentioned above, the body of a piece of surround advice consists of two expression, the before- and after-part expressions. In the syntax, these are separated by a proceed. This proceed is not an expression. It merely serves to syntactically separate the before and after parts, and as mnemonic for the semantics of surround advice. The second difference between surround- and around-advice declarations, is the lack of a return type 251

decl:: = ... | spectator a(self,G*) {field* surr* } surr:: = surround (form* ) : pcd { e; proceed; e }

form:: - t var, where vart {this,reply}

7:: = ... | self

domains:: = domain g;, where g 19?sc|f

asp:: = use o(g*>; | use a(self,g*);, where g € ^se|f

vare {this, reply}u 'V, where Y is the set of variable names

( geWu ^se|f. where S is the set of public concern domain names

^self - {selffoc ' loc e ,'£\, the set of private concern domain names

Figure 5.1 Differences in Syntax of MiniMAOg vs. MiniMAO^ in surround advice. The result of evaluating a piece of surround advice is the result of the advised code. Since surround advice is only evaluated for side effects, it does not have its own return type. The third difference stems from the fact that surround advice may only mutate the private concern domain of its host spectator.

Thus, all surround advice has an implicit effects clause, writes (self), which is omitted from the syntax.

In MiniMAOs, the meta-variable, var, ranges over all variable names, the special this variable, and a new special variable: reply. The reply variable may be used in the after part of surround advice to refer to the result of the advised code (or of any subsequent advice). The static type system, plus the restriction on var in the form non-terminal of Figure 5.1, ensure that reply is only used in the after-part of surround advice.

The meta variable 7, which ranges over concern domain names and concern domain variables in Mini-

MAO2, also may denote the special self concern domain variable in MiniMAOg.

The domains non-terminal in MiniMAOs bears an additional restriction not present in MiniMAO^. The meta variable g, which ranges over public concern domain names in MiniMAOg, may also range over the set of private concern domain names, in MiniMAOs. However, the domains non-terminal, and aspect instantiation instructions discussed next, restrict g to just range over public concern domains. This restriction is part of the mechanism for keeping private concern domains private. Only the operational semantics may introduce private concern domain names into a computation. Private concern domain names have the form self/oc, where loc is the location in the store of the spectator instance associated with the named domain.

Assistants are only applied if a concern map says so. Concern maps are represented by aspect instantiation instructions in MiniMAOg. Spectators could be applied more generally, because the advised code does not need to be aware of them. But in MiniMAOs, some mechanism is needed to instantiate any public concern domain variables in a spectator declaration. Aspect instantiation instructions provide this. Unfortunately this 252

Syntax extensions:

e::-... | er\e gE3»(#u#se,f) B | ft_b,loc,(e,e), ffls Y e^^u^wjrujself}) t, S, U .. ... | T

Evaluation contexts:

E" = ... I Erve

Evaluation rules:

(E[chain \[b,loc,[eb,ea),^s + B,j( v0,...,vn)],J,S)^

(Efunder ((c,{selftoc}; chain B,j( v0,...,v„))RV(E^)£I|SE|FTOCI)],/ + /,S) SURROUND

where e'b = e\3{loc/thisU(vo,...,vn)l b\, e'a = ea\loclth\s\\{VQ,...,vn)l b\, and j' = (this, loc, —, —,—,—D

{E\vr\e],J,S) {l[e\vl reply}; v\,J,S) LEAP

Advice binding:

adviceBindU, S) = B, where B is a smallest list satisfying

\f (loc,pcd,{eb,ea),t)s e AT • {{matchPCD${f,pcd,S) = b^±) => Hi;, loc, (e|,,ea),rJls e B) and

M(loc,pcd,e,y,T,T') e AT• ((matchPCDU,pcd,S) = -L) => fife, Zoc, e, 7, T,T'J1 E B)

Subtyping:

CT(c) = spectator a { ... } t =< T a

Figure 5.2 Differences in the Operational Semantics of MiniMAOg vs. Mini-

MA02 confounds the use of aspect instantiation instructions as a mechanism for instantiating spectators and as a formal representation for concern maps. However, accepting this confounding allows me to avoid adding yet another additional form to the syntax.

5.1.2 Operational Semantics of MiniMAOj

Figure 5.2 gives the differences in the operational semantics and supporting definitions of MiniMAOg versus MiniMA02.1 describe these differences in the following subsections. 253

5.1.2.1 Syntax Extensions for the Operational Semantics of MiniMAOg

Like the previous calculi, MiniMAOs extends the user syntax with an additional expression used by the operational semantics to track machine state. The new expression form, termed a leap expression, has the form e\r\e2-The semantics first evaluates e\, then eg for its side effects, replacing any occurrences of reply in eg with the value of e\. The result of the whole expression is the value arrived at from evaluating e\—the value of ei "leaps" over the value of eg. I use the leap expression to express the meaning of surround advice.

If MiniMAOs had a let form, I could use that to express the desired semantics of surround advice. The semantics of ei rx eg is the same as:

let reply=ei in (eg; reply).

However, since MiniMAOg does not have let, I choose to introduce the new, more concise expression form rather than general let expressions. This option also avoids introducing local variables and makes the special semantics of surround advice more explicit.

I use a new advice body tuple form, \[b,loc, (e^, ea ),£_[] s, to represent surround advice in chain expressions.

I will refer to these as surround-advice body tuples, and will refer to the advice body tuples of MiniMAOg as around-advice ones. Like around-advice body tuples, the ones for surround advice include a binding term, b, and a location, loc, pointing to the host aspect instance in the store. The expression pair (e^.ea) represents the before- and after-part expressions, respectively (hence the subscripts). Unlike around-advice body tuples, those for surround advice do not include a set of writable concern domains; it is always {self/oc}. Surround- advice body tuples also omit the function types representing the type of the advice and the type of any proceed expressions in the advice. These function types are not needed for the semantics or meta-theory of surround advice. In place of these function types, a surround-advice body tuple just records a type, t, representing the return type of the advised code. This type information is used in the static semantics for typing the special

reply variable in ea.

MiniMAOg includes the type T, which is a supertype of every type.2 I use it for typing the pointcut descriptors of surround advice, which can safely use more general pointcut matching rules than those for

around advice. I discuss this more in Section 5.1.3.4. The T type is not part of the user syntax; it cannot be used for a formal parameter, field, or cast type.

2Because subtyping is positionally invariant for concern domains, Object cannot serve as a top type in MiniMAOg or MiniMAOs. 254

5.1.2.2 Evaluation in MiniMAOs

Program evaluation in MiniMAOs is essentially the same as in MiniMAOg. Like the surround-advice body tuples introduced for chain expressions in MiniMAOs, the advice table also includes special 4-tuples for surround advice, (loc,pcd, (%, ea), tj)^. The elements represent the spectator location {loc), surround advice pointcut description (pcd), before-part (e^) and after-part (ea) expressions, and the expected result type (tj).

The "T" subscript on t here is just a mnemonic to remind the reader that the expect result type might be

T—any type.

The initial store for the evaluation of a MiniMAOs program includes assistant instances as in MiniMAOg.

The initial store also includes spectator instances. The home domain of a spectator instance, stored in location loc, is the private concern domain self/oc. This is formalized in Definition 5.1 (Store Validity) on page 264. Unlike in MiniMAOa, where evaluation of a program may begin with any valid initial store, evaluation of a program in MiniMAOs must start with a valid initial store that "respects privacy". Definition 5.15 (Privacy Respecting

Store) on page 283 formalizes this property. The evaluation rules maintain the property (see Theorem 5.16

(Respect for Privacy)), so starting with a store that has the property ensures that the property always holds.3

MiniMAOs uses the same evaluation contexts as MiniMAOs, plus one additional context for leap expres­ sions (see Figure 5.2 on page 252). The right-hand side of a leap expression is not evaluated until the left-hand side has been reduced to a value.

MiniMAOs includes two new evaluation rules. One new rule handles leap expressions. The other handles the case of the current redex being a chain expression with a surround-advice body tuple at the head of the advice list. Although MiniMAOs uses the BIND rule, and assorted rules for casts, unchanged from MiniMAOg, a new definition of adviceBind and an extended subtyping relation affect these rules.

THE LEAP RULE The LEAP evaluation rule is straightforward. The value, v, on the left-hand side is substi­ tuted for reply in the expression, e, on the right-hand side. A sequence expression is used to let v "leap" over e.

THE SURROUND RULE The SURROUND rule appears a bit daunting. However, it just composes concepts already discussed. The basic scaffolding for the generated expression is a leap expression. This leap expression allows the result of the advised code to leap over the (discarded) result of the after-part.

On the left-hand side of the leap expression, is a sequence. The first term in the sequence evaluates the before-part expression for side effects. The second (chain) term in the sequence evaluates the advised code, or

^Technically, respect for privacy could be included in the definition of store validity. I keep the concepts separate for expository purposes. 255 any subsequent advice in the chain.

The rule replaces the formal parameters in both the before- and after-part expressions with the appropriate actuals according to the binding term, b. These ^-converted expressions— ef and e'a—are tagged to indicate that only the private concern domain of the spectator may be mutated. Finally, the rule wraps the whole sordid mess in an under expression, to record that the spectator location has been pushed onto the join point stack.

OTHER CHANGES The other differences in MiniMAOs versus MiniMAOg that affect the evaluation rules are simple. The adviceBind auxiliary function in MiniMAOs (see Figure 5.2 on page 252) calls the new matchPCDs pointcut matching function, described below, to handle any surround advice records in the advice table; adviceBind continues to use matchPCD for around advice.

MiniMAOg extends the subtyping relation of MiniMAOs to make spectator instances subtypes of Object, in the appropriate private concern domain. This could potentially affect the cast rules, since a spectator instance could be up-cast to Object (though this serves no purpose and causes no harm). The subtyping relation in

MiniMAOs also makes every type a subtype of T. This does not affect the evaluation rules, because T cannot appear in a cast expression and no value may have the actual type T.

5.1.2.3 Pointcut Matching for Surround Advice

Because of the restrictions on the behavior of surround advice as compared to around advice, a more gen­ eral pointcut matching mechanism can be used for surround advice without sacrificing type safety. Surround advice can match more because it does less.

Figure 5.3 on the following page gives the rules that define pointcut matching for surround advice, denoted by the function matchPCDs.

Consider the first rule in the figure. This rule handles the call pointcut descriptor. It matches a join point abstraction where the return type, u, of the advised code is a subtype of t, the type that the pointcut descriptor names. The corresponding rule for around advice requires u= t.Why the difference?

In both around advice and surround advice, the result of the advised code may be used in the advice.

Since the advice treats the result as having type t, it cannot bind to code where the result type, u, is a proper supertype of t. Or else the advice might call a method defined for t but not defined for the supertype. Thus, the semantics must require u^t.

But unlike surround advice, around advice may also return some value other than the original result to the calling code. The caller expects that the result is a subtype of u. But the type system can only ensure that the result is a subtype of t. So if u were allowed to be a proper subtype of t when matching around advice, then the 256

matchPCDs{ik,^,m,^,tox ...xtp — flLJ + /,call( u idPat(..)),S)

<-,-> if k - call, t =4 u, and m e idPat (1 otherwise

matchPCDsiik,m,tox ... xtp — + /,execution( u idPat(..)),S)

(-, -> if k = exec, t =4 u, and m E z'dPaf {± otherwise

, [<-,-> iff'S f mafc/zPCDs((ll_,,1_,,L_J,^,1_,,7l) + /,writes(f ),S) = < I ± otherwise

matchPCDs^, iA1_,,1_,,1_,,1_,l) + /,this( t var),S)

(var<-^ vst,~) if e = loc5, S(loc) = [s. F\, and ô s 4 t (where readonly(t) = 8') {1 otherwise

matchPCDsi^,-,^,^,^,^ + /,this( t var),S) = matchPCD$UAh\s{ t var),S)

\(-,var} if so ^ f matchPCDs^,^,s0x ... xsn — s,^J + /,target) t var),S) = < [ ± otherwise

matchPCDs (( ,_•> I) + /, ta rget( t var),S) = matchPCDs (J, target! f var),S)

matchPCDs{i^,^,l_1,^,t0x...xtp^ t,Ji + /,args( MI var\,...,un varn),S)

(-,-,vari,...,varn) \îp-ri and Vz E {1..ZÎ} • (fz- ^ M,-) (± otherwise

matchPCDs (/, pcd 11 pcd', S) = matchPCDs (/,pcd, S) v matchPCDs(/, pcd', S)

matchPCDs (/, pcd && pcd', S) = matchPCDsU, pcd, S) A matchPCDs (/, pcd', S)

matchPCDs U, ! pcd, S) = -> matchPCDs(J, pcd, S)

matchPCDs (/,pcd, S) = ± for any case not matched by the preceding rules

Figure 5.3 Pointcut Descriptor Matching for Surround Advice 257 original caller might try to call some method on the result that is defined on u, but not on t. So for around advice, the semantics must require t =4 u, and hence t=u. Because surround advice is not able to change the original result, letting surround advice match when u =4 t does not create type safety problems.

The rule for execution pointcut descriptors is just like the one for calls. Similar subtyping considerations apply to the rules for target and args. Though for these rules, it is the prohibition on surround advice replacing the arguments to the advised code that allows the more relaxed matching.

The rule for matching writes pointcut descriptors in surround advice requires that the set of writable concern domains of the advised code be a superset of the one given in the pointcut descriptor. As discussed in

Section 5.1.3.4 below, this has no implications for the type system. Using superset matching allows surround advice to match any code that may mutate a particular concern domain, even if that code also may mutate other concern domains. The example discussed below demonstrates this. (One consequence of this design decision is that there is no way to specify a piece of surround advice that only matches pure methods; using writes <} would match any superset of the empty set, i.e., any set. This could be resolved be adding a pointcut descriptor that uses subset matching for writable concern domains, say on ly Writes. I omit this because it is technically uninteresting.)

Finally, the surround advice matching rules for this pointcut descriptors and for pointcut union, intersec­ tion, and negation exactly mimic those for around advice matching.

Figure 5.4 on the next page shows a Logger spectator that takes advantage of the more general pointcut matching in MiniMAOs. Consider the semantics of the pointcut description in the figure, for the spectator instance created in line 17. This pointcut description will match any call or execution of a method that

— has any target type in the Products domain (line 5),

— takes a single argument, also in the Products domain (line 6), and

— might mutate the Products domain (line 7).

Compare this to the example in Figure 4.3 on page 155, which must use the exact matching of around advice.

5.1.3 Static Semantics of MiniMAOs

Most of the machinery necessary for static type safety in MiniMAOs already exists in MiniMAOg. The new calculus uses generalized notions of the evaluation dependency table and dependency closure to accommodate private concern domains. The calculus includes typing rules for the new spectator and surround advice declaration forms, and it uses a new program typing rule that considers spectator instantiation. The expression 258

/ spectator Logger(self, loggee) { 2 StringBuffer(self) log; 3 4 surround(readonly Object(loggee) targ, readonly Object(loggee) newVal) : 5 target(readonly Object(loggee) targ) 6 && args(readonly Object(loggee) newVal) ? && writes(loggee) { s this.log.append("Entering " + targ + " with " + newVal); II before part 9 proceed; 10 this.log.append("Exited " + targ) IIafter part

16 { 17 use Logger(self, Products);

18 19 }

Figure 5.4 Example Illustrating Relaxed Pointcut Matching for Surround Advice typing rules also get minor tweaks, to accommodate surround-advice body tuples in chain expressions and the new leap expression form. I discuss all of these changes in the following subsections.

5.1.3.1 General Differences

The evaluation dependency table in MiniMAOa includes a reflexive pair (g, g) for every declared, public concern domain in the program. Because MiniMAOs does not have declarations for private concern domains,

I must extend the evaluation dependency table with a pair (self/oc,self/oc) for every implicitly declared private concern domain, i.e., for every spectator instance. Clearly this does not affect the reflexive nature of the evaluation dependency table. Note that the self domains are private and spectators lack dependency clauses.

So the new pairs also do not affect the transitive nature of the evaluation dependency table. The type of dependency tables for MiniMAOs must admit pairs of private domains. It is:

DT: \^S U ^Svar U ^self) ~U ^var U ^self) •

The dependency closure auxiliary function in MiniMAOs includes all the private concern domains from the dependency table (see Figure 5.5 on the next page). This reflects the fact that an unseen spectator may always modify its private concern domain. However, because a private concern domain may only be named 259

Writable domains dependency closure:

depCloseDT (y) = {/ • 3y e y • (y,y') e D7'} u {self/oc• (Bloce S£ • (selfZoc,selfZoc) e DT)\,

C where DT: u u <^se|f) — ( S u'.V mr u% e\{) is reflexive and transitive, and Vy e f • (y, y) e DT

Spectator predicate:

CT{a) = spectator a...

isSpectator(<5 a{j\

Figure 5.5 Auxiliary Functions for the Static Semantics of MiniMAOg within the representation of the spectator, other code can still not mutate it.

The last general difference in the static semantics is in type environments. In MiniMAOg, a type environ­ ment, T, allows mappings like F (selfZoc) = domain and F (self) = domain.

5.1.3.2 Declaration Typing

Figure 5.6 on the following page gives the differences in the typing rules of MiniMAOs versus MiniMAOs.

The T-PROG rule in MiniMAOs must handle instantiation of both assistants and spectators. To do this it uses two "helper" rules. The T-ASSTINST rule is for assistant instantiation; it just includes the hypotheses from the T-PROG rule in MiniMAOg that are used to check aspect instantiation instructions there. The T-SPECINST rule is for spectator instantiation; it ensures that only spectator instances use private concern domains.4

The T-SPEC rule for spectators is just like the T-ASP one for assistants (see Figure 4.14 on page 174), but it omits checks on dependency declarations, which spectators lack.

The T-SURR rule for surround advice is similar to the T-ADV rule for around advice. T-SURR uses a relaxed pointcut declaration typing judgment (indicated by the subscripted turnstile ") that places no constraints on the this, target, or args types of pcd. Section 5.1.3.4 below discusses this in more detail. T-SURR checks that both the before- and after-part expressions are well-typed, using a set of writable concern domains that just includes the private self domain. Because these expressions are only evaluated for their side effects, T-SURR puts no constraints on the types given to them. It is enough that the expressions are well typed. When checking the formal parameter types, the T-SURR rule uses an empty set of writable concern domain variables. This forces all formal parameters of the surround advice to be read-only, preventing the advice from mutating any of the arguments to be passed to the advised code.

4It may be that assistants could also be allowed to have their own private concern domains. I have not yet considered either the safety or the utility of this generalization. 260

Declaration typing rules:

T-PROC, (replaces rule from MiniMAOg)

Vz' e {l..n}• I- decli OK Vz E {l..r}-{g\,...,gp} h aspt OK

gi :do main, ...,gp: domain. {gi,...,gp} \~DTe: t DT = depTable({gi ,...,gp},0)

H decl\ ...decln { domain gi; domain gp, asp^.^asp,. e } OK

T-ASSTINST T-SPECINST

CT(a) = aspect a(G\,...,Gn)... CT(a) = spectator a(self,G2,...,G„>...

Vz e {l..n}-gi e g Vz'e{2..zi!-g/eg

g h use fl OK g h use fl(self,g2,...,g„> OK

T-SPEC DT = depTable{{se\i,G2,...,Gq\,0)

Vz e {l..p} -D71- surri OK in a(self,G2,...,G9> q> 1 Vz E {l..n} - {self} t- f; OK in «(self, G2,...,G(?}

h spectator { /1; ...; tn fn; surr\...surrp } OK

T-SURR F ^ pcd:^.^.^.uj .V .V V = {self} r,this: «(self, G2,...,G,. {self}

r,this : «(self, G2,... ,G^), reply :readonly Mj.{self} Hôrea:sa Vz E {l..«} -0 (- f, OK in a(self,G2,...,G^>

F = var\ : t\,...,varn: self: domain, G2: domain,...,G% : domain

DTh surround( t\ var\,...,tn varn ) : pcd { proceed; ea } OK in «(self,G2,...,Gq)

Expression typing rules:

T-CHAIN (replaces rule from MiniMA02)

Vz E {0..n} • T.y hôr

(readonlyiuo) = readonly) => (y' = 0) Vz e {l..p}-r.f'.x HDJ-B; OK T = fox ... x tn —• ?

r.y hprchain Bi + ...+Bp + •,(L ,1_1,Lj),_1,T,f'D( e0,...,e« ): t

T-BOD

F I- b OK F,this: F(/oc), typeBind (F, 6;, (%),...,f»>). depCloseDT (y') ^

s =<; f depCloseDT (y') ç depCloseDT (y) T = £0 X... x tn ->• f

T-BODS

FI- foOK F,this: F(/oc), typeBind (T,bt{to,...,tn))- depCloseDT ({selftoc}) gy :

F, reply: readonly wj, this: F(/oc), typeBind (F, £>, (fo> ••.,£«». depCloseDT ({self/oc}) \~DTea :sa t^UJ T = to X ... X t„ —• ?

T. y. T FdT RÈ, toc, (EY.ga) - "TILS OK

T-LEAP r-f breo: f r,reply:?.y^eiis

T.fhDTeQr\ei:t

Figure 5.6 Differences in the Static Semantics of MiniMAOs vs. MiniMAO^ 261

5.1.3.3 Expression Typing

The T-PROG rule in MiniMAOg uses helper rules to differentiate between spectators and assistants. Simi­ larly, the T-CHAIN rule uses helper rules—T-BOD and T-BODS—to differentiate between around-advice and surround-advice body tuples in the advice chain, È. When all body tuples in B represent around advice, then

T-CHAIN and T-BOD together are equivalent to the T-CHAIN rule for MiniMAOa (see Figure 4.17 on page 179).

Recall that the hypotheses of T-BOD serve to propagate type information needed in the subject reduction proof. The hypotheses of T-BODS serve a similar purpose for surround advice. The differences between T-BOD and T-BODS reflect the more relaxed typing requirements on surround advice.

The new T-LEAP rule is straightforward, mirroring the operational semantics for leap expressions. T-LEAP ensures that the left-hand expression, eo, is well typed and gives its type, t, to the whole expression. The rule checks the right-hand expression, e\, assuming that reply has type t. Since the right-hand expression is only evaluated for side effects, T-LEAP does not place constraints on its type. It is enough that the expression is well typed.

5.1.3.4 Static Semantics of Pointcuts for Surround Advice

The typing judgment for a pointcut in surround advice is denoted

F ^ pcd\û.û! .U .u.V .V'.

See Section 3.2.3.2 on page 115 for a description of the various elements in the type.

The main differences between the pointcut typing rules for around advice (see Figure 4.20 on page 183) and those for surround advice (Figure 5.7 on the next page) are that the latter (1) do not track the set of writable concern domains matched by the pointcut and (2) allow more general combination of result types, treating an unconstrained result type as T.

Difference (1) is possible because the set of writable concern domains of a piece of surround advice is always {self}. I do not consider the side effects of the advised code to be side effects of the surround advice.

They would happen even in the absence of the surround advice and, unlike for around advice, can only happen once. (The operational semantics reflects this treatment of side effects. The SURROUND rule tags the before- and after-part expressions with the set {self/oc}. But the rule does not tag the chain expression representing the proceed of the advice.)

Difference (2) is possible because for surround advice the result type of the advised code does not need to be determined exactly, or even determined at all. Why is this? In around advice, proceeding to the advised 262

U:: = (t*) |1 û:: = t\± V e &>{T)

û U1 = û _Lu û = û UU_L = U A-UU = U

T-CALLPCDS Vz' E {l..^}.R(r/) - domain

F^call(5 idPat(..))\-L.l.l.ô T{j\,...,jq).0.0

T-EXECPCDS Vz e {l..<7}-r(ri) = domain

F^execution(Ô T{ji,...,jq) idPat{..)):L.1.1.5 T(yi jq).0.0

T-WRTPCDS T-THISPCDS Vz' e {!..«} -r(7j) = domain T(var) - t

T ^ writes(7i,...,7„ ):1.1.1.T .0.0 r 1-5 this( t var): f.l.l.T.{var}.{var}

T-TARGPCDS T {var) = t

T ^ target( t var):1 .r. 1 .T . {var} .{var}

T-ARGSPCDS Vz £ {1..n} • (P (vari) = r,) Vz' e {!..»} • (Vj e {l..rz} \ {:) • (vari £ varj))

F ^ args( fan tn varn ): 1.1. T. {vari,...,varn}. {var\,...,var„}

T-UNIONPCDS

F ^ pcdx :û.û! .U .u\.Vi.V[ T\^pcd2:û.û' .U .u2.V2.V2 T-NEGPCDS 7 U] ^ uj u2 mt V = Vi n V2 t ' = V( u V2 T ^ pcd: û. û'.U. u.V. V'

T\^pcd1 I) pcd2:û.û' .U.uj.V.V' T ^ ! pcd:1.1.1. T. 0.0

T-INTPCDS

T h; pcd\ : û\.û\. U\ .U\. V\. V'i I h; pcd2 :Û2.Û'2.U2.U2.V2.V 2

Û=Û\UÛ2 û' = û[ u û2 U = U\ u U2

u\ =4 uj U2 =4 uj V]' nV2 = 0 V = V\ u V2 V' — Vj u V2

F ^ pcd1 && pcd2 : û. û'.U. uj.V. V'

Figure 5.7 Static Semantics of Pointcuts for Surround Advice 263

code is done with a proceed expression. The result of the advised code is available to be manipulated by the advice, so the type system must place an upper bound on the possible result type. But, as discussed above, around advice may also return any value, not just the result of the advised code. To avoid problems in client code, which expect the result to conform to the type of the advised code, the type system must ensure that the value actually returned by the around advice is a subtype of the expected result type. Thus, for around advice the result type of the advised code must be determined exactly.

On the other hand, for surround advice, the result of the advised code is automatically the result of the advice. So the type system must only place an upper bound on the result type; this bound allows the result to be used in the after-part of the surround advice. If the bound is just T, then the reply special variable reference might be used in the after-part, but essentially nothing can be done with it. A reply reference in such a piece of advice would have type T. It could not be used as a target: T does not have fields or methods. It could not be passed as a parameter or assigned to a field: T is not in the user syntax, so parameters and fields cannot have type T. It could not be returned as a result: the operational semantics for surround advice only evaluates surround advice for side effects.

This more relaxed typing for results raises another question. Why are the typing rules not relaxed for target, this, and args pointcut descriptors? In fact, they are relaxed somewhat by virtue of the pointcut typing hypothesis in T-SURR, which allows these positions to be left unchecked (i.e., they can be _L). Also, the surround advice pointcut matching function, matchPCDs, uses subtype matching instead of exact matching. But still, in Figure 5.7 on the preceding page, the T-UNIONPCDS and T-INTPCDS rules are strict about combining the type information for target, this, and args—just as strict as are the corresponding rules for around advice. The reason is that the type system must still ensure that formal parameters bound by these pointcut descriptors are bound exactly once. The result value is bound to reply automatically, so these binding issues do not come into play there. If MiniMAOg were extended with non-binding forms of target, this, and args like those available in

AspectI, then more relaxed typing could likely be used. I leave the formalization of AspectJ's full menagerie of pointcut descriptors to future work.

5.2 Meta-Theory of MiniMAOg

Rather than restating the entire meta-theory from MiniMAOg, I just give the definitions, lemmas, and theorems that differ for MiniMAOg. The rest of the meta-theory of MiniMAOg is included here by reference, with the understanding that the descriptions apply to MiniMAOg syntax and semantics—a sort of dynamic scoping of the meta-theory. As in the previous chapter, I first discuss supporting definitions and lemmas, then

I cover the soundness of the static type system. A final subsection addresses the effectiveness of effects clauses, 264 private concern domains, and read-only annotations.

5.2.1 Supporting Definitions and Lemmas

Definition 4.2 (Concern-Complete Environments); Definition 4.3 (Environment-Store Consistency), F » S; and Definition 4.4 (Stack-Store Consistency), / « S, are applicable to MiniMAOg as written. In MiniMAOg, a valid store must instantiate spectators in the appropriate, private self/oc concern domains. The definition of store validity reflects this.

I 1 I Definition 5.1 (Store Validity). Given a well-typed program P with aspect instantiation instructions

use Cl\ (gl,l, • • • tg\,p\ )r •••/ use an(gfit\,...,gfitpn},

we say that a store S is valid if both of the following hold:

S{loc) = [a,-(selfzor,g,-,g/,,,,.>.F] if C7'(«,:) = spectator ... 1. Vz £ {!..«} -Bloce •<

S(loc) = \ai(giii,...,giipi).F] otherwise 2. 3F-F =: S I

The statement of the Dependency Closure Inclusion lemma for MiniMAOg is the same as Lemma 4.6

(Dependency Closure Inclusion) on page 186.1 update the proof to consider both public and private concern domains.

I 1 Lemma 5.2 (Dependency Closure Inclusion). LetP beaprogram with concern domains g and evaluation

dependency table DT. Iff ç g, f s g, and f 5 depCloseDT (f), then depCloseDT (f') ç depCloseDT (f).

Proof. Because DT is constant throughout the proof, I elide it where practical. Let 7' be an arbitrary element

of depClose(f). There are two possibilities.

If 7' £ then by definition of depClose, there exists 7 E 7' such that (7,7') £ DT. But 7 £ 7' implies

7 £ depClose {f) by the assumption of the lemma. So again by the definition of depClose, there exists 7" £ 7

such that (7", 7) e DT. Now DT is reflexive and transitive, so (7", 7') e DT. By the definition of depClose,

y" E 7 => 7' E depClose (7).

( On the other hand, suppose y' e ,

depClose, all private concern domains are in every dependency closure over DT. Thus, 7' £ depClose(y).

So every element of depClose (7') is also an element of depClose (7). • 265

The Dependency Table Extension lemma for MiniMAOg has the same statement as Lemma 4.7 (Depen­ dency Table Extension) on page 187, however the proof here considers the new definition of depClose.

I l Lemma 5.3 (Dependency Table Extension). Ife includes only user syntax, T.y V-DTe\ t, DT ç DT2, and

Vy ef -(7,7) e DT2, then

r.depClose DT2 (7) by/2 e : t.

Proof. The proof is by structural induction on the derivation of T. 7 \-DT e : t. The base cases are T-NEW,

T-OBJ, T-VAR, and T-NULL. (We do not need to consider T-Loc, because locations are not part of the user

syntax.) For all of these, the judgment does not depend on DT, so the claim holds.

The remaining expression typing rules constitute the induction steps. The induction hypothesis is that

the claim of the lemma holds for all derivations smaller than the one under consideration. For T-GET,

T-SET, T-CAST, T-SEQ, T-PROC, and T-UNDER, the claim immediate from the induction hypothesis.

All but one of the hypotheses of T-CALL hold immediately by the induction hypothesis. The one

hypothesis from the derivation off.y \jyr e : t that we must consider is depCloseDT (f) G 7, where 7' is the

set of writable domains from the effects clause of the called method. The corresponding hypothesis from

the derivation of F. depCloseDI-2 (y) \-DT2 e:t is depCloseDTz (f) Ç depCloseDI-2 (7).

First, note that depCloseDT (7') ç 7 implies 7' Ç 7. To see this, take 7' e f. By definition,

7' e depCloseDT (7')

and thus 7' e 7.

Next, note that 7' Ç 7 implies depCloseDI-2 (7') Ç depClosenTz (7). To see this, take 7' e depCloseDTz (f).

f There are two possibilities, depending on whether or not y is private, i.e., 7' e ^se|f.

If 7' e ^se|f, then let 7' = self/or. By the definition of depClose,

(self/oc selftoc) e DT2 and 7' e depCloseDT,, (7).

On the other hand, suppose 7' € %e|f. Then there exists 7 e 7' such that (7,7') e DT2. But y' Ç 7 then

implies that there exists yey such that (y, y') e DTi- So y' e depCloseDT2 (y).

Thus, by T-CALL F. depCloseDI-2 (Y) \~DT2 e: t, and the claim holds for this case.

The remaining expression typing rules—T-EXEC, T-CHAIN, T- JOIN, T-TAG, and T-LEAP—do not apply

to user syntax. Thus, the claim holds. • 266

The Substitution lemma for MiniMAOg requires a proof case for the new leap expression.

I 1 Lemma 5.4 (Substitution). IfY, van '• h,...,varn :tn.f\-DTe:t and\/i e \l..n}-T .f\-DTei : s; where Si =4 ti

thenT .f\-DTe\e\l var\,...,enl varn \: s for sorriest t.

Proof The set up for the proof is exactly like that for Lemma 4.8 (Substitution) on page 188.1 just give

here the induction step for the new T-LEAP case. (The differences in T-CHAIN between MiniMAOg and

MiniMAOg are immaterial for this lemma.)

For the T-LEAP case, e=e\ r\ e'2 and the last step in the type derivation is:

Y'.f \- e\:t F', reply: t.f h e'z : s

r'.71- e\ r\ e'2 : t

Now e\ë/mr\ - e'^ël var\r\e'2\ël vari. By the induction hypothesis, T.f h e'^ël var\ : t', F, reply: t.f h

e'2lël~viïrl : s', for some t' =4. t and s' =4. s (where the application of the induction hypothesis for e'2 uses the

initial type environment F, reply: t). Lemma4.13 (Environment Subtyping) on page 198 gives F, reply: t'.f (-

1 e'2{ël var\ '• s", for some s" =<: s'. Thus, by T-LEAP, T.f H e\ë! var\ : t , t' =4 t, and the claim holds. • 1 1

Lemma 4.9 (Environment Extension), Lemma 4.10 (Environment Contraction), and Lemma 4.11 (Replace­ ment) from MiniMAOz apply to MiniMAOa as written.

The Replacement with Subtyping lemma for MiniMAOg introduces a proof case for the new leap evaluation context. The case for the chain evaluation context of the proof from MiniMAOg is sufficiently general as to apply here without change.

1 1 Lemma 5.5 (Replacement with Subtyping). If T.f lyrE[e] : t, r.f \oTe:u, andT.f \~DTe' \u' where u' =4 u

and f Ç 7, then r. f V-DT ELE'L : / ' where t' ^4 t.

Proof. The set up for the proof is exactly like that for Lemma 4.12 (Replacement with Subtyping) on

page 194.1 just give here the case for the new leap evaluation context. (The differences due to the new form

of T-CHAIN for MiniMAOg are immaterial for this lemma.)

Suppose E2 = -r\e". The last step in the type derivation for Ezle] must be T-LEAP (with 7' = 7" and 267

s = u): T.f" h e:s r, reply: s. f" h e" : s"

T.f" \-E2ie]: s

By assumption, T.f" I- e' : u', where u' ^ u - s. By Lemma 4.13 (Environment Subtyping) on page 198,

F, reply : u'. f" h e" : u" for some u" =4 s".

Thus, T.f" h E2 le'] : M' where u' =4 s. • i i

Lemma 4.13 (Environment Subtyping) from MiniMAC>2 applies to MMMAO3 as written. Lemma 4.14

(Binding Soundness) from MiniMAOa, for around-advice body tuples, also applies to MiniMAOg. I add a new binding soundness lemma to deal with surround-advice body tuples.

I I Lemma 5.6 (Surround Binding Soundness). LetP be a well-typed program with evaluation dependency

x table DT. Let S be a valid store for P and J - fl...,(fo ... x tn —<• t),f [I + /' be a stack consistent with S. If

È = adviceBindU, S), then V \[b, loc, [e^,ea), uj JI5 e B the following conditions hold:

Consequent 1. t =4 uj

Consequent 2. 0 h b OK

Consequents. For concern-complete T » S, the judgments

r, this : T(loc), typeBind {T,bl(to,...,tn)). depCloseDT ({selfioc}) \~DT eb : tb

and

T, reply-.readonly uj,this : T{loc), typeBind{T, b,{to tn)). depCloseDT ({selfioc}) \-DTea : ta

hold for some types tb and ta.

Proof I will use a common setup and some common meta-variables throughout the proof.

Pick an arbitrary surround-advice element Hb, loc,(, e a ), uj\\s e B. Let the surround advice corre­

sponding to [1b, loc, [e^, ea ), ujJ| s be

surround (s'{ var\ s"fl varp) : pcd" { e"y proceed; e" } 268

Meta-variable Bindings:

\[b, loc,[eb,ea),ur!\s^B

S {loc) = |a (self,oc, g2,... ,gqt). f]

r' = var\ :si varp : sp,self, oc : domain, g2 : domain,... ,gq/ : domain

Advice Type Derivation (with domains reified):

r' ^ pcd:^.^.^.uj .V.V V = {vari,...,var p\

r r ,this. a(sç\fiqC,g2,• • •>&q ) • {self/y^} ^~bTa ^b • ^b

T'.this: a( self,oc, g2>... ,gq>), reply : readonly uj. {self/oc} Y-DTa ea :s a

Vz e {l..p} -0 h si OK in a{se\fioc,g2,...,gq>)

DTa hsurround(si vari,...,sp varp) : pcd{ proceed; ea } OKin a(self/or,g2,...,gg/>

Figure 5.8 Setup and Common Meta-variable Bindings Used in the Proof of Lemma 5.6

with advice table entry (b, loc, (e^, ea), uj ). Let this advice be declared in a spectator a with concern domain

variables self, G2,...,Gqi. Let S{loc) = |ti(self;oc,g2 gq') •• VVc will consider the typing derivation for

this advice, which must exist because the program is well typed. However, we will a-convert the entire

derivation, replacing self with self,oc and G; with g -, for all i e \2..q'\.

To simplify the notation,I will write 8 g I G| for jself/0<:/ self,g2/G2,...,gqil Gqt\. Let Vz e {l ..p} • s{ =

s-'flg/Gt, and F' = vari '• si,..., varp : sp,se\fioc: domain, g2: domain,..., gqr. domain. By the construction of

AT, C|, = e'^\g! G\, ea = e'-'ig/ G|, and pcd = pcd"\gl G[. Let the dependency table of the advice typing be

DTa - depTable^selig2>... ,gq> |, 0]. This comes from T-SPEC, with concern domain variables replaced

by concern domain names.

Plugging this notation into the o-converted derivation from T-SURR gives:

r' ^ pcduj.V.V V- \vari,...,var p\

r', this : a). {self,oc} Y-ma eb : sb

T', this :a(s elftoc, g2,... ,gq<), reply : readonly uj. {selftoc} >rDTa ea : sa

V i e {l..p}-0 h Si OK in a(selftoc,g2,...,gy> (5.1)

DTa hsurround(5i vari sP varp) : pcd{ <%; proceed; ea } OK in a(self/oc,g2,...,gq/)

For convenience, Figure 5.8 summarizes the setup of the proof and the use of these meta-variables.

Consequent 1 on the preceding page relates the expected return type of the matched code, from pcd,

to the actual return type from the join point abstraction. This ensures that if reply is used in ea, then 269 it is treated as having the correct type. The following subclaim says that the consequent holds if pcd is well-typed, which it must be in a well-typed program.

Subclaim 1. Assume r' ^ pcd : û. û'.U. uj.V'. V". Then

matchPCDsU,pcd,S) # _L => t ~< uj

Proof of subclaim.

— pcd - call( t" idPat(..) ). By T-CALLPCDS, t" - uj. By the definition of matchPCD,

matchPCDs (/, pcd, S) # ± => t ^ t"

=> t =4 uj.

— pcd = execution( t" idPat(..) ). Similar to previous case, but by T-EXECPCDS.

— pcd = writes(... ). By T-WRTPCDS, UJ — T. By definition of subtyping, t=4 T.

— pcd = this(... ). Here t =

— pcd = target(... ). Here t =4 T = uj, by T-TARGPCDS-

— pcd - args(... ). Here t ^ T = uj, by T-ARGSPCDS.

— pcd= pcd y 11 pcd2. By T-UNIONPCDS, F' ^ pcdy :ûi.û'vU\.u\.Vi.V[, F' h; pcd2:û2.û2.U2-u2.V2.V2,

u\ =4 uj, and uz 4 uj. By the induction hypothesis, matchPCDs U, pcd{, S) # ± => t =4 u\ =4 uj and

matchPCDs il, pcd2,S) •£ _L => t =

matchPCDs(/, pcd,S) # _L ==> matchPCDs(/, pcd,, S) ^ 1or matchPCDs(/, pcd2,S) ^1

==> t ^4 uj

— pcd = pcdx && pcd2.ByT-INTPCDS, F' I-5 pcdj:.w'j.U\.UI.V\.V[, F' ^ pcd2: û2. «2. i/2. M2 . V2. V2',

mi aj, and u-i^4 uj. By the induction hypothesis, malchPCDsU,pcdy, S) / _L => t ^ u\ ^ uj and

matchPCDs (/, pcd2, S) ^ J_ ==> f 4 w2 ^ uj. By the definition of matchPCD,

matchPCDs (/, pcd, S) # -L => matchPCDs (/, pcd,, S) # ± and matchPCDsU, pcd2,S) ^ i.

=> t =4 uj 270

— pcd = ! pcdy. Here r ^ T = uj, by T-NEGPCDS.

Subclaim-•

We next turn to consequent 2 on page 267. We can this prove consequent with a single subclaim. We use a subclaim that is stronger than the consequent, partly so that the induction hypothesis is sufficiently powerful. The stronger subclaim will also be useful in proving consequent 3. In the subclaim, var[b) means all variables appearing in b (as defined in Figure 4.15 on page 176).

Subclaim2. Assume F' h; pcd: û.û'.U.uj.V'. V". Then matchPCDsU,pcd,S) = b= (a,/3o,---,Px) implies all of the following:

0 h foOK (5.2a)

V' ç var(b) ç V" (5.2b)

û = -L <=> a — — (5.2c)

û' = _L <=> po = - (5.2d)

U =1 => x = 0 (5.2e)

U •£ _L => x—n (5.2f)

U = A. Vz e {l..x}-Pi = - (5.2g)

Proof of subclaim. The proof of the subclaim exactly follows that of Subclaim 5 of Lemma 4.14 (Bind­ ing Soundness) for around advice (see page 206), but using surround advice pointcut typing rules and matchPCDs. Neither the pcd result type nor the writable domains set from the typing judgment for around advice are material to the proof.

Subclaim-H

By T-SURR, the assumption of the subclaim holds. Therefore, consequent 2 on page 267 holds by (5.2a).

Consequent 3 is more complex. To prove this consequent, it will suffice to show that

typeBind{T,b, (to,...,?„» = var\ :s[,...,varp:s'p where Vi e {l..p} -s- 4 s, (5.3)

We will see that this juxtaposition of f,- in typeBind and s, in the result is resolved by the pointcut descriptor typing rules and matchPCD, which will impose constraints on the types. We use a final subclaim to this end. 271

Subclaim 3. Assume F' ^ pcd : û.û'. U. uj.V'. V", where V" Q {var\varp\.Then

matchPCDs (/, pcd, S)-b^L

=> Vrare rar(fo)-(3z e {l../)},.s| e -T • ( var - vari, typeBind (T,b,{to,...,tn)) (vari) - s'v and s- ^ s,-))

Proof of subclaim. As with the previous one, the proof of this subclaim closely follows that from the

previous chapter for around advice (see Subclaim 6 on page 212). I choose to omit it.

Subclaim-•

With this last subclaim in hand we can now prove the final consequent of the lemma. The first two

hypotheses of T-SURR (see (5.1) on page 268) are:

r' ^ pcrf:U.U.U.«T • V.V

V = {var\,...,varp]

By definition of adviceBind, \[b, loc, (eb,ea),MTjls eB implies matchPCDs (], pcd, S) ^ _L. We first use Sub­

claim 2 and Subclaim 3 to prove equation (5.3) from page 270.

V = {vari,...,varp} by T-ADV

=> var(b) = {var\,...,varp} by (5.2b)

=> Vi e {l..p}-3s'ie3~-

(typeBind(I', fo, <'o,• • •, tn)) ( vatj) = , .s'. C s,) by Subclaim 3

Thus, all var e V are bound appropriately. By examination of the definition of typeBind, we see that

dom(typeBind{T, b, (to,... ,tn))) = var(b) = V.

Thus, no additional variables are bound and (5.3) on the preceding page holds:

typeBind(T,b,(to,...,tn» = var\-.s\,...,varp-.s'p where V i e \l..p\ • s\ =

Let T" = selftoc : domain,G2 : domain,... ,gqt :domain. Then T-SURR gives:

van : si,...,var p : sp,this : a(selfZoc, g2 gq>), T". {self/oc} \-DTa eb : sb

=> by Lemma 4.13

var :s this: a van : 4'• • -> P p' ^loc>82,• • • ,gq>),T"• {selfZoc} \-DTa eb : tb

where tb 4 sb and Vi e • sj. ^ Sj

=> by (5.3)

e r this : «(selffoe g2,... ,gqi), typeBindff\ b, ( tQ,..., tn)), r". {self/oc} h>Ta b '• b

=> by Lemma 4.9, with appropriate a-conversion of b and e

e T, this : «(self/oc, g2,• • • ,gq>), typeBind (T,b,(to,..., tn)),T". {self/oc} h>Ta b '• *b

=> by concern-completeness of T

T,th\s: a(se\iioc,g2,...,gqd, typeBind{T,b,{to,...,tn))• {se\fioc\ \-DTa eb: tb

e By the definition of evaluation dependency table, DTa g DT and (self/oc, self/oc) DT. The expression eb contains only user syntax, by the construction of AT. Thus Lemma 5.3 (Dependency Table Extension) on page 265 gives:

e : r r,this: «(self/oc,g2,•••,gq>),proceed :T',typeBind(T,b, (TO tn)).depCloseDT ({self/oc}) h>r b b

So the first part of consequent 3 holds. The second part holds similarly. •

I restate the Advice Chaining lemma based on the T-CHAIN rule of MiniMAOg.

Lemma 5.7 (Advice Chaining). Let

(T,proceed:i).y\-DTe-. t,

j = (L,^,u,T,Y"L),

T = to X ... X tn —<> t,

depCloseDT (f") Q y,

[readonlyito) = readonly) => (f" = 0),

and for all Be B let [T, proceed : T) . Y". T HqTB OK. 273

ThenT.fhDT((e))Èj:t.

Proof. The statement of the lemma is made more concise by the T-BOD and T-BODS rules introduced for

MiniMAOg. However, the proof of the lemma is exactly like that for Lemma 4.15 (Advice Chaining) on

page 216, so I omit it here. • i i

Lemma 4.16 (Join Point Abstractions) for MiniMAC>2 applies as written to MiniMAOg.

5.2.2 Type Safety

I restate the Subject Reduction theorem to account for MiniMAOg's private concern domains. The set of writable concern domains used in the expression typing judgments in the theorem must include all private concern domains, because they may always be mutated. However, most of the proof of Theorem 4.17 (Subject

Reduction) on page 218 can be incorporated here without change.

I 1 Theorem 5.8 (Subject Reduction). Given a well-typed program P with public concern domains g and

private concern domains g', for an expression e, a valid store S, a stack J consistent with S, a concern-

complete type environment F consistent with S, a set of concern domains f with g'çycjgu g'), and the

evaluation dependency table, DT, ofP, ifT. f lj)r e : 1 and (e,J,S)(e',J',S'), then /' » S', S' is valid, and

there exist concern-complete F' ~ S' and t' ^ t, such that F'. f \j)Te':t'.

Proof. To update the proof of Theorem 4.17 (Subject Reduction), I add two new cases for SURROUND and

LEAP, update the BIND case to account for the revised T-CHAIN type rule, and explain why the ADVISE case

does not need to be updated. All other cases from the proof on page 218 apply in MiniMAOg, as does the

set up for the proof.

Case 1—LEAP. Here e = E[fr\e"], e' = E[e"II v! reply}; v], /' = J, and S' = S.

Let r' = T. Clearly F' = S' and ]' « S'.

It remains to be shown that T. f h e' : t. Because e is well typed, it must be that v r\e" is also. Let

F.y h vr\e" : s. This must be by T-LF.AP with hypotheses r.yh v. s and F, reply: s.f I- e" : s' for some type

s'.

From the second hypothesis and Lemma 5.4 (Substitution) on page 266 F.f h e"\v! reply} : s" for some

s" ^ s\ By T-SKIP F.f H E"Jy/replyf; v:s. Thus, Lemma 4.11 (Replacement) on page 194 gives F.Y h e' : t. 274

Case2—SURROUND. Here

e = E[chain \[b,loc,(eb,ea),uj^\s + B,j( v0,...,vn )]

e' = [[under (((eb>e,{se]w; chain z/Q

j = (L>i_,.(Sox...xs„ — s),frJ

e'b = eb\loclth\$\\{VQ,...,vn)l b\

e'à - ea\lodX\\\s\\{vq,...,vn)l

/' = {this, loc,—, —, —, — D + /

S' = S

Let r' = F. Clearly F' % S'. Because il-Jls terms can only be added to a program by the auxiliary function adviceBind called by BIND, we know from the definition of adviceBind, and the validity and monotonicity of S, that loce dom(S). By T ~ S, we know loce dom{T). Thus, j' ~ S'.

It remains to be shown that T. f I- e' : t. Let

eieft = chain \[b, loc, (eb,ea), wTJls + B, j( v0,...,u„ )

e = v e right under (((%);:,{self/0,.}' chain B,j( VQ,...,vn )]'^ ^ a)5,{Self;0C})

Because e is well typed, we know that and all its subterms are also. Let r.f h e\eft : s. This must be by

T-CIIAIN as follows:

: s rh £>OK s^uj T, this :T{loc}, typeBind[Y,b, {sq s„>). depCZose ({self,oc}) h eb b

T, reply : readonly «T,this : T(loc), typeBind(T, b, {SQ,... ,sn)). depC/ose ({self ,oc}) h ea : sa T-BODS

T. f m. (So X ... X Sn — s) I- \[b, loc, (eb,ea),MTJls OK

Vi e {0..«}-r.f I-Vz e {0..«}• u, s(- depClose(fm) ^f

[reodonlyiuo) = readonly) => (Fm = 0) VB e B-T.Fm.(SQX ... xs„ — s) h B OK T-CHAIN r.ff- C|gf(. s

(5.4)

In the derivation above I expanded the subderivation by T-BODS, because we will need some of its hy­ potheses to complete the case.

We want to show that T. f h erj„ht : s. This must be by a derivation like that shown in Figure 5.9 on page 275

276. There are five "leaf" hypotheses in this derivation (appearing in the top fringe of the proof tree), one of which appears twice. We must show that each of the four unique leaf hypotheses hold.

Two of the leaf hypotheses are easy to demonstrate, R.f H chain B,j{ VQ,...,V„ ) : S holds by T-CHAIN using all the hypotheses from derivation (5.4) on the preceding page except the judgment of T-BODS.

By definition, depClose (\se\iioc\) — g', the set of all private concern domains. From the statement of the theorem, g' G f, so depClose ({self;,,,-}) G f. It remains to show the truth of the two leaf hypotheses for ef and e'a.

From (5.4), we know

T,reply:readonly uj,\h\s\T (loc), typeBind(T,b,(sQ,..., sn )). depClose {{se\iioc}) h ea :sa. (5.5)

Let b= (a,PQ,...,Pq). Assume a = var1 — lodg and /% - varof' Then expanding the typeBind term in (5.5) gives

1 t F,reply:readonly w-r,this:F(/oc), va^-.ST(loc ),(vari '• i)ia{i..q}-pi=mri-depClose{{se\iioc}) H ea:sa. (5.6)

Working the other direction, expanding the binding substitution in e'a gives

ea = ejlocltb\s,loc'gl var',(vtl var^^i..q}.pi=mrii- (5.7)

By two hypotheses of T-CHAIN in (5.4) on the previous page, we have

Vz e {1..n] • (r.f h vi : M; where u; ^ s,-).

For each value these judgments must be by T-Loc or T-NULL, neither of which use f in its hypotheses.

So we have V i e {!..»} • (f. depClose ({se; I f ) t- Vj : u, where Uj -4 s,). This fact, (5.6), and (5.7) satisfy the condition of Lemma 5.4 (Substitution) on page 266. Thus, T,reply:readonly uj. depClose ({se 11 /or}) H ea:sa for some s'J 4 sa. Finally, from (5.4), s -=-< uj readonly uj. So by Lemma 4.13 (Environment Subtyping) on page 198, F, reply : s. depClose {{se\f[oc}) h e'a:s'a for some s'a =4 sa 4 sa.

The argument that e'^ is well typed is similar, but without the extra complications for dealing with reply.

So, all the leaf hypotheses in Figure 5.9 on the following page hold. Therefore, F.f h e^ight: s and,

by Lemma 4.11 (Replacement) on page 194, F.f h e' : t. 5Handling the cases where either a = - or J6Q = -, or both, is a straightforward simplification. r.depClose{{se\ii oc}) h e'^ : ^ depClose{{se\iioc}) Ç f T-TAG r,reply : s. depCZose({self,oc}) \~e'a:s'a s r.7 !" (eb)£,{self;oc} : b T.f h chain È,j( vo,.-.,vn):s depClose({seUioc}) Q y T-SKIP T-TAG r e -f I" (< b>f.{selftoc}; chain B,j(v0,...,v„) : s r,reply:g.fl-(e^^|^:^ • T-LEAP M en f ^ w; Chain z/Q,z,» )j :s T-UNDER r. f h ^ight :s*

Figure 5.9 Type Derivation for Result of SURROUND Rule in Subject Reduction Proof 277

Case 3—BIND. Here:

e = Eljoinpt Jfc, vopt, mopt, l0pt,(s0 x... xsn — s),y'|)( v0 vn )]

e' = Elunder chain BAk, vopt, mopt, l0pt> (sox... xsn — s),y'D( vo,...,vn )]

x B - adviceBind(<\k, vopt, mopt,lopt, (so ... xs„ — s),y'|) + /,S)

/' = (1 k, vopt, mopt, lopt, (so x... x sn — s), y' D + /

S' = S

This case is quite similar to the BIND case from the proof for MiniMA02 (see page 224). The essential difference is dealing with surround advice body tuples.

Letr' = I\ Clearly F' ~ S'.

x We will see that/' » S'. Let eleft = joinpt flfc, vopt, m0pt,l0pi, (so ...*s„ — s),y'D( vq v„ ). Because e is well typed, it must be the case the and all its subterms are well typed. The typing derivation for e|eft must be by T-JOIN with F.f h EJeft : s. Thus, if vopt is a location it must be in dom{T) and so /' = S'.

It remains to show that T. y h e' : t. Let

fright = chain BAk, vopt,mopt,lopt,{s0x ... xsn — s),y'D( v0,...,v„ ).

(By T-UNDER, e^ight has the same type as under e^ighf 80 we can focus on the smaller expression.) The typing judgment for ERIGHT must be by T-CHAIN. SO we next show that all the hypotheses of T-CHAIN are satisfied for erighf

By the well-typedness of e\e^ and its subterms, let F.f h Vj : tj for all i e {0..n}. By T-JOIN, we have t( =4 Si for all i e {0..«}, depClose(f) Gy, and (readonlyiuo) = readonly) => (f = 0).

It remains to show the VB E Bl\y'.(.%x... x stl — s) h B OK. There are two cases to consider, depending on whether B is an around-advice body tuple, (1...J1, or a surround-advice one, fL J1S- Around-advice body tuples are treated in the BIND case of the proof for MiniMAOg, so I omit that argument here. Let

B - lb,loc,{eb,ea},UT$s be an arbitrary, surround-advice element of B. By the definition of adviceBind, it must be the case that there exists a piece of advice with advice table entry ( loc, pcd, (eb, ea), uj )s such that matchPCDs (/', pcd, S) = 278

By Lemma 5.6 (Surround Binding Soundness) on page 267 we have:

s=4uj

0 h b OK

T, this :T(/oc), typeBind(T,b, (so,... ,s„>). depClose ({se\fioc}) I- % : % for some

I\ reply readonly uj,this:T{loc),typeBind{T,b,(so,...,sn)).depClose({se\iioc}) h ea : sa for some sa

By appropriate A-conversion of b, <%, and ea, we have Y \-b OK. The remaining hypotheses of T-BODS are

satisfied directly by the results of the lemma. Thus, F.y H eright:sby T-CHAIN. By T-UNDER and Lemma 4.11

(Replacement) on page 194 on page 194, F.f he': t.

Case4—ADVISE. Although the T-CHAIN rule in MiniMAOg differs from that for MiniMAOg, the proof of this

case is the same as that in Theorem 4.17 (Subject Reduction). This is because the ADVISE rule only applies

when the first advice tuple in the chain is for around advice. The updated Lemma 5.7 (Advice Chaining) on

page 272 is sufficient to show the claim. • i I

I restate the Progress theorem, as I did Theorem 5.8 (Subject Reduction), to account for MiniMAOg's private concern domains. The proof of the theorem differs in only minor ways from that of Theorem 4.18 (Progress) on page 228; progress is trivial for the new SURROUND and LEAP rules.

I 1 Theorem 5.9 (Progress). Given a well-typed program, P, with public concern domains g and private con­

cern domains g', for an expression e, a valid store S, a stack J consistent with S, a concern-complete type

environment F consistent with S, a set of concern domains f such that g' çfç(gug'), and the evaluation

dependency table DT, such that the triple (e, J, S) is reached in the evaluation ofP, ifT. f \-DT e : t then either:

— e- locg for some ô and loce dom(S),

— e = nulls for some ô, or

— one of the following hold:

—(e',/',S'>

- (e, /, S> (NullPointerException,j',S')

- (e,],S)^ (ClassCastException, J', S')

Proof. The proof is the same as that for Theorem 4.18 (Progress) except for two differences: 279

— When the current redex matches the additional SURROUND or LEAP rules, progress is trivial; there are

no side conditions.

— When the current redex is a chain expression (Case 2 of the original proof, on page 229), if the advice

chain, B, is non-empty then:

- (e, J, S) may evolve by ADVISE, as in the original proof, or

- (e, J, S) may evolve by SURROUND. • I i

The statement of the Type Safety theorem for MMMAO3 is exactly like that for MiniMAOg, apart from referencing other meta-theory from the current chapter. But because of the centrality of the theorem, I repeat it here.

I 1 Theorem 5.10 (Type Safety). Given a program P, with main expression e, concern domains g,\~ P OK, and

a valid store So, then either the evaluation ofe diverges or else {e, •, So) •—* (x, J, S) and one of the following

hold for x:

— x= locg for some 8 and loce dom(S),

— x = nulls for some5,

— x- NullPointerException, or

— x-ClassCastException

Proof. If e diverges then the claim holds. If e converges, then note that the empty stack is consistent with

any store, the validity of SQ implies the existence of an initial type environment consistent with SO, and

h P OK implies I'. g \pTp e: t for some t, where DTP = Ugeg (g,g). Let DT be the evaluation dependency

table for P. By the definition of the evaluation dependency table for MiniMAOg (see Section 5.1.3.1 on

page 258), DTP Ç DT and Vg E g - (g,g) £ DT. Because e is the main expression of the program, it only

contains user syntax. Also, because g includes every concern domain in P, g = depCloseDT (g). Thus,

by Lemma 5.3 (Dependency Table Extension) on page 265, T. g e : t.

The proof (by induction on the number of evaluation steps) follows from Theorem 5.8 (Subject Reduc­

tion) on page 273 and Theorem 5.9 (Progress) on the previous page. • 280

5.2.3 Effects

The more interesting meta-theory for MiniMAOg is that for its effects control mechanisms. As in Mini-

MAO2, effects clauses are sound for public concern domains, but in MiniMAOg private concern domains

may change without explicit permission. However, the very privacy of these domains keeps those changes from affecting other code. I also relax the conditions for the Read-Only theorem. The new conditions allow spectators, demonstrating that a simple alias control mechanism is effective in the presence of some sorts of aspects.

5.2.3.1 Effects Clauses

The definition of concern domains in the store is as written in Definition 4.20 (Concern Domain) on

page 231. The Expression Typing Monotonicity lemma for MiniMAOg adds a lower bound on the set of writable domains used in a subderivation. This bound is the set of private concern domains. This lemma (apart from

the lower bound) was immediate by inspection in MiniMAOg. But because of the lower bound and the T-BODS

rule, which does not make the monotonicity property explicit, the proof is marginally more complex here.

1 I Lemma 5.11 (Expression Typing Monotonicity). If T.f \~DTe: t, g = {self,oc-[selfioc,self /oc) e DT}, and

g ç f, then for any subderivation I"'. f \j)T e' : t', it is the case that gçf'çf.

Proof The proof is by structural induction on the derivation T.f\pTe: t. The base cases are T-NEW, T-OBJ,

T-VAR, T-LOC, and T-NULL, which hold vacuously.

The remaining rules are the induction steps. The induction hypothesis is that the claim holds for all

derivations smaller than the one being considered. We proceed by cases on the remaining typing rules.

For each rule, we must consider the hypotheses that are expression typing judgments. For each such

hypotheses, F'. f tjyr e' : t', if we can show

gÇfGf, (5.8)

then the induction hypothesis is applicable and the claim holds.

The hypotheses of T-CALL, T-GET, T-SET, T-CAST, T-SEQ, T-PROC, T-UNDER, T-JOIN, and T-LEAP

satisfy (5.8) trivially; for all such hypotheses f - f.

Case 1—T-EXEC. For T-EXEC, there are two hypotheses that are expression typing judgments. For one,

the set of writable concern domains is f, so (5.8) is satisfied. For the other hypothesis, the set of writable

concern domains is depCloseDT [f"), where f" comes from the fun term in the judgment of T-EXEC. But 281

T-EXEC also gives that depCloseDT (f") Q y. By the definition of depClose, g Q depCloseDT (y"). Thus (5.8)

is also satisfied for this hypothesis.

Case2—T-CHAIN. For T-CHAIN, (5.8) is satisfied trivially for the argument expressions.

For around-advice body tuples, we have the advice body expression typed (in T-BOD) using a set of

writable concern domains depCloseDT (f "), where f" comes from the around-advice body tuple. Similar to

the T-EXEC case, we have g Ç depCloseDT (y") G y, where the upper bound is transitive through hypotheses

of T-BOD and T-CHAIN.

For surround-advice body tuples, we have the before- and after-part expressions typed using the set of

writable concern domains depCloseDT ({self,oc}). By the definition of depCloseDT, depCloseDT ({self,oc}) -

g. Thus, (5.8) is satisfied and the claim holds. • i I

The statements of Lemma 4.22 (Domain Preservation) and Theorem 4.23 (Tag Frame Soundness) are as written for MiniMAÛ2. But there is a crucial difference in their meaning. The definition of depClose in

MiniMAOg includes all private concern domains in every dependency closure. So the fact of the lemma and subsequent theorem—that Vg e (g\ depCloseDT (f)) • S|g - S'|g—means that the meta-theory of effects clauses only holds the specified public concern domains constant; private concern domains may be mutated.

I 1 Lemma 5.12 (Domain Preservation). Let P be a well-typed program with concern domains g and evalua­

tion dependency table DT. Suppose the evaluation step {E{{e)gtf], J, S) <-» (E[e'],/',S') occurs in an evalua­

tion of P. Then Vge (g\ depCloseDT (y)) • S|g = S'jg.

Proof. By h P OK, Theorem 5.8 (Subject Reduction), and Theorem 5.9 (Progress) we know that EKe)«5,f] is

well typed. Therefore {e)g f is also well typed. This must be by T-TAG. By the hypotheses of that rule, there

must be some F and t such that F. depCloseDT (f ) \-lyl e : t.

Let e" be the current redex of E((e>s,yl- Let E'H be defined such that E[(e>g,y] = EKE'Ie"]}^]. Let

g' be the set of private concern domains of P. By the definition of depCloseDT, g' G depCloseDT (f). So,

Y. depCloseDT[f) \~DTe: t implies, by Lemma 5.11 (Expression Typing Monotonicity), that there exists

f' Ç depCloseDT (f) such that F.y' \-j)T e" : s for some type s.

The remainder of the proof proceeds exactly like that for Lemma 4.22 (Domain Preservation). • 282

Theorem 5.13 (Tag Frame Soundness). LetP be a well-typed program with concern domains g and evalua­

tion dependency table DT. Suppose the evaluation triple (El(e)s r f],J,S) appears in an evaluation of P. Then

Z either the evaluation diverges or (E[

Proof. By inspection of the semantics, to reach a value with the tagged expression removed the evaluation

must be

The claim holds for the last step of this evaluation since the store is unchanged by the TAG rule. The claim

holds for each of the other steps in this evaluation by Lemma 5.12 (Domain Preservation) on the previous

page. •

5.2.3.2 Privacy

This subsection describes what it means for a concern domain to be private. The following lemma relates the extent of an object's graph to its home domain. It says that if one object can mutate another, then they must have the same home domain. (The lemma also holds for MiniMAOg, though it is not needed there.)

I 1 Lemma 5.14 (Write Home). LetS be a valid store occurring in the evaluation of a well-typed program P.

Let loc £ dom(S) andGsiloc) = (L, E). Then

Wloc' e L - {{locjoc') e writeReach(S)) => (homesiloc') = homesiloc)).

Proof. I prove the contrapositive.

Pick an arbitrary location, lod e L. If homesiloc1) - homesiloc), then the claim holds trivially. So

assume not. By the definition of homes, homesiloc') # homesiloc) implies loc' ^ loc. There must exist

some sequence of n annotated pairs, |/oc;_i "Zoqj e E, where loco = loc and locn = loc'.

Suppose, for the purpose of showing a contradiction, that [loc, loc') e writeReachiS). Then there exists

a such a sequence of annotated pairs such that none of the /,• are read-only. Choose any such sequence.

Since homesiloc') ^ homesiloc), there must exist some j e 11..n} such that homesilocj_\) # homesilocj).

Let S(locj-i) - [T(gi,...,gp).F] and let domainsiT) = (G\,...,Gp).

Consider field fj and let Ô U (G\,...,G'(j) be its declared type. From the typing of field declarations in

T-CLASS, T-ASP, and T-SPEC, we see that either GJSGI/ G\,...,gp! Gp\ - GI or else 5 = readonly. 283

We have assumed that ô # readonly. By Theorem 5.10 (Type Safety) and the positional invariance of do­

mains under subtyping, homesiloc j) = G\ |g, / G\,...,gpl Gp\ = gi. But homesilocj-\) = gi, contradicting

homesiloc j-\) -£ homesiloc j). So it must be the case that (loc, lod) C writeReachiS).

Thus,

Vloc' eL- (homesiloc') ^homes(loc)) => ((loc, loc') € writeReachiS)),

and so the claim holds. • I i

The following definition formalizes the notion of private concern domains as a property of the store. The definition says that any object in the home domain of some spectator may not be in the object graph of another location, unless that location names the private home domain of the spectator. This corresponds to privacy because only a spectator, and any objects it dynamically creates, may mention the spectator's private home domain name.

I 1 Definition 5.15 (Privacy Respecting Store). Let S be a store and P a program. Let

Ss = {{loc>-^[t.F]) e S• isSpectatorit)}.

The store S respects privacy if

VZoci, locz e S • ((3/ocs e S§ • selftocs = homesiloc\ ) t domainss (Z0C2)) => loci € reps{loc2)) •

The following theorem states that all "naturally occurring" stores in MiniMAOg respect privacy.

I Theorem 5.16 (Respect for Privacy). For any valid store S occurring in the evaluation of a well-typed

program P, S respects privacy.

Proof. The proof is by induction on the number of evaluation steps up to the occurrence of the store S.

The base case is the initial store, So, for the evaluation of P. By the definition of program evaluation in

MiniMAOs, So is a valid store that respects privacy. To see that such a store exists, let So be the minimal

valid store for P. Pick any two locations loc\, I0C2 e dom{So). Suppose loc\ e repSo{loc2). Because

V[t.F] e rng{S) • rng{F) = {null}, 284 it must be that loc\ - I0C2. Thus

homes0{loc\) = homes0{loc2) e domainss0(loc2),

and So respects privacy.

For the induction, consider an evaluation step (E[e],/,S> (Ele'l, /, S') in the evaluation of P. The induction hypothesis is that S respects privacy. For each possible evaluation rule, we prove that S' also respects privacy. For all evaluation rules except NEW and SET, S' - S, so this holds trivially. Consider the two non-trivial cases and let be the current redex and e^ight be the result such that e - E'(e|efil and

z e' - E'[

Case 7—NEW.

Because lod' is fresh and rng{F) = {null}, there is no locedom(S') such that either lod' e repsr{loc) or

loc e repst {lod'). Thus, by the induction hypothesis, S' respects privacy.

Case 2—SET. E|EFT = (lod'.f=v), E^GHT = v, S (lod') - \t.F], S' = S®(loc"" [F.Fe (/-» 1/)]), and

loc' \iv- lods,

null otherwise

(Since e|eft is well typed, we can omit any ^-subscript on lod'.)

The only object changed in S' versus S is S (lod'). It v' - null, then V loc e dom(S')-repsi{loc) c reps{loc),

and S' respects privacy by the induction hypothesis.

So assume v' = lod. After the assignment, lod e repsi [loc"). Suppose there is some mapping

(locs~[s.F'])eS'

such that isSpectator(s) and homesi {loc') = self,ocs € domainsst(loc"). We will see that this leads to a contra­

diction. By Theorem 5.10 (TypeSafety), is well typed. Therefore, homesr{lod) e domains(fieldsOf{t){f))

by T-SET and the definition of subtyping. But that implies, by the definition oîfieldsOf, that self,ocs £

domainsgf [lod'), a contradiction. Thus there can be no spectator instance that witnesses to the violation of

respect for privacy. S' respects privacy. 285

So for all possible evaluation steps, respect for privacy is maintained. Thus, by induction, the claim

holds. • l I

Theorem 5.16 (Respect for Privacy) on page 283 and Lemma 5.14 (Write Home) on page 282 imply that any object writable by a spectator may not be referenced by another aspect or by code in the base program. This is what allows reasoning about the program while ignoring spectators.

Rather than treating respect for privacy as a separate property, an alternative way of handling this issue would be to define store validity to include the domain privacy property stated in the lemma. However, that would require threading the proof of domain privacy maintenance through the subject reduction proof. In order to use as much meta-theory of MiniMAOg as possible for MiniMAOg, I choose to separate the domain privacy property.

5.2.3.3 Read-Only Annotations

Definition 4.24 (Reach), Definition 4.25 (Writable Reach), and Definition 4.26 (Object Graph) apply to

MiniMAOg as written. The statement of Definition 4.27 (Included Locations) on page 236 also applies, but the locations function must handle the new syntax of MiniMAOg. For clarity, I restate the definition.

I 1 Definition 5.17 (Included Locations). Given an expression e, the set of locations included in e, denoted

locations(e), is given by the recursive definition in Figure 4.25 on page 236 plus the following:

locations(eor\e\) - locations(eo)u locations[ei)

locations (\[b, loc, (eb, ea) + S) = locations{b) u {loc} u locations(e^) u locations(ea) u locations(B)

Definition 4.28 (Home Domain) on page 236 also applies as written to MiniMAOg.

The assumptions of Lemma 4.29 (Read-only Preservation) and Theorem 4.30 (Read-only Soundness), which disallow all aspects, can be relaxed for MiniMAOg to allow spectators. This is a consequence of Theorem 5.16

(Respect for Privacy) on page 283. Only the BIND case of the original proof for MiniMAOg relies on the strongest assumptions, so the proof below is updated without much trouble.

I I Lemma 5.18 (Read-only Preservation). Suppose the evaluation triple

of a well-typed program P. Let loc be a location in dom{S) such that domains${loc) c

names public concern domains. Let&siloc) - {L,E), and let the following assumptions hold: 286

Assumption 1. VÔ • (locg e locations{e)) => (5 = readonly). (Intuitively, no write-enabled pointers to the

object of interest appear in the expression.)

Assumption 2. \/loc'5 e locations(e) • (Ô = c) => (V/oc" e reps(loc) • (loc', loc") £ writeReach{S)). (Intuitive­

ly, the expression does not contain any write-enabled pointers that reach into the graph of

the object of interest.)

Assumption 3. V loc' e dom(S)-S(loc') = [t.F] => isClass(t)y isSpectator{t). (No assistant instances appear

in the store.)

If(E[e],J,S) — (E[e'],J',S'), then

Consequent 1. Vô -{Iocs e locations [e')) => [5 = readonly)

Consequent2. VZoc^ e locations(e') • (8 - e) => (Vloc" e reps{loc) • [loc', loc") £ writeReach(S'))

Consequent3. VZoc' e dom(S') • S' (Zot/) - F| => isClass(t) v isSpectator(t)

Consequent4. Gs(loc) = Gs'(loc),

Proof. The set up for the proof is exactly like that for Lemma 4.29 (Read-only Preservation) on page 237, as are all cases except that for BIND. I give the BIND case, and the new SURROUND and LEAP cases, for

MiniMAOa.

Casel—BIND, e^ = joinpt j ( vo,...,vn ), E^ght = under chain B,j ( vo,...,vn ), B - adviceBind{j + J), and

S' = S. Because S' = S, consequents 3 and 4 hold.

Now locations[erigh^j contains all elements of locations[e\e^). By the definitions of locations and adviceBind, locations[erjg^t] also includes the locations of the aspects of any matching advice. Advice body expressions in É do not contribute any locations, by a similar argument to that for method bodies in Case 3 of the MiniMA02 proof. The other possible source of new locations for locations \^en,^ is the binding terms in B. In particular, the left-most join point abstraction in j + J of the form may contribute v to locations^jght j because of a this pointcut descriptor.

By assumption 3 and the validity of S, there can be no matching around advice. There may, however, be surround advice. Let \[b, Zocs,il s be an arbitrary surround-advice body tuple in B.

By construction of the advice table, Iocs is not read-only and home${locs) - self/oc, a private concern domain. Let Zoc" be an arbitrary element of reps{loc). Assume for the purpose of showing a contradiction that (iocs, loc") e writeReach(S). Then Lemma 5.14 (Write Home) gives homesiloc") - homes(locs) = 287

selffocS. But by the statement of the lemma, self/ocs t domainss(loc). So Theorem 5.16 (Respect for Privacy) implies that loc" t reps{loc), a contradiction. Thus, (Iocs, loc") t writeReach{S).

Finally, consider the binding term, b. If it does not include a this pointcut binding, then b does not introduce a new location. Also, if the this-bound location is read-only, then assumption 2 holds trivially for it. So assume b = (varloc'Let the pointcut that binds lod be this( t var). By the definition of matchPCDs (see the this-binding rule), loc' being write-enabled implies readonly^ t) = e. But by T-SURR, all formal parameters have read-only types. Thus, the assumption that lod is not read-only leads to a contradiction. For all possible locations in [locations[er]ghtj \ locations(e|eft))> assumption 2 holds.

Case2—SURROUND. Here

e = left chain \[b,locs,(eb,ea),^\\s + B,j ( v0,...,vn)

e,ght - u^er chain BJ ( %

e'b = ebUocs/tb\sU{v0,...,vn)l b\

e'a = eaUocs/th\sU{vo,...,v„)l b\

Because S' = S, consequents 3 and 4 hold. Examining the definition of binding substitution, we see that no new locations are introduced. Some locations may be dropped if not all formais appear in the before- and after-part expressions. So locations[efjghtj Q locations(e\e^), and consequent 2 holds.

Case 3—LEAP. Here S' -S and locations(E|EFT) = locations^g^J, so all the consequents hold. • j

l Theorem 5.19 (Read-only Soundness). Suppose the evaluation triple {t[e], J ,S) appears in the evaluation of a well-typed program P. Let loc be a location in dom(S) such that domainssiloc) c 9?, i.e., S(loc) only names public concern domains. LetGsiloc) = (L,E), and let the following assumptions hold:

Assumption 1. V<5 • (locg e locations{e)) ==> (S = readonly).

Assumption 2. \/loc's e locations(e) • (ô = e) => (Vloc" e reps(loc) • (lod, lod') £ writeReach(S))

Assumption3. \/loc'e dom(S)-S(lod) = [t.F] => isClass{t) v isSpectator(t).

If{E[e],J,S)^ (El v],/',S'), thenGs(loc) = Gs/(/oc).

Proof. Immediate by appealing to Lemma 5.18 (Read-only Preservation) at each step in the evaluation. • 288

5.3 Discussion

By Theorem 5.19 (Read-only Soundness), spectators can be used in a program without breaking the alias- control mechanism. The first two assumptions of the theorem are local properties of an expression. The other assumption just restricts the sorts of programs that are considered. So the statement of the theorem can be viewed as a formalization of local reasoning about the expression. In the last chapter, I argued that allowing assistants in the program would break this local reasoning property. In this chapter, I have demonstrated that spectators, surround advice, and private concern domains can be used to allow some kinds of aspects while maintaining the local reasoning property. I also noted in the last chapter that Read-only Preservation holds with assistants if we consider all applicable assistants in assumption 2 of the theorem. This corresponds to the notion that applicable assistants must be considered for sound reasoning.

Theorem 5.13 (Tag Frame Soundness) on page 282 allows unseen, private concern domains to be modified during method or advice execution. However, because of Theorem 5.16 (Respect for Privacy) on page 283, one can still reason about the effects of a method or piece of advice. To reason about the execution of a method or piece of advice one must know its signature including its effects clause, the concern domains of the target object, and the configuration of assistants in the program, as represented by the aspect instantiation instructions and dependency declarations. By Theorem 5.16 (Respect for Privacy), if the concern domains of the target object do not include any private concern domains, then no changes made by unseen spectators will be visible in the code being considered. The side effects of spectators are effectively sequestered. Thus,

spectators can be used non-invasively, as claimed in Chapter 2. Only the configuration of assistants must be

known to reason about the effects of a block of code.

5.4 Related Work

Surround advice as formalized here is very similar to "harmless advice" [48]. Both restrict advice to always

proceeding and never mutating arguments. Unlike the harmless advice design, MiniMAOs also includes

more powerful around advice—Dantas and Walker [48] might call it "harmful"—that is not restricted. A more

complete discussion of their work appears in Section 4.4.3.2. I also refer the reader to that section for a

discussion of the other work related to MiniMAOs. 289

5.5 Conclusion

In this chapter, I presented MMMAO3. MiniMAOg uses concern domains and read-only annotations to formalize spectator aspects as conceived in Chapter 2. Spectator aspects include surround advice that obeys the control flow restrictions proposed in Section 2.2.2. Surround advice also obeys the restriction on mutation proposed there.

In MiniMAOg, even with unseen spectator aspects, the reasoning properties of MiniMAOg still hold. One does not need to know about the spectators present in a program in order to reason about the base program.

Spectators can be used non-invasively without sacrificing modular reasoning. Only the configuration of assistants must be known to reason about the effects of a block of code. The key to this is my proof of "respect for privacy": the portion of the store mutable by a spectator cannot be observed by any objects that are not part of the spectator's representation. 290

CHAPTER 6. CONCLUSIONS AND FUTURE WORK

In the introduction to this dissertation, I stated my thesis that there exists a discipline for programming in aspect-oriented languages with dynamic-context pointcut descriptors that (1) allows modular reasoning,

(2) permits the use of existing aspect-oriented idioms for separation of concerns, (3) can be verified by a combi­ nation of static typechecking and simple verification conditions, and (4) can be incorporated into a practical, aspect-oriented language.

I conclude my dissertation by reflecting on how this work supports the four claims of my thesis, and outlining the main open problems. I sketch directions for future work on modular reasoning for aspect- oriented languages and conclude with some more general reflections.

6.1 Support for the Thesis

Chapter 2 presented the MAO discipline for modular aspect-oriented reasoning. The MAO discipline addresses the twin problems of modular reasoning in aspect-oriented languages: unseen aspects may apply to the code, and aspects may be developed without complete knowledge of the code that will be advised.

The discipline addresses these problems by separating aspects into two sorts: spectators and assistants. The discipline also requires that the aspect author and the programmer of advised code share the burden of ensuring modular reasoning.

Chapter 2 also described additional language features to facilitate the MAO discipline. These new features include accepts clauses and concern maps for explicit acceptance of assistance. Explicit acceptance allows assistant aspects, which have the full power of Aspectfs aspects, to be modularly identified, and thus considered when reasoning. The new features also provide for spectator declarations. Spectators are statically constrained to not modify the behavior of the modules that they view. This allows modular reasoning about the advised code, even if spectators remain unseen.

To demonstrate how explicit acceptance of assistance enables modular reasoning, Chapter 2 presented my extensions to the Java Modeling Language that allow one to write specifications for advice. These features allow one to write abstract specifications for around advice that model most compositions possible with proceed 291 expressions. Based on the specification constructs, I presented an algorithm for composing specifications that allows one to determine the effective specification for any method call or execution in the presence of advice from accepted assistance. This composition process requires only modularly identifiable specifications and demonstrates the reasoning process that would be used even in the absence of formal specifications, thus supporting claim 1 of my thesis.

Because my proposed language features change the semantics of advice binding in Aspect], Chapter 2 also included my evaluation of the practical effects of my proposal. An analysis of existing code samples showed that current aspect-oriented idioms could be coded within my proposal, supporting claim 2 of my thesis, and providing anecdotal support for claim 4. The ready identification of places to accept assistance from client or implementation utilities in these samples supports my contention that experienced aspect-oriented

programmers are already using disciplines, like the MAO discipline, that enable modular reasoning.

To validate the results of Chapter 2,1 had to demonstrate that the claimed non-interference property of spectators could be statically checked. The remaining chapters built the formalism required to prove this claim, introducing several novel techniques in the process. The meta-theory of my formalism also provides partial support for claim 3 of my thesis.

Chapter 3 introduced MiniMAOi, my core calculus for Aspect], MiniMAOi faithfully explains the semantics

of Aspect]'s around advice on method call and execution join points. In particular, MiniMAOi is the first

aspect-oriented formalism to model the possibility that advice can change the target object at a join point and affect method dispatch. MiniMAOi models the fact that, in Aspect], advice that changes the target object

at a call join point may change the method dispatched to, while advice that changes the target object at an

execution join point will not affect the dispatched method.

Aspect] is not statically type safe [74]. With MiniMAO i, I demonstrated that the type safety problems extend

to the ability to change target objects in advice. To provide a solid foundation for formalizing the reasoning

issues that I am concerned with, I devised changes in advice matching and pointcut typing in MiniMAOi that

allow for static type safety. I introduced the concept of binding soundness for proving the soundness of my

static type system.

Chapter 4 extended MiniMAOi with concern domains and a simple alias-control system using read-only

references. The result, MiniMAOz, enables efficient static detection of tangled code by lifting cross-cutting

concerns from the program implementation into the type system. The type system enforces a non-interference

property so that a global, signature-level search can identify all the code that might mutate a particular concern

domain. Read-only references in MiniMAOi serve as a proxy for the reasoning issues involved in combining

more general alias-control type systems with an aspect-oriented language. I proved that knowing the set of 292 writable concern domains for a method or piece of advice (a modular property given the explicit acceptance of assistance) allows one to reason about the possible side effects of the code.

Chapter 5 presented MiniMAOg. MiniMAOg uses concern domains and read-only annotations to formalize spectator aspects as conceived in Chapter 2. Spectator aspects include surround advice that obeys the control flow restrictions proposed in Section 2.2.2. Surround advice also obeys the restriction on mutation proposed there.

In MiniMAOg, even with unseen spectator aspects, I proved that the reasoning properties ofMiniMAOg still hold. One does not need to know about the spectators present in a program in order to reason about the program. Spectators can be used non-invasively without sacrificing modular reasoning. Only the configuration of assistants must be known to reason about the effects of a block of code. The key to this is my proof of

"respect for privacy": the portion of the store mutable by a spectator cannot be observed by any objects that are not part of the spectator's representation.

6.2 Open Problems

My formal study provides strong, theoretical support for my thesis. My evaluation of existing Aspect] examples in Chapter 2 provides some evidence as to the practicality of my proposal. However, some open problems remain.

— To fully support claim 3,1 must formalize the verification conditions entailed by my proposed specifica­

tion language constructs, and prove that reasoning using effective specifications is sound.

— To fully support claim 4,1 must demonstrate the incorporation of my proposed language features into a

practical programming language. I must use that language to implement realistic-scale programs.

Each of these open problems entails a significant research program. I consider some of the issues involved in the following subsections.

6.2.1 Verification

In Chapter 2, I presented an algorithm for forming the effective specification for a method call in the presence of accepted assistance. I argued that this effective specification was intuitively correct, and that properly constrained spectators could be soundly neglected in reasoning about the method call. The meta- theory of MiniMAOa and MiniMAOg provides more supporting evidence for this argument.

However, more work is needed to support my claim of static verification in the MAO discipline. To prove the claim, I envision developingMiniMAO, as an extension to MiniMAOg. In MiniMAO I would 293

— add constructs to MiniMAOg for giving specifications in the desugared form of Section 2.4.2.1 (i.e., as

quantified variables, pre- and postconditions, and frame axioms);

— develop an axiomatic semantics for MiniMAO and prove it sound with respect to the operational

semantics [70, 71]; and

— prove that the axiomatic semantics of an advised method call corresponds to the effective specification

formed according to my algorithm.

I would need to show that in MiniMAO the actual code executed at run time, including spectators, corre­ sponds to the effective specification, which excludes spectators. The key to this is that the effective specification is considered relative to the named, public concern domains of the method. Thus, the axiomatization of Mini­

MAO must accommodate concern domains.

It seems that separation logic may provide the leverage to make this work [126,127,143,144]. As discussed in Section 4.5, the central idea in separation logic is to separate specification predicates in a "spatial con­

junction" so that each refers to an unconnected, disjoint subset of the heap, where "unconnected" means the absence of pointers from one subset to the other. This unconnected-ness requirement is related to the restrictions on aliasing in Theorem 5.19 (Read-only Soundness). Concern domains, and private spectator domains, should provide the necessary substrate for applying separation logic to the verification problem in

MiniMAO. O'Hearn et al. [127, §8] also discuss a notion of "memory faults", run-time errors that are signaled when code accesses a portion of the heap outside of the subset described in the specification of the code. A proof of correctness for the code must ensure that such memory faults cannot occur. The static type system of

MiniMAO can ensure this property for write access. It may be that MiniMAO would also need readable domain sets, which would place a static bound on the set of domains that may be read by a piece of code.

6.2.1.1 Dynamic-Context Pointcut Descriptors

Another challenge in formally verifying aspect-oriented programs is dynamic-context pointcut descriptors.

With pointcut descriptors like cflow in a language, static determination of whether a piece of advice will be

executed at a given join point would seem to be undecidable.

As mentioned in Section 2.5.2, one potential solution to this problem would be to include dynamic-context

predicates in the specification language. This would allow effective specifications to use guarded specification

cases for advice that includes dynamic-context pointcut descriptors.

It might also be possible to simplify the set of dynamic-context pointcut descriptors. For example, the

following combination of general, dynamic-context pointcut descriptors; 294

cflow(execution(* m(..))) && !cflowbelow(execution(* m(..)))) is a common idiom in Aspect! for matching the first execution of a method m. Instead of using general dynamic-context pointcut descriptors, perhaps a simpler, more specific descriptor could be used, like

firstExecution(* m(..)).

Other common idioms might require other simple pointcut descriptors. This more specific, but less powerful, set of dynamic-context pointcut descriptors may simplify the static analysis. For example, they might allow the

axiomatic semantics of MiniMAO to include a simple abstraction of the call stack. If so, this abstraction could

be used to choose between dynamic-context-guarded specification cases at join points. On the other hand, it

may be that sacrificing the power of general, dynamic-context pointcut descriptors is too great a sacrifice in

expressiveness. After all, these pointcut descriptors seem to be one of the unique contributions of Aspect).

(See my discussion of the work of Kiczales and Mezini [80] in Section 2.6.)

6.2.1.2 Multiple Proceeds

One benefit of detailed method specifications in a language like Java with JML, or Eiffel [110, 111], is

that individual methods may be separately verified against their specifications. My proposed specification

constructs should provide similar benefits for separate verification of advice. However, it is not precisely clear

how to map the proceed-clause-separated subcases of advice specifications to the actual code of the advice.

When the code of the advice is separated into neat blocks separated by proceed expressions that are always

reached, the verification problem seems straightforward. However, proceed expressions in an advice body

may be embedded in various looping and branching constructs. Because the specification for a piece of advice

makes promises not just about the pre- and postconditions, but about the control flow, the proof obligations

for showing that around advice is correct are stronger.

Furthermore, as mentioned in Section 2.4.1, some advice may proceed an indefinite number of times.

Thus, future work must also consider specification constructs for describing this situation. Perhaps some of

the JML techniques for specifying loops and loop invariants might apply [94, §12.2].

6.2.1.3 Mechanized Meta-theory1

One concern in extending MiniMAOg for formal verification is that proofs of the meta-theory are already

quite involved. Thus, it may be sensible to use an automated reasoning system, such as Twelf [134], for any

^This section heading comes from the tag line of the POPLMARK project,"Mechanized Metatheory for the Masses" [16]. 295

extensions. (Other potential systems are enumerated by Aydemier et al. [16, §1] in their POPLMARK challenge.)

Although I am confident in the veracity of the proofs given in this work, only the most dedicated reviewer could check all the details presented therein. Machine checked proofs would increase others confidence in this work.

Using an automated system for proving the soundness of verification in MiniMAO would also open the door to investigating other features of Aspect!where the tedium of manual proofs would otherwise pose an obstacle. Among these would be the formalization of before and after advice, introductions, and the rest of

Aspect!'s pointcut descriptors. The automated system could also be used to investigate the use of concern domains for providing abstract descriptions of control flow, analogous to the subsystem annotations of Lam and Rinard [88] discussed in Section 4.5.

6.2.2 MAO

In Chapter 2,1 described an evaluation of my proposed language features based on studying small examples of existing programs written in Aspect!. This provides some support for claim 4 of my thesis, that the MAO discipline can be incorporated into a practical, aspect-oriented language. However, to fully support my claim, I must actually incorporate the discipline into a practical language.

So, having laid the theoretical foundation with MiniMAO, an obvious next step is to develop a full-scale programming language—a variant of Aspect!—that provides my type safety and reasoning properties. I call this yet-to-be-developed language MAO. I would also like to extend IML [93,94] for use in specifying other features of MAO programs beyond just around advice.

6.2.2.1 Approach

There are two approaches to implementing MAO that have complementary advantages and disadvantages.

The first approach would be to develop MAO as an extension of the Aspect Bench Compiler (ABC) [54], ABC is a full implementation of a compiler for Aspect!, based on the Polyglot compiler framework [122] for its front end and the Soot optimization framework [155] for its back end. One of the main advantages of using ABC to implement MAO is that, being a Polyglot extension, my prototype implementation of concern maps and accepts clauses (discussed in Section 2.2.1.3) could be ported without much difficulty. The other advantage of building on ABC is that it was specifically designed as a framework for investigating extensions to Aspect!.

ABC is strictly a compiler; it translates program text to machine code (or lava virtual machine code in this case). Merely implementing the translation semantics and typechecking for MAO is of relatively little technical interest. Although such an exercise is bound to uncover issues not considered in my formal study, my main 296 motivation for implementing MAO is to study the issues that arise in using the language for real software development.

Most large-scale software development is presently done using integrated development environments.

Thus, another approach to implementing MAO would be to extend the Aspect] Development Toolkit (AJDT) for

ECLIPSE.2 This approach would allow programmers to use MAO within a professional integrated development environment. It would also link the implementation of MAO to the reference implementation of Aspect), allowing (forcing?) MAO to keep pace with the evolution of the core language. Furthermore, if the MAO extensions proved useful in practice, they could be more easily adopted into the core Aspect) language under this approach. Another advantage of this approach is that it provides the right environment for my proposed tool support for automatic generation of effective specifications (see Section 2.5.3). The major disadvantage of this approach is that the AJDT is not primarily designed to provided an extensible language platform, although the AJDT is open source, and so extensions are possible. However, because its primary goal is as a reference implementation, the AJDT is much more likely to change in ways that break extensions than is an extension framework like ABC.

6.2.2.2 Evaluation

Having developed an implementation of MAO, I would like to program and specify non-trivial systems using the MAO language and discipline. Questions to be answered include:

— Are concern domains that partition the heap an effective mechanism for statically separating con­

cerns? Or are concerns, even in aspect-oriented programming, sufficiently tangled so that no statically-

enforced separation is reasonable?

— Does the MAO discipline, like behavioral subtyping, help in guiding programmers' thinking and design

efforts?

— Do effective specifications help programmers to reason about advised code?

— What proportion of aspects in large-scale systems are spectators? assistants?

— What tool support is necessary to help developers write useful specifications of advice?

Like many practical questions in programming languages, it is difficult and expensive to perform sufficiently large experiments to get significant answers to these questions. One way to achieve a larger sample is to make

2The AJDT is available from http://www.eclipse.org/aspectj, URL valid as of July 17, 2005. 297 the tools freely available and encourage the development of a user community. Such an approach was key to the early success of Aspect}, and has also been beneficial for the JML project.

6.2.2.3 Other Features

Other interesting issues would arise with the development of a full-scale MAO language. One issue is adding concern domain annotations to the Java API. For this, I could borrow the technique of JML's .spec files

[94]. These files allow one to write a specification for a module separately from the module's declaration. They are used in the JML project to provide behavioral specifications for a subset of the Java API.

Another issue that I would have to address is I/O. Disk input and output can be used as storage to pass data between domains that would otherwise be separated by the static type system. It may be sensible to consider such uses to be outside the scope of the type system's safety properties. Another possibility is to develop a locking I/O that could confine certain files to certain concern domains. Such a library would have to interact more closely with the file system than Java's does. Also related to I/O is an investigation of how concern domains interact with graphical user interfaces. In my evaluation of proposed language features (see

Section 2.3), I discussed the Debug aspect of AspectJ's spacewar example. This aspect attaches an additional menu item to the game's interface when the aspect is included in the system. To accommodate this with concern domains, it may be that all user interface elements must belong to a common concern domain.

But how would this interact with my requirement that objects not maintain write-enabled pointers to other concern domains? It may be that the call-back architecture of most GUI frameworks would allow my restriction on write-enabled pointers to stand. Or it may be that the restriction would have to be loosened. I conjecture that it would be sufficient to restrict spectators to obeying the read-only restriction, but allow assistants and other classes to violate it. But it is not clear how this would affect regular objects in the representation of a spectator. Another possibility for concern domain references is to allow hierarchical concern domains, like the domains of Aldrich and Chambers [9],

To maintain the static type safety of MiniMAO, I would also have to investigate the use of introductions in

AspectJ. Introductions in AspectJ are not statically type safe without a whole-program analysis. This is because two different aspects may introduce colliding methods to a class. The one that survives to run time is whichever is added last. But a client may expect the other method. In Multijava, we demonstrate how open classes can be used to achieve modular, static typechecking for introductions [38,43,46]. In fact, with open classes two different methods can be safely introduced to the same class, with a client deciding which of the two should be in scope. This lexical selection of applicable extensions was an early motivation for the current work. 298

6.3 Future Work

In additional to the open problems discussed above, the current work also suggests several other interesting lines of investigation. I discuss these briefly here.

6.3.1 Alias Control

I showed in Section 4.4.3.2 that the restrictions of my simple alias-control system could be violated in the presence of assistants. The private concern domains of spectators prevent them from violating the system in this way. The basic issue is that assistants can "leak" pointers into a computation. Adding a more expressive alias-control system to MiniMAO might allow more control over aliasing between assistant aspects and base program objects. On the other hand, the power of assistant aspects might break the more powerful alias-control system also.

Here are a couple of promising approaches to investigating this issue:

— The per-object domains of Aldrich and Chambers [9] might allow my concern domains and an alias-

control system to be unified. In their work they control aliases in order to understand the aliasing

patterns used in program architecture. They do not consider side-effect control.

— Rinard et al. [146] propose "abstract fields", which seem to be equivalent to Leino's data groups [97].

They use abstract fields to detect (through a global analysis) object-aspect interference without breaking

data encapsulation. Abstract fields are also useful in providing a more abstract representation of any

interference, uncluttered by the specific details of all the concrete fields. My modular, static type system

uses concern domains to limit interference to that specifically allowed by the programmer. Perhaps

concern domains closer in granularity to data groups could be used to statically prevent interference at

a finer granularity.

6.3.2 Late Binding and Aspect-Oriented Virtual Machines

It seems that the non-interference properties of spectators might have implications for dynamic weaving

[57, 112, 113, 135, 138, 151]. Because spectators cannot change the behavior of other modules, it seems natural to be able to apply them to a program that is already running, for example to diagnose a problem in a long-running server application. The generality of spectator application means that they can potentially be dispatched to at any join point. Thus, it seems that some form of virtual machine support for spectators might be interesting. 299

The Steamloom virtual machine includes dynamic aspect dispatch [19]. The CeasarJ aspect-oriented language uses Steamloom as its virtual machine to enabled dynamic deployment (and "undeployment") of aspects [113]. (The JRockit JVM from BEA Weblogic also includes support for dynamic weaving.) An aspect- oriented virtual machine like Steamloom would include facilities for applying and removing spectators from already running programs and for dispatching to spectators at the appropriate join points.

6.3.3 Concurrent Aspect-oriented Programming

My study focused on sequential aspect-oriented programs. This focus excludes some interesting techniques.

For example, Laddad's worker object creation pattern uses proceed closures [86, §8.1]. In this pattern, advice captures a proceed expression inside an instance of an anonymous Runnable class. This allows the advised code to be postponed, or executed immediately but in a new thread. Such use of proceed is fascinating, but to study it I would need a formalism that models concurrent processes. It may be that some variant of the

7r-calculus would be appropriate for this study [115].

6.3.4 Subtype Matching in Around? Unsound!

It is interesting to note that the semantics of matchPCDs for surround advice, described in Section 5.1.2.3, corresponds to that used by AspectJ for all advice. Before and after advice in AspectJ share many of the properties of surround advice, and I conjecture that AspectJ's matching semantics is statically type safe for before and after advice. But as discussed in Section 3.2.2.4, using a semantics like matchPCDs for around advice is not statically type safe.

AspectJ was designed for expressiveness and to be Java-like, in order that it might be readily adopted by

Java programmers. It is common for Java programs, especially prior to Java 5 [65], to include many type casts.

Prior versions of Java did not include parametric polymorphism. Container classes in these versions of Java treated all contained objects as having type Object. Downcasts had to be used to perform any interesting operations on an object extracted from such a collection. Java also has a co- and contravariance problem for arrays [13, §6.4.4] that is similar to the one for arguments in around advice in AspectJ. (See sample code in Figure 6.1 on the next page.) Because of these static type safety issues in Java, AspectJ's designers did not treat static type safety as their highest goal.3 With the array co- and contravariance problem in Java, there is no way to avoid the exception. This differs from the situation in Aspect] where the compiler automatically inserts a cast. Instead of inserting the cast, the AspectJ compiler could issue an error and require that the

3 Personal communication, Erik Hilsdale, June 17,2005. 300

public class ArrayCoCon { public static void main(String[] args) { lnteger[] i = new lnteger[1 ]; m(i); // triggers an ArrayStoreException at run time }

public static void m(Object[] o) { System.out.println(o instanceof Object[]); //true for call above System.out.println(o instanceof Integer!]); //true for call above o[0] = new ObjectO; // no way to avoid an exception! } }

Figure 6.1 Array Co- and Contravariance Problem in Java programmer manually insert the appropriate typecase and cast to suppress the compiler warning, and avoid any undesired run-time type errors, based on her knowledge of the desired semantics.

On the other hand, because Java 5 has dramatically reduced the need for type casts, it is interesting to consider how around advice in an AspectJ-like language might be made statically type safe without giving up expressiveness. Some possible alternatives are:

Exact matching. This is the MiniMAOi solution for soundness of its static type system, though it means that

before, after, and surround advice use a different join point matching semantics. This is likely to be

confusing to programmers. Would exact matching on interface types solve the expressiveness problem?

1 conjecture that it would but have not thought deeply about this. Even so, this would still leave the

problem of having different semantics for pointcut matching in different kinds of advice. This could

be mitigated by introducing new pointcut descriptors, like exactCall, that use exact type matching.

Around advice would only be statically type safe if it used exact-matching pointcut descriptors.

Whole-program analysis. Rather than requiring a program-inserted type cast, a whole-program analysis

could be performed to see if any unsafe uses appear. With concern maps the scope of this analysis could

be restricted. However, once we admit dynamic weaving of aspects, then any analysis based on visible,

unsafe uses would no longer be safe. Perhaps this could be avoided by only allowing dynamic weaving

of before, after, and surround advice.

Final parameters. It might seem that the co- and contravariance problem for around advice could be avoided

by making all pointcut-bound parameters final. However, this does not prevent swapping parameter

order or substituting local state of the aspect for parameters, so it is a non-solution. 301

Revised proceed. Another possibility would be to make proceed in around advice behave something like the

automatic proceed in surround advice. It could be restricted to not allowing changing of the values

passed to the advised code in reference type arguments. It could still allow mutation of those arguments,

zero or more proceeds, and mutation of results. This avoids the co- and contravariance problem because

the arguments would point to the same objects as in the original call, thus preserving type invariance,

while still allowing more flexibility than can be allowed for surround advice.

More expressive types. Would a more expressive type system for matching pointcut descriptors, perhaps using

bounded parametric types [26,136,145] or dependent types [125,161], allow less restrictive pointcut

typing and matching while maintaining soundness? It is appealing to consider these more sophisticated

type systems. On the other hand, would such a type system be accessible for the typical programmer?

6.3.5 Component-based Programming

It would also be interesting to compare the reasoning problem in aspect-oriented programming to reason­ ing in component-based programming [63,152].

Component-based programming requires components to specify their expectations of external modules.

This allows separate verification of the components, provided that expectations are checked at composition time. In the MAO discipline, the steps are performed in a different order. Each piece of advice is separately verified. Then, for a given composition, the specifications are composed to determine the effective specification of an advised join point. This effective specification is used to verify the code that triggers the join point. A problem that would surface as an unsatisfied expectation in component-based programming, appears as an effective specification like requires false; ensures true;. It is essentially useless for verifying the client code.

It seems that the essential trade-off is that component-based programming provides simpler compositional reasoning, but less expressive composition mechanisms versus aspect-oriented programming. Aspectual collaborations [102] can be considered a mid-point between these extremes, though that system does not include formal specifications.

6.4 Postscript

My work on Multilava [38, 43, 46] initially attracted me to the problems explored here. Open classes in

Multilava preserve static type safety, while the similar introductions of AspectJ do not. I was troubled by this mismatch. At the time it seemed incongruous that an extension to a statically type safe language would not try

to maintain this property. In retrospect, Java is not so statically type safe as I thought. Though with parametric 302 polymorphism, Java 5 comes closer to this ideal (especially if one eschews arrays of reference types for generic

Array Lists).

But still, I was and am bothered that a language that claims to improve modularity properties actually requires a whole program analysis for type checking and compilation.

My contention was that if some formal notion of modular reasoning was not to be found for AspectJ, then it was simply a programming language for specifying global mutations over the syntax of a program. Aspects instruct the compiler to edit code that matches certain quantified predicates. For dynamic-context pointcut descriptors, the compiler is instructed to insert branching instructions also.

However, having demonstrated that modular reasoning is, in fact, possible in AspectJ, I am now convinced that aspect-oriented programming really is a new paradigm for separating cross-cutting concerns. I am still troubled by the lack of static type safety and other properties of AspectJ. However, I believe that these problems can be remedied in future aspect-oriented languages and I look forward to making contributions in that area.

Is aspect-oriented programming as radical a departure from the past as object-oriented programming was? I do not think so. Aspect-oriented programming is more evolutionary in nature. While object-oriented programming really requires an entirely different approach to conceptualizing a problem domain, aspect- oriented programming requires more of an augmentation of the approach. Aspects serve as abstractions to separate the code for cross-cutting concerns, and as glue to connect concerns together. However, I suspect that within those concerns, regular object-oriented designs will prevail.

I am left with one main question: Does the complexity in reasoning about aspect-oriented programs make the paradigm inaccessible to the typical programmer? It may be that the weight of the machinery required for modular, aspect-oriented reasoning is just as heavy as the code needed to modularize cross-cutting concerns in an object-oriented program. If so, then perhaps something like spectators, or the harmless advice of Dan tas and Walker [48], is sufficient, and everything else can be done with plain old objects. Only time may provide an answer, and given the vagaries of technological evolution, we may never know. Still, I am sure that it will be an interesting journey. 303

BIBLIOGRAPHY

[1] Martin Abadi and Luca Cardelli. A Theory of Objects. Monographs in Computer Science. Springer-Verlag,

1996.

[2] FOOL-12. The 12th international workshop on Foundations of object-oriented languages, Long Beach,

California, 2005. ACM.

[3] ICSE '05. Proc. of the 27th international conference on Software engineering, St. Louis, Missouri, USA,

2005. ACM.

[4] OOPSLA '02. Proc. of the 17th annual ACM SIGPLAN conference on Object-oriented programming, sys­

tems, languages, and applications, Seattle, USA, 2002. ACM.

[5] POPL '05. Proc. of the 32nd ACM SIGPLAN-S1GACT symposium on Principles of programming languages,

Long Beach, California, USA, 2005. ACM.

[6] AOSD '03. Proc. of the 2nd international conference on Aspect-oriented software development, Boston,

Mass., USA, 2003. ACM.

[7] AOSD '04. Proc. of the 3rd international conference on Aspect-oriented software development, Lancaster,

UK, 2004. ACM.

[8] Jonathan Aldrich. Open modules: A proposal for modular reasoning in aspect-oriented programming. In

Curtis Clifton, Ralf Lâmmel, and Gary T. Leavens, editors, FOAL 2004 Proceedings: Foundations of Aspect-

Oriented Languages Workshop at AOSD 2004, pages 7-18, Lancaster, UK, 2004. Iowa State University,

Dept. of Computer Science.

[9] Jonathan Aldrich and Craig Chambers. Ownership domains: Separating aliasing policy from mechanism.

InOdersky [124], pages 1-25.

[10] Jonathan Aldrich, Valentin Kostadinov, and Craig Chambers. Alias annotations for program understand­

ing. In OOPSLA '02 [4], pages 311-330. 304

[11] Pierre America. Inheritance and subtyping in a parallel object-oriented language. In Jean Bezivin

et al., editors, ECOOP '87, European Conference on Object-Oriented Programming, Paris, France, pages

234-242. Springer-Verlag, 1987. Lecture Notes in Computer Science, volume 276.

[12] Pierre America. Designing an object-oriented programming language with behavioural subtyping. In J. W.

de Bakker, W. R de Roever, and G. Rozenberg, editors, Foundations of Object-Oriented Languages, REX

School/Workshop, Noordwijkerhout, The Netherlands, May/June 1990, volume 489, pages 60-90. Springer-

Verlag, 1991.

[13] Ken Arnold, James Gosling, and David Holmes. The Java Programming Language, Third Edition. Addison -

Wesley, Reading, MA, 2000.

[14] AspectJ Team. The AspectJ programming guide. Available from http://eclipse.org/aspectj on March 1,

2003.

[15] Enis Avdicausevic, Marjan Mernik, Mitja Lenic, and Viljem Zumer. Experimental aspect-oriented lan­

guage - AspectCOOL. In Proc. of the 2002 ACM Symposium on Applied Computing, Madrid, Spain, 2002.

ACM.

[16] Brian E. Aydemier, Aaron Bohannon, Matthew Fairbairn, J. Nathan Foster, Benjamin C. Pierce, Peter

Sewell, Dimitrios Vytiniotis, Geoffrey Washburn, Stephanie Weirich, and Steve Zdancewic. Mechanized

metatheory for the masses: The POPLmark challenge. In Theorem Proving in Higher Order Logics: 18th

International Conference, Lecture Notes in Computer Science, Oxford, UK, June 2005. Springer-Verlag.

To appear.

[17] Lodewijk Bergmans and Mehmet Akçits. Composing crosscutting concerns using composition filters.

Comm. of the ACM, 44(10):51-57, 2001.

[18] A. Michael Berman, editor. OOPSLA '99: Proceedings of the 14th ACM SIGPLAN conference on Object-

oriented programming, systems, languages, and applications, Denver, Colorado, USA, 1999. ACM Press.

[19] Christoph Bockisch, Michael Haupt, Mira Mezini, and Klaus Ostermann. Virtual machine support for

dynamic join points. In AOSD '04 [7], pages 83-92.

[20] Ron Bodkin, Don Almaer, and Ramnivas Laddad. aTrack: an enterprise bug tracking system using AOP. A

demonstration at AOSD 2004, available from https://atrack.dev.java.net/ on July 17,2005, March 2004.

[21] Jonas Bonér and Alexandre Vasseur. AspectWerkz. http://aspectwerkz.codehaus.org/index.html, valid

July 17, 2005. 305

[22] Alex Borgida, John Mylopoulos, and Raymond Reiter. On the frame problem in procedure specifications.

IEEE Transactions on Software Engineering, 21(10):785-798, October 1995.

[23] Richard Bornât, Cristiano Calcagno, Peter O'Hearn, and Matthew Parkinson. Permission accounting in

separation logic. In POPL '05 [5].

[24] L. Bougé and N. Francez. A compositional approach to superimposition. In Proc. of the 15th ACM

SIGPLAN-SIGACT symposium on Principles of programming languages, pages 240-249, San Diego, Cali­

fornia, USA, 1988. ACM Press.

[25] Chandrasekhar Boyapati, Barbara Liskov, and Liuba Shrira. Ownership types for object encapsulation.

In Proc. of the 30th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, New

Orleans, Louisiana, USA, 2003. ACM Press.

[26] K. B. Bruce. A paradigmatic object-oriented programming language: Design, static typing and semantics.

Journal of , 4(2):127-206, April 1994.

[27] Glenn Bruns, Radha Jagadeesan, Alan Jeffrey, and James Riely. juabc: A minimal aspect calculus. In

Proceedings of the2004 International Conference on Concurrency Theory, pages 209-224. Springer-Verlag,

2004.

[28] Lilian Burdy, Yoonsik Cheon, David Cok, Michael Ernst, Joe Kiniry, Gary T. Leavens, K. Rustan M. Leino,

and Erik Poll. An overview of JML tools and applications. In Thomas Arts and Wan Fokkink, editors,

Eighth International Workshop on Formal Methods for Industrial Critical Systems (FMICS 03), volume 80

of Electronic Notes in Theoretical Computer Science (ENTCS), pages 73-89. Elsevier, June 2003.

[29] Bill Burke, Austin Chau, Marc Fleury, Adrian Brock, Andy Godwin, and Harald Gliebe. JBoss as­

pect oriented programming, http://www.jboss.org/index.html?module=html&op=userdisplay&id=

developers/projects/jboss/aop, valid March 1,2004.

[30] Luca Cardelli, editor. ECOOP '03 - Object-Oriented Programming European Conference, volume 2743 of

Lecture Notes in Comp. Sci., Darmstadt, Germany, 2003. Springer-Verlag.

131] Giuseppe Castagna. Covariance and contravariance: conflict without a cause. ACM Trans, on Prog. Lang,

and Systems, 17(3):431-447,1995.

[32] Yoonsik Cheon. A Runtime Assertion Checker for the Java Modeling Language. PhD thesis, Iowa State

University, Ames, Iowa, USA, 2003. Available as ISU/CS TR 03-09, from archives.cs.iastate.edu. 306

[33] Yoonsik Cheon and Gary T. Leavens. A runtime assertion checker for the Java Modeling Language

(JML). In Hamid R. Arabnia and Youngsong Mun, editors, Proceedings of the International Conference on

Software Engineering Research and Practice (SERP '02), Las Vegas, Nevada, USA, June 24-27,2002, pages

322-328. CSREA Press, June 2002.

[34] Shigeru Chiba and Kiyoshi Nakagawa. Josh: An open AspectJ-like language. In AOSD '04 [7], pages

101-111.

[35] Dave Clarke and Sophia Drossopoulou. Ownership, encapsulation and the disjointness of type and effect.

In OOPSLA '02 [4], pages 292-310.

[36] Siobhân Clarke and Robert J. Walker. Composition patterns: an approach to designing reusable aspects.

In Proceedings of the 23rd international conference on Software engineering, pages 5-14. IEEE Computer

Society, 2001. ISBN 0-7695-1050-7.

[37] Siobhân Clarke and Robert J. Walker. Towards a standard design language for AOSD. In Kiczales [79],

pages 113-119.

[38] Curtis Clifton. Multilava: Design, implementation, and evaluation of a Java-compatible language sup­

porting modular open classes and symmetric multiple dispatch. Master's thesis, Iowa State University,

Ames, Iowa, USA, 2001.

[39] Curtis Clifton and Gary T. Leavens. Observers and assistants: A proposal for modular aspect-oriented

reasoning. In Gary T. Leavens and Ron Cytron, editors, FOAL 2002 Proceedings: Foundations of Aspect-

Oriented Languages Workshop at AOSD 2002, pages 33-44, Enschede, the Netherlands, 2002. Iowa State

University, Dept. of Computer Science.

[40] Curtis Clifton and Gary T. Leavens. Spectators and assistants: Enabling modular aspect-oriented reason­

ing. Technical Report 02-10, Iowa State University, Department of Computer Science, 2002.

[41] Curtis Clifton and Gary T. Leavens. Obliviousness, modular reasoning, and the behavioral subtyping

analogy. Technical Report 03-15, Iowa State University, Department of Computer Science, 2003.

[42] Curtis Clifton and Gary T. Leavens. MiniMAO: Investigating the semantics of proceed. In Curtis Clifton,

Ralf Lâmmel, and Gary T. Leavens, editors, FOAL 2005 Proceedings: Foundations of Aspect-Oriented

Languages Workshop at AOSD 2005, pages 51-61, Chicago, Illinois, USA, 2005. Iowa State University,

Dept. of Computer Science. 307

[43] Curtis Clifton, Gary T. Leavens, Craig Chambers, and Todd Millstein. Multilava: Modular open classes and

symmetric multiple dispatch for Java. In OOPSLA 2000 Conference on Object-Oriented Programming,

Systems, Languages, and Applications, volume 35(10), pages 130-145, New York, 2000.

[44] Curtis Clifton, Gary T. Leavens, and Mitchell Wand. Formal definition of the parameterized aspect

calculus. Technical Report 03-12b, Iowa State University, Department of Computer Science, 2003.

[45] Curtis Clifton, Gary T. Leavens, and Mitchell Wand. Parameterized aspect calculus: A core calculus for

the direct study of aspect-oriented languages. Technical Report 03-13, Iowa State University, Department

of Computer Science, 2003.

[46] Curtis Clifton, Todd Millstein, Gary T. Leavens, and Craig Chambers. Multijava: Design rationale, compiler

implementation, and applications. Trans, on Prog. Lang, and Sys., 2005. To appear, preliminary version

available from ftp://ftp.cs.iastate.edu/pub/techreports/TR04-01/TR.pdf on July 17,2005.

[47] Yvonne Coady, Gregor Kiczales, Mike Feeley, and Greg Smolyn. Using AspectC to improve the modu­

larity of path-specific customization in code. In ESEC/FSE-9: Proceedings of the 8th

European software engineering conference held jointly with 9th ACM SIGSOFT international symposium

on Foundations of software engineering, pages 88-98, Vienna, Austria, 2001. ACM.

[48] Daniel S. Dantas and David Walker. Harmless advice. In FOOL-12 [2].

[49] A. Darvas and R Miiller. Reasoning About Method Calls in JML Specifications. Submitted to FTfJP 2005,

available from http://sct.inf.ethz.ch/publications/getpdf.php?bibname=Own&id=DarvasMueller.pdf

on July 17,2005.

[50] Krishna Kishore Dhara and Gary T. Leavens. Weak behavioral subtyping for types with mutable objects.

In S. Brookes, M. Main, A. Melton, and M. Mislove, editors, Mathematical Foundations of Programming

Semantics, Eleventh Annual Conference, volume 1 of Electronic Notes in Theoretical Computer Science.

Elsevier, 1995.

[51] Krishna Kishore Dhara and Gary T. Leavens. Forcing behavioral subtyping through specification inher­

itance. In Proceedings of the 18th International Conference on Software Engineering, Berlin, Germany,

pages 258-267. IEFE Computer Society Press, 1996. A corrected version is Iowa State University, Dept. of

Computer Science TR #95-20c.

[52] Werner Dietl and Peter Miiller. Universes: Lightweight ownership for JML. Journal of Object Technology,

2005. 308

[53] R. Douence, O. Motelet, and M. Stidholt. A formal definition of crosscuts. In Reflection 2001, volume

2192 of Lecture Notes in Comp. Sci., Heidelberg, Germany, November 2001. Springer-Verlag.

[54] Bruno Dufour, Christopher Goard, Laurie Hendren, Oege de Moor, Ganesh Sittampalam, and Clark

Verbrugge. Measuring the dynamic behavior of aspect] programs. In Proc. of the 19th annual ACM

SIGPLAN Conf. on Object-oriented programming, systems, languages, and applications, pages 150-169,

Vancouver, BC, Canada, 2004. ACM.

[55] Matthew Dwyer, editor. Proc. of the 12th ACM SIGSOFT symposium on the Foundations of software

engineering (FSE-12), Newport Beach, California, USA, 2004. ACM Press.

[56] Michael Eichberg, Mira Mezini, and Klaus Ostermann. Pointcuts as functional queries. In Wei-Ngan Chin,

editor, Programming Languages and Systems: Second Asian Symposium, APLAS 2004, Lecture Notes in

Comp. Sci., pages 366-382, Taipei, Taiwan, November 2004. Springer-Verlag.

[57] Erik Ernst and David H. Lorenz. Aspects and polymorphism in aspect]. In AOSD '03 [6], pages 150-157.

[58] Matthias Felleisen and Robert Hieb. The revised report on the syntactic theories of sequential control

and state. Theoretical Computer Science, 103:235-271,1992.

[59] Robert E. Filman and Daniel R Friedman. Aspect-oriented programming is quantification and oblivi­

ousness. In Robert E. Filman, Tzilla Elrad, Siobhân Clarke, and Mehmet Ak§it, editors, Aspect-Oriented

Software Development. Addison-Wesley, 2005.

[60] Robert E. Filman, Stuart Barrett, Diana D. Lee, and Ted Linden. Inserting ilities by controlling communi­

cations. Comm. of the ACM, 45(1):116-122, 2002.

[61] Matthew Flatt, Shriram Krishnamurthi, and Matthias Felleisen. A programmer's reduction semantics for

classes and mixins. In Formal Syntax and Semantics of Java, chapter 7, pages 241-269. Springer-Verlag,

1999.

[62] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable

Object-Oriented Software. Addison-Wesley, Reading, Mass., 1995.

[63] David S. Gibson, Bruce W. Weide, Scott M. Pike, and Stephen H. Edwards. Toward a normative theory

for component-based system design. In Gary T. Leavens and Murali Sitaraman, editors, Foundations of

Component-Based Systems, chapter 10, pages 211-230. Cambridge University Press, 2000. ISBN 0-521-

77164-1. 309

[64] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java Language Specification, Second Edition.

The Java Series. Addison-Wesley, Boston, Mass., 2000.

[65] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java Language Specification, Third Edition.

The Java Series. Addison-Wesley, Boston, Mass., 2005.

[66] Jeff Gray, Ted Bapty, Sandeep Neema, Douglas C. Schmidt, Aniruddha Gokhale, and Balachandran

Natarajan. An approach for supporting aspect-oriented domain modeling. In Proceedings of the second

international conference on Generative programming and component engineering, pages 151-168, Erfurt,

Germany, 2003. Springer-Verlag.

[67] Kris Gybels and Johan Brichau. Arranging language features for more robust pattern-based crosscuts. In

AOSD '03 [6], pages 60-69.

[68] William Harrison and Harold Ossher. Subject-oriented programming (a critique of pure objects). In

OOPSLA '93: Proceedings of the eighth annual conference on Object-oriented programming systems, lan­

guages, and applications, pages 411-428. ACM Press, Washington, D.C., USA, 1993.

[69] Erik Hatcher and Steve Loughran. Java Development with Ant. Manning, Greenwich, CT, 2003.

[70] C. A. R. Hoare. An axiomatic basis for computer programming. Comm. of the ACM, 12(10):576-583, Oct.

1969.

[71] C. A. R. Hoare. Proof of correctness of data representations. Acta Informatica, 1(4):271—281,1972.

[72] IBM. Concern manipulation environment. Available from http://www.research.ibm.com/cme/papers/

handout.html on July 17,2005, March 2003.

[73] Atsushi Igarashi, Benjamin Pierce, and Philip Wadler. Featherweight Java: A minimal core calculus for

Java and GJ. In Berman [18], pages 132-146.

[74] Radha Jagadeesan, Alan Jeffrey, and James Riely. A typed calculus for aspect oriented programs. Available

from ftp://fpl.cs.depaul.edu/pub/rjagadeesan/typedABL.pdf on February 1, 2004.

[75] Radha Jagadeesan, Alan Jeffrey, and James Riely. A calculus of untyped aspect-oriented programs. In

Cardelli [30], pages 54-73.

[76] Shmuel Katz and Yossi Gil. Aspects and superimpositions. In Int'l Workshop on Aspect-Oriented Pro­

gramming (ECOOP 1999), Lisbon, June 1999. Available from http://trese.cs.utwente.nl/aop-ecoop99/

papers/katz.pdf on July 17,2005. 310

[77] Mik A. Kersten and Gale C. Murphy. Atlas: A case-study in building a web-based learning environment

using aspect-oriented programming. In Herman [18], pages 340-352.

[78] Gregor Kiczales. The fun has just begun. AOSD'03 Keynote Address, available from http://www.cs.ubc.

ca/~gregor on July 17, 2005, March 2003.

[79] Gregor Kiczales, editor. Proc. of the 1st international conference on Aspect-oriented software development,

Enschede, the Netherlands, 2002. ACM.

[80] Gregor Kiczales and Mira Mezini. Aspect-oriented programming and modular reasoning. In ICSE '05 [3],

pages 49-58.

[81] Gregor Kiczales, John Lamping, Anurag Menhdhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier,

and John Irwin. Aspect-oriented programming. In Mehmet Akçit and Satoshi Matsuoka, editors, ECOOP

'97 — Object-Oriented Programming 11th European Conference, volume 1241 of Lecture Notes in Comp.

Sci., pages 220-242, Jyvaskyla, Finland, 1997. Springer-Verlag.

[82] Gregor Kiczales, Erik Hilsdale, Jim Hugunin, Mik Kersten, Jeffrey Palm, and William Griswold. Getting

started with AspectJ. Comm. of the ACM, 44(10):59-65, October 2001.

[83] Gregor Kiczales, Erik Hilsdale, Jim Hugunin, Mik Kersten, Jeffrey Palm, and William G. Griswold. An

overview of AspectJ. In J. Lindskov Knudsen, editor, ECOOP '01 — Object-Oriented Programming 15th

European Conference, Budapest Hungary, volume 2072 of Lecture Notes in Comp. Sci., pages 327-353,

Budapest, Hungary, 2001. Springer-Verlag.

[84] Ivan Kiselev. Aspect-Oriented Programming with AspectJ. Sams Publishing, Indianapolis, 2003.

[85] Shriram Krishnamurthi, Kathleen Fisler, and Micahel Greenberg. Verifying aspect advice modularly. In

Dwyer [55], pages 137-146.

[86] Ramanivas Laddad. AspectJ in Action. Manning Publications Co., Grennwich, Conn., 2003.

[87] Donal Lafferty and Vinny Cahill. Language-independent aspect-oriented programming. In Proceedings of

the 18th ACM SIGPLAN conference on Object-oriented programing, systems, languages, and applications,

pages 1-12, Anaheim, California, USA, 2003. ACM Press.

[88[ Patrick Lam and Martin Rinard. A type system and analysis for the automatic extraction and enforcement

of design information. In Cardelli [30], pages 273-302.

[89] Ralf Lâmmel. A semantical approach to method-call interception. In Kiczales [79], pages 41-55. 311

[90] Gary T. Leavens and Albert L. Baker. Enhancing the pre- and postcondition technique for more expressive

specifications. In Jeannette M. Wing, Jim Woodcock, and Jim Davies, editors, FM'99 — Formal Methods:

World Congress on Formal Methods in the Development of Computing Systems, Toulouse, France, Septem­

ber 1999, Proceedings, volume 1709 of Lecture Notes in Comp. Sci., pages 1087-1106. Springer-Verlag,

1999.

[91] Gary T. Leavens and Krishna Kishore Dhara. Concepts of behavioral subtyping and a sketch of their

extension to component-based systems. In Gary T. Leavens and Murali Sitaraman, editors, Foundations

of Component-Based Systems, chapter 6, pages 113-135. Cambridge University Press, 2000.

[92] Gary T. Leavens and William E. Weihl. Reasoning about object-oriented programs that use subtypes

(extended abstract). In OOPSLA/ECOOP '90: Proceedings of the European conference on object-oriented

programming on Object-oriented programming systems, languages, and applications, pages 212-223,

Ottawa, Canada, 1990. ACM Press.

[93] Gary T. Leavens, Albert L. Baker, and Clyde Ruby. Preliminary design of JML: A behavioral interface

specification language for Java. Technical Report 98-06y, Iowa State University, Department of Computer

Science, 2004.

[94] Gary T. Leavens, Erik Poll, Curtis Clifton, Yoonsik Cheon, Clyde Ruby, David R. Cok, and Joseph Kiniry.

JML reference manual. Department of Computer Science, Iowa State University. Available from www.

jmlspecs.org on July 17, 2005, December 2004.

[95] Gary T. Leavens, Yoonsik Cheon, Curtis Clifton, Clyde Ruby, and David R. Cok. How the design of

JML accommodates both runtime assertion checking and formal verification. Science of Computer

Programming, 55(l-3):185-208,2005.

[96] K. Rustan M. Leino. Toward Reliable Modular Programs. PhD thesis, California Institute of Technology,

1995. Available as Technical Report Caltech-CS-TR-95-03.

[97] K. Rustan M. Leino. Data groups: Specifying the modification of extended state. In Proc. of the 13th an­

nual ACM SIGPLAN Conf on Object-oriented programming, systems, languages, and applications, pages

144-153, Vancouver, BC, Canada, 1998. ACM.

[98] K. Rustan M. Leino and Peter Millier. Object invariants in dynamic contexts. In Odersky [124], pages

491-516. 312

[99] K. Rustan M. Leino and Greg Nelson. Data abstraction and . ACM Trans, on Prog.

Lang, and Systems, 24(5):491-553, September 2002.

[100] K. Rustan M. Leino, Arnd Poetzsch-Heffter, and Yunhong Zhou. Using data groups to specify and check

side effects. In Proceedings of the ACM SIGPLAN 2002 Conference on Programming Language Design

and Implementation, pages 246-257, Berlin, Germany, 2002. ACM Press.

[101] Karl Lieberherr, Doug Orleans, and Johan Ovlinger. Aspect-oriented programming with adaptive methods.

Comm. of the ACM, 44(10)=39-41, 2001.

[102] Karl Lieberherr, David H. Lorenz, and Johan Ovlinger. Aspectual collaborations: Combining modules

and aspects. The Computer Journal, 46(5):542-565,2003.

[103] Barbara Liskov. Data abstraction and hierarchy. ACM SIGPLAN Notices, 23(5): 17-34, May 1988. Revised

version of the keynote address given at OOPSLA '87.

[104] Barbara Liskov and John Guttag. Abstraction and Specification in Program Development. MIT Press,

Cambridge, Mass., 1986.

[105[ Barbara Liskov and Jeannette Wing. A behavioral notion of subtyping. Trans, on Prog. Lang, and Sys., 16

(6):1811—1841,1994.

[106] Vincent Massol and Timothy M. O'Brien. Maven: A Developer's Notebook. O'Reilly, Sebastopol, CA, 2005.

[107] Hidehiko Masuhara and Kazunori Kawauchi. Dataflow pointcut in aspect-oriented programming.

In Programming Languages and Systems: First Asian Symposium, APLAS 2003, volume 2895 of Lecture

Notes in Comp. Sci., pages 105-121, Taipei, Taiwan, November 2003. Springer-Verlag.

[108] Hidehiko Masuhara and Gregar Kiczales. Modeling crosscutting in aspect-oriented mechanisms. In

Cardelli [30], pages 2-28.

[109] . Object-oriented . Prentice Hall, 1988.

[110] Bertrand Meyer. Eiffel: The Language. Object-Oriented Series. Prentice Hall, New York, NY, 1992.

[1111 Bertrand Meyer. Object-oriented Software Construction. Prentice Hall, second edition, 1997.

[112] Mira Mezini and Klaus Ostermann. Integrating independent components with on-demand remodular-

ization. In OOPSLA '02 [4], pages 52-67. 313

[113] Mira Mezini and Klaus Ostermann. Variability management with function oriented programming and

aspects. In Dwyer [55], pages 137-146.

[114] Todd Millstein and Craig Chambers. Modular statically typed multimethods. Information and Compu­

tation, 175(11:76-118, 2002.

[115] Robin Milner. The polyadic ^-calculus: a tutorial. Technical Report ECS-LFCS-91-180, Laboratory

for Foundations of Computer Science, Department of Computer Science, University of Edinburgh,

October 1991. Proceedings of the International Summer School on Logic and Algebra of Specification,

Marktoberdorf, August 1991.

[116] Peter Millier. Modular Specification and Verification of Object-Oriented Programs, volume 2262.

Springer-Verlag, 2002. The author's Ph.D. Thesis.

[117] Peter Millier and Arnd Poetzsch-Heffter. Universes: A type system for alias and dependency control.

Technical Report 279, Fernuniversitat Hagen, 2001.

[118] Peter Millier, Arnd Poetzsch-Heffter, and Gary T. Leavens. Modular specification of frame properties in

JML. Concurrency, Computation Practice and Experience., 15:117-154,2003.

[119] Andrew Myers and Barbara Liskov. JFlow: Practical mostly-static information flow control. In Proc. of the

26th ACM symposium on Principles of programming languages, pages 226-241, San Diego, California,

USA, 1998. ACM Press.

[120] Nanning Project. Nanning Java aspects AOP framework, http://nanning.codehaus.org/project-info.html,

valid July 17, 2005.

[121] James Noble, Jan Vitek, and John Potter. Flexible alias protection. In Eric Jul, editor, ECOOP '98 —

Object-Oriented Programming 12th European Conference, volume 1445 of Lecture Notes in Comp. Sci.,

pages 158-185, Brussels, Belgium, 1998. Springer-Verlag.

[122] Nathaniel Nystrom, Michael R. Clarkson, and Andrew C. Myers. Polyglot: An extensible compiler

framework for java. In Proceedings of CC 2003:12'th International Conference on Compiler Construc­

tion. Springer-Verlag, 2003.

[123] ObjectWeb Consortium. Java aspect components, http://jac.objectweb.org/, valid July 17,2005.

[124] Martin Odersky, editor. ECOOP '04 - Object-Oriented Programming European Conference, volume 3086

of Lecture Notes in Comp. Sci., Oslo, Norway, 2004. Springer-Verlag. 314

[125] Martin Odersky, Vincent Cremet, Christine Rôckl, and Matthias Zenger. A nominal theory of objects with

dependent types. In Cardelli [30], pages 201-224.

[126] Peter O'Hearn and David Pym. The logic of bunched implication. Bulletin of Symbolic Logic, 5(2):

215-244,1999.

[127] Peter O'Hearn, John Reynolds, and Hongseok Yang. Local reasoning about programs that alter data

structures. In Proceedings of CSL'01, volume 2142 of Lecture Notes in Computer Science, pages 1-19.

Springer-Verlag, 2001.

[128] Doug Orleans. Incremental programming with extensible decisions. In Kiczales [79], pages 56-64.

[129] Harold Ossher and Peri Tarr. Using multidimensional separation of concerns to (re) shape evolving

software. Comm. of the ACM, 44 (10):43-50,2001.

[130] Johan Ovlinger. Modular Programming with Aspectual Collaborations. PhD thesis, Northeastern Univer­

sity, 2003.

[131] Matthew Parkinson and Gavin Bierman. Separation logic and abstraction. In POPL '05 [5],

[132] D. L. Parnas. On the criteria to be used in decomposing systems into modules. Comm. of the ACM, 15

(12):1053-1058,1972.

[133] D. L. Parnas. Software engineering or methods for the multi-person construction of multi-version

programs. In Clemens E. Hackl, editor, Programming Methodology, 4th Informatik Symposium, IBM

Germany, Wildbad, 25-27September, 1974, volume 23, pages 225-235. Springer-Verlag, 1975.

[134] Frank Pfenning and Carsten Schiirmann. System description: Twelf—a meta-logical framework for

deductive systems. In H. Ganzinger, editor, Proc. of the 16th Intl. Conf. on Automated Deduction (CADE-

16), volume 1632 of Lecture Notes in Artificial Intelligence, pages 202-206, Berlin, Heidelberg, New York,

July 1999. Springer-Verlag.

[1351 Roman Pichler, Klaus Ostermann, and Mira Mezini. On aspectualizing component models. Softw. Pract.

Exper., 33(10):957-974,2003.

[136] Benjamin C. Pierce and David N. Turner. Simple type-theoretic foundations for object-oriented program­

ming. Journal of Functional Programming, 4(2):207-248, April 1994. A preliminary version appeared in

POPL 1993. 315

[137] Gordon Plotkin. A structural approach to operational semantics. Technical Report DAIMIFN-19, Aarhus

University, 1981.

[138] Andrei Popovici, Gustavo Alonso, and Thomas Gross. Just-in-time aspects: efficient dynamic weaving for

Java. In AOSD '03 [6], pages 100-109.

[139] François Pottier and Vincent Simonet. Information flow inference for ML. ACM Trans, on Prog. Lang,

and Systems, 25(1):117-158, Jan 2003.

[140] Arun D. Raghavan and Gary T. Leavens. Desugaring JML method specifications. Technical Report 00-03e,

Iowa State University, Department of Computer Science, May 2005.

[141] Hridesh Rajan and Kevin J. Sullivan. Classpects: unifying aspect- and object-oriented language design.

In ICSE '05 [3], pages 59-68.

[142] Awais Rashid and Ruzanna Chitchyan. Persistence as an aspect. In AOSD '03 [6], pages 120-129.

[143] John Reynolds. Intuitionistic reasoning about shared mutable . In Millennial Perspectives

in Computer Science, Proceedings of the 1999 Oxford- Symposium in Honor of Sir Tony Hoare.

Palgrave, 2000.

[144] John C. Reynolds. Separation logic: A logic for shared mutable data structures. In Proceedings of the

Seventeenth Annual IEEE Symposium on Logic in Computer Science. IEEE Computer Society Press, 2002.

[145] John C. Reynolds. Types, abstraction and parametric polymorphism. In Proc. IFIP Congress '83, Paris,

September 1983.

[146] Martin Rinard, Alexandur Salcianu, and Suhabe Bugrara. A classification system and analysis for aspect-

oriented programs. In Dwyer [55], pages 147-158.

[147] Daniel Sabbah. Aspects—from promise to reality. Keynote address at AOSD 2004, available from

http://aosd.net/2004/archive/AOSD-FromPromiseToReality.ppt on July 17,2005, March 2004.

1148] Marcelo Sihman and Shinuel Katz. Superimpositions and aspect-oriented programming. The Computer

Journal, 46(5), 2003.

[149] Olaf Spinczyk, Andreas Gal, and Wolfgang Schrôder-Preikschat. AspectC++: an aspect-oriented extension

to the C++ programming language. In Proceedings of the Fortieth International Conference on Tools

Pacific, pages 53-60. Australian Computer Society, Inc., 2002. ISBN 0-909925-88-7. 316

[150] Stanley M. Sutton, Jr and Isabelle Rouvellou. Modeling of software concerns in Cosmos. In Kiczales [79].

[151] Davy Suvée, Wim Vanderperren, and Viviane Jonckers. JAsCo: an aspect-oriented approach tailored for

component based software development. In AOSD '03 [6], pages 21-29.

[152] Clemens Szyperski, Domiinik Gruntz, and Stephan Murer. Component Software: Beyond Object-Oriented

Programming. ACM Press and Addison-Wesley, second edition, 2002.

[153] Peri L. Tarr, Harold Ossher, William H. Harrison, and Stanley M. Sutton Jr. N degrees of separation:

Multi-dimensional separation of concerns. In Proc. of the 21 th international conference on Software

engineering, pages 107-119, Los Angeles, California, USA, 1999. ACM Press.

[154] David B. Tucker and Shriram Krishnamurthi. Pointcuts and advice in higher-order languages. In AOSD

'03 [6], pages 158-167.

[155] Raja Vallée-Rai, Etienne Gagnon, Laurie J. Hendren, Patrick Lam, Patrice Pominville, and Vijay Sundare-

san. Optimizing Java bytecode using the Soot framework: Is it feasible? In Compiler Construction, 9th

International Conference (CC2000), pages 18-34, London, 2000. Springer-Verlag.

[156] David Walker, Steve Zdancewic, and Jay Ligatti. A theory of aspects. In Proceedings of the eighth ACM

SIGPLAN international conference on Functional programming, pages 127-139, Uppsala, Sweden, 2003.

ACM Press.

[157] Mitchell Wand, Gregor Kiczales, and Chris Dutchyn. A semantics for advice and dynamic join points in

aspect-oriented programming. Trans, on Prog. Lang, and Sys., 26(5):890-910, 2004.

[158] Alan Wills. Capsules and types in Fresco: Program validation in Smalltalk. In P America, editor, ECOOP

'91 — Object-Oriented Programming 5th European Conference, volume 512 of Lecture Notes in Comp.

Sci., pages 59-76, Geneva, Switzerland, 1991. Springer-Verlag.

[159] Jeannette M. Wing. Writing Larch interface language specifications. ACM Trans, on Prog. Lang, and

Systems, 9(l):l-24, January 1987.

[160] Andrew K. Wright and Matthias Felleisen. A syntactic approach to type soundness. Information and

Computation, 115(l):38-94,1994.

[161] Matthias Zenger and Martin Odersky. Independently extensible solutions to the expression problem. In

FOOL-12 [2], 317

1162] Jianjun Zhao and Martin C. Rinard. Pipa: A behavioral interface specification language for AspectJ.

In Proc. Fundamental Approaches to Software Engineering, volume 2621 of Lecture Notes in Comp. Sci.,

Warsaw, Poland, 2003. Springer-Verlag.