Universidade Federal de Pernambuco Centro de Inform¶atica · refactoring e consiste em mudan»cas...

328
Universidade Federal de Pernambuco Centro de Inform´atica P´os-gradua¸c˜ ao em Ciˆ encia da Computa¸c˜ ao Tese de Doutorado Refactorings as Formal Refinements por M´arcio Lopes Corn´ elio Recife, junho 2004

Transcript of Universidade Federal de Pernambuco Centro de Inform¶atica · refactoring e consiste em mudan»cas...

Universidade Federal de Pernambuco

Centro de Informatica

Pos-graduacao em Ciencia da Computacao

Tese de Doutorado

Refactorings as Formal Refinements

por

Marcio Lopes Cornelio

Recife, junho 2004

UNIVERSIDADE FEDERAL DE PERNAMBUCOCENTRO DE INFORMATICA

Tese de Doutorado

Refactorings as Formal Refinements

Marcio Lopes Cornelio

Esta tese foi apresentada a Pos-Graduacao em Ciencia

da Computacao do Centro de Informatica da Univer-

sidade Federal de Pernambuco como requisito parcial

para obtencao do grau de Doutor em Ciencia da

Computacao.

A thesis presented to the Federal University of Pernam-

buco in partial fulfillment of the requirements for the

degree of Doctor (Dr.) in Computer Science.

Orientador (Supervisor):

Profa. Dr. Ana Lucia Caneca Cavalcanti

Co-orientador (Co-supervisor):

Prof. Dr. Augusto Cesar Alves Sampaio

Recife, junho 2004

Cornélio, Márcio Lopes

Refactoring as formal refinements / Márcio Lopes Cornélio. – Recife : O Autor, 2004.

xvii, 307 p. : il., fig., tab.

Tese (doutorado) – Universidade Federal de Pernambuco. CIn. Ciência da Computação, 2004.

Inclui bibliografia e apêndices.

1. Engenharia de software. 2. Software –Transformação de programas. 3. Programação orientada a objetos – Reestruturação. 4. Refinamento formal (Programação orientada a objetos) – Técnica. I. Título.

004.432.4 CDU(2.ed.) UFPE 005.117 CDD(21.ed.) BC2004-481

Acknowledgments

I would like to thank my supervisor, Ana Cavalcanti, for her teaching, advice and guidance alongthese years, and for providing constant direction. She has been a source of encouragement andinspiration.

I am also indebted to my co-supervisor, Augusto Sampaio, for his guidance, valuable discussionsand suggestions, and for his refined perception. He has also been a source of inspiration.

I am thankful to my thesis committee that has contributed with comments, and correctionswhich helped me to improve this thesis. Special thanks to Paulo Borba for valuable suggestionsand insightful comments.

Many thanks to Leila Silva for voluntarily and patiently proof-reading parts of this thesis, andfor discussions about this work. Several improvements of it are due to her comments. Thanks toAlexandre Mota and Luıs Carlos Menezes for useful discussions on program transformation duringthe development of this work.

I thank my colleagues of the Department of Computing Systems of the State University ofPernambuco for encouragement during the final stage of this work.

Thanks to the Centre of Informatics staff for their support in difficult moments. Thanks to JoseRoberto Pereira, Carlos Melo, Rodrigo Santana, and Mario Sergio. A special thanks to MarliceNovais, for her friendship and support.

My parents, my sister and my brothers have provided continued support and stimulus, whichcan never be fully acknowledged. I cannot thank them enough, but I will start dedicating this workto them.

I am deeply grateful to Roxana de Siqueira for her encouragement, patience, and love alongthese years.

I am most fortunate to have so many friends so that it is difficult to name them all in this space.Their friendship, help and encouragement in all worrisome moments have been a distinguished asset.

Most importantly, I thank God for hidden care and for my salvation. Fundamentally, nothingelse really matters. Glory and praise unto the Lord.

The work described in this thesis was financially supported by the Brazilian government throughCapes, one of the Brazilian agencies that afford for postgraduate studies in Brazil.

Resumo

A reestruturacao de programas no contexto da orientacao a objeto e tambem conhecida comorefactoring e consiste em mudancas na estrutura interna de um software, sem modificar seu com-portamento externo, a fim de melhorar sua legibilidade e torna-lo mais facil de passar por futurasmudancas. Na pratica, refactoring baseia-se em compilacao e testes para assegurar a preservacaodo comportamento.

Trabalhos como os de Opdyke e Roberts foram realizados com vistas a formalizacao de refac-torings por meio da identificacao de condicoes que devem ser satisfeitas para assegurar que umamudanca num programa preserva o comportamento do mesmo. As condicoes, geralmente escritasna linguagem do calculo de predicados, sao introduzidas como pre e pos-condicoes dos refactor-ings. Outras abordagens para a prova de preservacao do comportamento de refactorings usamformalismos como analise conceitual e reescritura de grafos. Contudo, nao ha tecnica algebricaque apresente refactorings como transformacoes que preservam o comportamento, com prova destefato.

Nossa principal contribuicao constitui-se na apresentacao de refactorings como transformacoesde programas escritos em rool (Refinement object-oriented Language), uma linguagem baseadaem Java, com classes, controle de visibilidade, ligacao dinamica, e recursao. A linguagem rool

permite que raciocinemos sobre programas orientados a objetos e especificacoes, pois a mesma uneestas construcoes como no calculo de refinamentos de Morgan. A semantica de rool e baseada emweakest preconditions. Um conjunto de leis de programacao esta disponıvel tanto para os comandosimperativos de rool quanto para construtores relacionados a orientacao a objetos. A prova, nasemantica de rool, de que tais leis sao corretas, e tambem uma contribuicao do presente trabalho.

Apresentamos refactorings como regras algebricas de refinamento envolvendo programas. Aprova da preservacao do comportamento e realizada pela aplicacao de leis de programacao a umlado da regra a fim de obtermos o lado oposto. Nos generalizamos a tecnica padrao de refinamentode dados a fim de lidar com hierarquia de classes.

Neste trabalho tambem apresentamos como obter um sistema estruturado segundo um padraode projeto, por meio da aplicacao de regras de refactoring. Padroes de projeto constituem-senum objetivo natural para a realizacao de transformacoes por meio da aplicacao de refactorings.Trabalhos presentes na literatura sobre padroes de projeto que propoem a formalizacao dos mesmos,em geral, concentram-se em suas descricoes formais, nao na transformacao de um sistema com vistasa estrutura-lo de acordo com padroes de projeto. Tambem apresentamos a transformacao de umaaplicacao monolıtica para uma aplicacao estruturada segundo um padrao arquitetural.

Abstract

Program restructuring in the context of object-oriented programming is known as refactoring. Thisconsists of changes made to the internal structure of software in order to improve its legibility andmake it easier to modify without changing its external behaviour. In practice, refactoring usuallyrelies on compilation and tests in order to guarantee behaviour preservation.

Works like those by Opdyke and Roberts have already been done in the direction of refactoringformalisation by means of the identification of conditions that must be satisfied to guarantee thata change to a program is behaviour preserving. The conditions, which are usually written in thepredicate calculus, are introduced as pre- and postconditions of the refactorings. Other approachesfor the proof of refactoring behaviour preservation use formalisms such as concept analysis andgraph rewriting. However, there is no algebraic technique that presents refactorings as behaviourpreserving transformations, with proofs carried out. This avoids changes of notation and facilitatesmechanisation.

Our contribution is to present refactorings as transformations of programs written in the lan-guage rool (Refinement object-oriented Language), which is a Java-like imperative language withclasses, visibility control for attributes, dynamic binding, and recursion. It allows reasoning aboutobject-oriented programs and specifications, as both kinds of constructs are mixed as in Morgan’srefinement calculus. The semantics of rool, as usual for refinement calculi, is based on weakestpreconditions. A set of programming laws is available for the imperative constructs of rool aswell as for its object-oriented features. The correctness of these laws, which is also a contributionof the present work, is proved against the semantics of rool.

We present refactorings as algebraic refinement rules involving program terms. The proof thatthese rules are behaviour preserving is accomplished by the application of the programming lawsof one of the sides of the rule to obtain the other side. The proofs of some refactoring rules alsoinvolve data refinement of classes. We generalise the standard data refinement technique fromsingle modules (classes) to class hierarchies.

Design patterns arise as a natural objective for refactoring a system. The literature on designpatterns already presents works that propose the formalisation of design patterns. They usuallyconcentrate on the formal description of patterns, not on the transformation of a system with theintention of obtaining a final system structure according to a design pattern. In this work, wealso present how to obtain a system that is in accordance with design patterns by the applicationof refactoring rules proved to be behaviour preserving. We also present the transformation of amonolithic application to a well-structured one according to an architectural pattern.

Contents

1 Introduction 1

1.1 Refactoring and Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Formal Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Refinement Calculi and Object-Orientation . . . . . . . . . . . . . . . . . . . . . . . 41.4 Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.5 Thesis Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2 Refactoring—State of the Art 9

2.1 Program Restructuring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.2 Refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.2.1 Formalisms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132.2.2 Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.2.3 Refactoring Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.3 Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.3.1 Formalization of Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.4 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3 ROOL and Laws 19

3.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.2 Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.2.1 Typing environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233.2.2 Typing Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3.3 Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.3.1 Environments and states . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.3.2 Extended typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.3.3 Commands and parameterised commands . . . . . . . . . . . . . . . . . . . . 293.3.4 Programs and method calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.4 Refinement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323.5 Laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.5.1 Simulation Laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

x CONTENTS

3.5.2 Laws of Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.5.3 Laws of Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.6 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

4 Compositional Refactorings 41

4.1 Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424.2 Refactoring Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

4.2.1 Extract and Inline Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434.2.2 Move Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464.2.3 Move Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.2.4 Pull Up and Push Down Method . . . . . . . . . . . . . . . . . . . . . . . . . 614.2.5 Replace Parameter with Method . . . . . . . . . . . . . . . . . . . . . . . . . 664.2.6 Extract Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

4.3 New refactorings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754.3.1 Clientship Elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754.3.2 Delegation Elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

4.4 Further Compositional Refactoring Rules . . . . . . . . . . . . . . . . . . . . . . . . 814.4.1 Inline Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824.4.2 Self Encapsulate Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 834.4.3 Decompose Conditionals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.4.4 Introduce Explaining Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . 864.4.5 Consolidate Conditional Expression . . . . . . . . . . . . . . . . . . . . . . . 864.4.6 Consolidate Duplicate Conditional Fragments . . . . . . . . . . . . . . . . . . 874.4.7 Substitute Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

4.5 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

5 Contextual Refactorings 91

5.1 Refactoring Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915.1.1 Changing clientship between classes in a hierarchy . . . . . . . . . . . . . . . 925.1.2 Pull Up and Push Down Field . . . . . . . . . . . . . . . . . . . . . . . . . . 965.1.3 Extract Superclass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015.1.4 Collapse Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055.1.5 Rename Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145.1.6 Parameterise Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195.1.7 Encapsulate Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

5.2 Further Contextual Refactoring Rules . . . . . . . . . . . . . . . . . . . . . . . . . . 1285.2.1 Add and Remove Parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . 1285.2.2 Separate Query from Modifier . . . . . . . . . . . . . . . . . . . . . . . . . . . 1285.2.3 Encapsulate Downcast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

CONTENTS xi

5.3 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

6 Refactoring towards Patterns 133

6.1 The Facade Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

6.2 A Layered Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

6.2.1 A New Refactoring Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

6.2.2 The Architectural Pattern Derivation . . . . . . . . . . . . . . . . . . . . . . 139

6.3 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

7 Conclusions 147

7.1 Related Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

7.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

A Derivation of Compositional Refactoring Rules 155

A.1 Delegation Elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

A.1.1 inline delegate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

A.1.2 (undo) inline delegate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

A.2 Inline Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159

A.3 Self Encapsulate Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

A.4 Decompose Conditionals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

A.5 Introduce Explaining Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

A.6 Consolidate Conditional Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

A.7 Consolidate Duplicate Conditional Fragments . . . . . . . . . . . . . . . . . . . . . . 169

A.8 Substitute Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

B Derivation of Contextual Refactoring Rules 171

B.1 Add/Remove Parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

B.2 Separate Query From Modifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

B.3 Encapsulate Downcast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

C Lemmas for Program Derivation 187

D Laws of Commands 199

D.1 Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

D.2 Conditional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

D.3 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

D.4 Sequential Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

D.5 Local Variable Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202

D.6 Angelic Variable Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203

D.7 Additional Laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

xii CONTENTS

D.7.1 Alternation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

D.7.2 Guards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

D.7.3 Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206

D.7.4 Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

D.7.5 Local Variable Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208

D.7.6 Variable blocks and parameterised commands . . . . . . . . . . . . . . . . . . 208

D.8 Laws from Morgan’s work [64] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

D.9 Data Refinement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

E Laws of Classes 213

E.1 Normal Form Laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

E.1.1 Class Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

E.1.2 Attribute Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214

E.1.3 Method Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

E.1.4 Parameter Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218

E.1.5 Method Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

E.1.6 Casts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

E.1.7 Commands and expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

E.2 Further object-oriented programming laws . . . . . . . . . . . . . . . . . . . . . . . . 221

E.2.1 Laws for new . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221

E.2.2 Laws for changing a superclass . . . . . . . . . . . . . . . . . . . . . . . . . . 223

E.2.3 Class invariant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

E.3 Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

F Proofs of Laws of Commands 227

F.1 Proofs of laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

F.1.1 Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

F.1.2 Conditional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229

F.1.3 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233

F.1.4 Sequential Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234

F.1.5 Local Variable Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237

F.1.6 Angelic Variable Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240

F.2 Proof of additional command laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244

G Proof of Laws of Classes 265

G.1 Normal Form Laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265

G.1.1 Class Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265

G.1.2 Attribute Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266

G.1.3 Method Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271

CONTENTS xiii

G.1.4 Parameter type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278G.1.5 Method calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280G.1.6 Casts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282G.1.7 Commands and expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283

G.2 Further object-oriented programming laws . . . . . . . . . . . . . . . . . . . . . . . . 286G.2.1 Changing a superclass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289G.2.2 Class invariant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290

H Typing Rules 293

xiv CONTENTS

List of Figures

1.1 Class Person before refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Class Person after refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Formalisation of Refactorings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3.1 A class in rool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

6.1 The system before refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1346.2 The four-layer architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1376.3 The class Application in the end of Stage 1 . . . . . . . . . . . . . . . . . . . . . . . 1416.4 The class Application in the end of Stage 2 . . . . . . . . . . . . . . . . . . . . . . . 1426.5 The class BusinessCollection in the end of Stage 2 . . . . . . . . . . . . . . . . . . . 1436.6 Class BusinessCollection in the end of Stage 3 . . . . . . . . . . . . . . . . . . . . . 1446.7 Classes RepositoryClass and RepositoryClassRef . . . . . . . . . . . . . . . . . . . . 144

A.1 Law 〈inline delegate〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156A.2 Law 〈(undo)inline delegate〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

xvi LIST OF FIGURES

List of Tables

3.1 Grammar for expressions and predicates . . . . . . . . . . . . . . . . . . . . . . . . . 203.2 Grammar for commands and parameterised commands . . . . . . . . . . . . . . . . . 213.3 Programs in rool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223.4 Typing of Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.5 Typing of Parameterised Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.6 Typing of Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.7 Syntactic Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293.8 Semantics of some commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

H.1 Typing of Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293H.2 Typing of Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294H.3 Coercion Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294H.4 Typing of Parameterised Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . 294H.5 Typing of Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295

Chapter 1

Introduction

Changes are intrinsic to software. After a software product is delivered to a customer, new require-ments often arise. Also, the use of a software product may reveal mistakes that were not realisedduring development [48]. Sometimes, however, changes to a software do not affect its externalbehaviour. For instance, changing the name of a function, or eliminating duplicate code throughthe use of procedures, should not affect a software’s external behaviour. Indeed, such modificationschange just the internal software structure. This activity is called software restructuring [45].

Many practitioners recognise that changing an object-oriented software is easier than conven-tional software [62]. Some changes to object-oriented software can be made just by the additionof new classes, subclasses, or methods in a class. However, changing an object-oriented softwaremay require changing abstractions described by means of classes and their relationships like, forinstance, moving an attribute or a method between classes.

When a structural change is made to a class or a set of classes, changes may also be neededelsewhere in a program in order to preserve its behaviour. For example, changing a method nameimplies changing the old name of the method to the new one in all calls that occur in the program.Other changes may affect inheritance hierarchies. In object-oriented programming, behaviour pre-serving transformations are known as refactorings [69, 42].

We propose an approach to refactoring that is based on transformation rules between programswritten in an object-oriented language whose semantics has been formally described. Each ruleis described by means of a meta-program on its left-hand side and another meta-program on theright-hand side and allows us to transform a program into another. The correctness proof of theserules is based on the application of laws of programming whose soundness is proved against thelanguage’s semantics. Programming laws state properties of program constructs [46].

1.1 Refactoring and Patterns

Due to the complexity of object-oriented applications, changes must be done in a disciplined way,so that the behaviour of the program is preserved. Indeed, refactoring is defined as the “process of

2 CHAPTER 1. INTRODUCTION

class Person{private String name;private String areaCode;private String homeTelNumber;public String getName(){

return name;}public String getTelephoneNumber(){

return (”(” + areaCode + ”)” + homeTelNumber)}

}

Figure 1.1: Class Person before refactoring

changing a software system in such a way that it does not alter the external behaviour of the codeyet improves its internal structure” [42].

As an example of a possible need for code design improvement, and also for disciplined changeof program, let us consider the class Person in Figure 1.1, which embodies two different real-worldconcepts: person and telephone. It has an attribute name, which records the name of a person, andattributes areaCode and homeTelNumber, which record an area code and a home telephone number,respectively. We use the Java [1] programming language notation to describe this class.

Clearly there are two independent abstractions inside this class. In order to obtain a betterdesign, it is necessary to split the class Person, so that the concept of telephone is described in aseparate class. So, we should extract a reusable component: the class that describes telephones.This extraction requires refactoring the existing class Person. The classes that result from refactor-ing are presented in Figure 1.2. The class Person now is a client of class TelephoneNumber. Person

has an attribute of type TelephoneNumber. This attribute is used as a target of calls to methods ofTelephoneNumber.

As illustrated in our example, sometimes it is necessary to restructure a class in order to achievereuse. One reason for this is that it is difficult to determine, in an initial design, all the importantconcepts for an application and how they interrelate. Indeed, in the example we presented, twoconcepts are described in a single class. After refactoring, the opportunities for reuse increase asthe different classes can determine, for instance, new class hierarchies.

The changes in the example we presented are simple and can be done by hand. In fact, pro-grammers have been doing changes as this one for years. Nonetheless, simple transformations canbe part of a sequence of other transformations; and it is required that, afterwards, the system mustbehave as before any transformation. If the small refactorings are shown to be correct, then largechanges composed of small refactorings will also be correct.

The practical approach to refactoring usually relies on program compilation and test cycles [42].Compilation detects, for example, that a new class has the same name as an already existing class.

1.2. FORMAL METHODS 3

class Person{ class TelephoneNumber{private String name; private String areaCode;private homeTel = new TelephoneNumber(); private String homeTelNumber;public String getName(){ public String getTelephoneNumber(){

return name; return(”(” + areaCode + ”)” +} homeTelNumber);public String getTelephoneNumber(){ }

return homeTel.getTelephoneNumber(); }}

}

Figure 1.2: Class Person after refactoring

In other words, compilation is related to static analysis, including type checking. On the otherhand, it is necessary to guarantee that the behaviour of a program is not changed after refactoring.Testing is what is usually adopted.

Opdyke [69] presents seven properties based on which behaviour preservation can be assured.Six of these properties deal with well-formedness of programs. The last property is related tothe semantic equivalence of references and operations. In other words, refactorings not only mustproduce legal programs in terms of syntax and typing, but also the versions of the programs beforeand after refactoring must produce semantically equivalent references and operations, in order fora program to produce the same set of values for a given set of inputs before and after refactoring.Tokuda [86] argues that refactorings preserve the behaviour because of good engineering and notbecause of any mathematical guarantee.

1.2 Formal Methods

Formal methods are mathematical techniques for system specification, verification, and reasoning.Systems are specified using formal specification languages, which have well-founded mathematicalbasis. They include theories like first-order logic, sets, and algebra, which allow the verification ofspecification properties. The use of such languages reduces ambiguity, inconsistency, and incom-pleteness, which often arise when using informal development techniques.

Two approaches can be taken in a formal development process: one based on specificationverification, and the other one based on specification transformation. In the first approach, for agiven specification, a design or program is proposed and verified to satisfy the specification. Inthe second one, a specification is refined until a concrete design or a program is obtained. Thetransformational approach can be more effective than the verification-based one, because it seemsgenerally less difficult to develop a program and verify its correctness at the same time than toverify a program against its specification in a retrospective way [34].

The formal development process is not necessarily intrinsic to the specification language. A

4 CHAPTER 1. INTRODUCTION

system can be developed using the verification-based or using the transformational approach, oreven mixing these two approaches in spite of the language used. However, the semantic model ofa language must give support to both approaches. One of the most well-known transformationaltechniques are the refinement calculi [65, 5, 7, 66], which involve a wide spectrum language and aset of correctness preserving rules. By using these rules, we can calculate a refined program that iscorrect by construction with respect to its specification.

The language Z [79, 78] is an example of a formal specification language that can be used in adevelopment process that mixes the verification-based approach as well as the transformational one.Traditionally, a Z abstract specification is proposed for a system, then a concrete specification ispresented and verified to be correct against the abstract specification. The correctness is based onrefinement proof obligations [89]. This phase of the development process is based on specificationverification. The concrete specification of the system, however, is not executable. It is necessary totransform this concrete specification in order to obtain program code. This transformation can bedone by means of a Z refinement calculus [20], which presents a set of conversion and refinementlaws for Z.

Extensions to formal specification languages, like Z, to deal with object-oriented features wereproposed mainly in the beginning of the 1990’s. Among the Z extensions we can find Object-Z [72],and MooZ (Modular object-oriented Z ) [58, 59]. These extensions are used for the specification ofobject-oriented systems, but there is still a gap between the most concrete specification we canobtain at the end of the development and program code. The development process usually appliedin the context of object-oriented formal specification languages is based on specification verification.There is no refinement calculus defined for these languages.

1.3 Refinement Calculi and Object-Orientation

Refinement calculi have been extensively used as a formal basis for stepwise development in thecontext of imperative programming languages. Different approaches were proposed by Back [5, 7],Morgan [65, 64], and Morris [66]. Their languages are extensions of the language of guardedcommands of Dijkstra [34]; they integrate specification and executable constructs in a unifiedlanguage. This integration is the key for a stepwise development process in which a program isdeveloped through a series of transformations within a single language.

Refinement calculi are convenient for describing object-oriented developments, as we can specifyclasses at various abstraction levels. As behavioural subclassing involves intermingled programsand specifications [3], refinement calculi are a natural choice because it unifies specifications andprogram code in a single language.

Utting [87] extended a refinement calculus to support object-oriented programming. He definesa model for multiple dispatch late binding and specialises this model to deal with single dispatch.He also formalised the notion of modular reasoning in which all objects are ordered by a substitution

1.3. REFINEMENT CALCULI AND OBJECT-ORIENTATION 5

relation. In his definition, an object of a class A can be substituted for an object of class B , ifmethods of A are refined by methods of B . He separates implementations and specifications (types),and checks behavioural conformance of types to their supertypes. Data refinement is only allowedbetween the implementation and a specification of an object. Utting does not consider visibilitycontrol, and recursive method calls. Also, he does not propose object-oriented programming laws.

Mikhajlova and Sekerinski [63] define a language in which all attributes are private and methodsare public. Class constructors are concerned only with object creation and are not part of the classinterface. They also define a refinement relation between classes which is based on the algorithmicand data refinement supported by the refinement calculus. In their approach, a class C1 is refinedby a class C2 if the constructor of C2 refines that of C1, and each method of C2 refines thecorresponding method of C1. Subclassing is a syntactic relation between classes, implying just inconformance of interfaces. They allow contravariance of input parameters and covariance of outputparameters. In order to establish behavioural subclassing, they require that declaring one class asa subclass of another raises the proof obligations that class refinement holds between these classes.

Interface refinement is proposed by Mikhajlova and Sekerinski as a generalisation of class refine-ment, as it introduces a refinement relation for input and output parameters of the correspondingmethods of two classes. They also define client refinement as being of two types: implicit andexplicit. In implicit client refinement, a client class does not know that the class of which it isa client is refined, whereas in the explicit case the refinement is known. They do not presentlaws for object-oriented programming. Leino [54] has extended existing refinement calculi withobject-oriented features, but restricting inheritance and not dealing with classes and visibility.

Cavalcanti and Naumann [21, 24, 22] present a language called rool, which is a subset ofsequential Java. This language includes specification constructs from Morgan’s refinement calculus,recursive classes, visibility control, dynamic binding, and recursive methods. It has a copy semanticsrather than a reference semantics. This simplifies the semantics: rool has a predicate transformersemantics allowing us to reason about object-oriented program development and to study formalrefinement of programs. The imperative constructs of rool are based on Morgan’s refinementcalculus [64]. In particular, the syntax of commands is based on that of Dijkstra’s language ofguarded commands [34].

In the context of the refinement calculus for imperative programming, there are well establishedlaws that can assist and form a basis for formal program development [64]. Indeed, the laws forimperative programming are well known [46]. In a response to the lack of formal programming lawsfor object-oriented programming [13], Borba and Sampaio [14] present a set of basic laws for rool.These laws deal with imperative commands of rool as well as with medium-grain object-orientedconstructs. Cornelio et al. [33] address the proof of the soundness of the laws of commands ofrool. Borba et al. [16, 17] present a comprehensive set of laws for object-oriented programming.They concentrate on object-oriented features, and they show that this set of laws is sufficient totransform an arbitrary program into a normal form expressed in terms of a small subset of the

6 CHAPTER 1. INTRODUCTION

language operators. There is already a mechanisation of the normal form reduction strategy [57].These laws not only clarify aspects of the semantics, they also serve as a basis for deriving moreelaborate laws and for practical applications of program transformations like those we present inthis work. In [35, 36], these laws are used to prove rules that support compiler construction in thealgebraic style proposed by Sampaio [75].

1.4 Objectives

We propose an approach to refactoring that is based on transformation rules between meta-programs in rool [21, 22]. Each rule is described by means of a meta-program on its left-handside and another target meta-program on the right-hand side. Moreover, each rule has a set ofconditions that must be satisfied in order to allow the rule to be applied. In this way, we still haverefactorings described in the same language as the one that we use to write programs.

An object-oriented language with a formal semantics is essential for the proof that programtransformations are semantics preserving. We adopt the notion that a behaviour-preserving trans-formation is a semantics-preserving transformation. Behaviour preservation implies that a programbehaves the same before and after a transformation. The behaviour of a program, what is expectedfrom a program execution, is expressed as the meaning of a program. The notion of behaviourpreservation we adopt in this work is related to sequential programs that do not involve real-timerequirements, and are not used as components nor are part of a framework as changing them mayimpact clients.

Having a set of basic laws for object-oriented programming is crucial for the derivation of moreelaborate programming laws that can be useful for the practical development of programs. Ourmain objective in this work is to formalise and prove refactoring practices as those presented byFowler [42]. Other refactoring rules also arise from the process of formalisation of already registeredrefactoring rules.

The laws of object-oriented programming proposed by Borba et al. [16, 17, 14, 15] for commandand classes form a basis for the proofs of the program transformations described by refactorings.A program that appears on the left-hand side is, by means of law applications, transformed intoanother program, the one that appears on the right-hand side, provided some side-conditions aresatisfied. We prove the soundness of the laws against the weakest preconditions semantics ofrool [21, 22].

Also, data refinement is required for the derivation of refactoring rules. We propose a law forchange of data representation inside a class, which is similar to the traditional data refinement lawfor a single program module [64]. Besides that, we use a law for change of data representation inclass hierarchies: a generalisation of traditional data refinement laws.

Refactoring an object-oriented system has the purpose of obtaining a better design. Further-more, refactoring may have the objective of obtaining a system that is structured in accordance

1.4. OBJECTIVES 7

Semantics

Laws of Commands Laws of Classes Data Refinement Laws

Design Patterns

Refactoring Rules

Figure 1.3: Formalisation of Refactorings

with a design pattern [30, 40, 43]. Design patterns capture knowledge of software experts: a pat-tern is a solution to a problem in a given context. The design embodied in a pattern may not berealised in a software because, for instance, a designer is unfamiliar with design patterns. In thiscase, refactoring may be necessary; code that conforms to design patterns can be obtained by theapplication of several refactorings.

We explore the application of refactoring rules for obtaining programs that are in accordancewith a design pattern [43]. Differently from refactoring rules, design patterns are not presentedas rules, but as development strategies. The reason is that a program must match the left-handside of a rule and satisfy its side-conditions in order for the rule application to be possible. Designpatterns, however, are a possible goal of object-oriented refactoring; it is difficult to identify theclass of programs that can or should be redesigned. Here, we apply refactorings to a small particularsystem, which we use as a case study, in order to obtain a final system according to a design pattern.We also deal with the transformation of a poorly-structured system into one that is in accordancewith an architectural pattern.

We summarise the strategy we follow for the formal derivation of refactoring rules in Figure 1.3.Some of these rules were initially presented in [32]. We use programming laws that deal withcommand, classes and also laws for data refinement in order to derive refactoring rules. Based onrefactoring rules and, eventually in data refinement, we transform a system into one structuredaccording to a design pattern.

In summary, the objectives of this thesis are as follows.

1. Formalisation of refactorings already available in the literature;

2. Identification of new refactoring rules as a result of the formalisation process;

3. Proof of the soundness of the refactoring rules by the application of programming laws thatdeal with commands, object-oriented constructs like classes and methods, and simulation;

8 CHAPTER 1. INTRODUCTION

4. Exemplification of the introduction of design and architectural patterns from particular sys-tems by applying refactoring rules and laws of programming;

5. Proof of the programming laws of rool that deal with commands of the language;

6. Proof of the programming laws that deal with object-oriented features.

The study of the data refinement laws is left as future work. The soundness of simulation,however, has already been established in [23].

1.5 Thesis Overview

In the next chapter we present a survey of previous work on refactoring. We present the languagerool and its semantics in Chapter 3, where we also present some laws of rool.

We define that refactorings which, when a applied to a class, for instance, do not change otherparts of a system to be compositional. They do not affect the context in which a class that is beingrefactored appears. We present these refactorings in Chapter 4 along with their proofs.

In Chapter 5 we present refactorings that might change the context in which the class that isbeing refactored appears. These refactorings are said to be contextual, and their proofs are usuallyin the form of development strategies.

The application of refactoring rules and other object-oriented programming laws to a system,with the aim of obtaining a design in accordance with a well-known pattern, is exemplified inChapter 6. In this chapter we also present an example of a poorly structured system that istransformed into a well structured one which follows a layered architectural pattern.

Finally, in Chapter 7 we summarise the contributions of this research and describe future work.

Chapter 2

Refactoring—State of the Art

In this chapter we present a survey of works related to refactoring. First, we present works onprogram restructuring in contexts other than object-oriented programming. Then, we presentrelated works on refactoring. Finally, we present works on design patterns.

2.1 Program Restructuring

In [45], Griswold investigated meaning-preserving transformations to restructure programs writtenin a block-structured programming language. The language he analysed in his research was Scheme.Many transformations are well-known compiler optimisations or their inverses, like extracting orinlining a function. However, his transformations have a different aim from compiler optimisations;his transformations concern program restructuring for aiding maintenance, but are, in fact, similarto local compiler optimisations. In order to ensure that the transformations are meaning preserving,he uses Program Dependence Graphs to reason about the correctness of transformation rules. Hisresearch focused on transformation rules of the syntactic constructs of a block-structured language,so these transformations do not take into account inheritance matters. He recognises that classhierarchies complicate transformations and make analysis and transformations more complex. Hediscusses how his approach might be applied to object-oriented systems, for dealing, for instance,with method extraction.

The Demeter system provides a high-level interface to class-based object-oriented systems.The well-known Law of Demeter originated from work with this system. The goal of the law isorganise and reduce the behavioural dependence between classes to make sure that methods havelimited knowledge of an object model [55]. A proof that any object-oriented program written ina bad style can be systematically transformed into a program that obeys the Law of Demeterwas presented [56]. An algorithm that transforms any object-oriented program into an equivalentprogram which satisfies the law is available. The algorithm uses a data structure known as theclass dictionary graph. The vertices of the graph are classes; construction vertices are instantiable,whereas alternation vertices denoted abstract classes. Two types of edges represent the relationship

10 CHAPTER 2. REFACTORING—STATE OF THE ART

between two vertices. Alternation edges represent inheritance relationship, whereas constructionedges represent part-of relationship “uses” and “knows”.

Bergstein [9] presents a small set of primitive object-preserving class transformations, that is,the reorganisation of a class hierarchy does not change the set of objects which the classes defineand programs after a transformation accept the same inputs and produce the same outputs asbefore a transformation. These primitive transformations help form a theoretical basis for classorganisation. The set of transformation is shown to be correct. Bergstein’s rule for abstractingcommon parts in a hierarchy can be seen as a derived rule in the framework presented in [17, 16].Bergstein’s rule is similar to refactoring for pulling up and pushing down attributes and methods.There is no argument for completeness in terms of a normal form expressed in terms of a smallset of object-oriented constructs as in [17, 16]. Consequently, his notion of completeness does notcover all possible transformations that can be applied to object-oriented programs. In particular,there are no transformations for dealing with type tests and casts, nor he deals with type changes.

Banerjee and Kim [8] applied restructuring operations in the context of database schema evo-lution. They defined a set of schema transformations, which are used for schema evolution: thedynamic definition and subsequent changes to a database schema in an object-oriented databaseenvironment. They identified a set of invariant properties of an object-oriented schema which mustbe preserved across schema changes, for instance, attributes of a class, whether defined or inher-ited, have distinct names. There are no rules allowing changing the location of a method in a classhierarchy.

2.2 Refactoring

The seminal work on the formalisation of refactoring of object-oriented programs was presentedby Opdyke [69]. He identified 23 primitive refactorings and gave examples of three compositerefactorings. Each primitive refactoring has a set of preconditions that would ensure the behaviorpreservation of the transformation. Behavior preservation is argued in terms of seven programproperties, which are related to inheritance, scoping, type compatibility, and semantic equivalence.The properties are the following:

1. Unique Superclass: every class must have exactly one superclass.

2. Distinct Class Names: every class in the system must have a unique identifier.

3. Distinct Member Names: attributes and methods have unique names in a single class. Meth-ods can be redefined in subclasses.

4. Inherited Member Variable Not Redefined : a subclass cannot redefine an attribute of itssuperclass.

2.2. REFACTORING 11

5. Compatible Signatures in Member Function Redefinition: redefinitions of methods have thesame signatures as the redefined method.

6. Type-Safe Assignments: every expression that is assigned to a variable must be of the typeor a subtype of the type of the variable.

7. Semantically Equivalent References and Operations: operationally, it means that before andafter a refactoring, a program has to produce the same output for a given set of inputs.

The importance of the achievement of Opdyke is not only the identification of refactorings,but also the definition of the preconditions that are required to apply a refactoring to a programwithout changing its behaviour. Each refactoring is (informally) shown to be behaviour-preservingby arguing that the preconditions satisfy the seven properties above.

Roberts [74] goes a step further than Opdyke: he gives a definition of refactoring that focuses ontheir pre- and post-conditions. The definition of post-conditions allows the elimination of programanalysis that are required within a chain of refactorings. This comes from the observation thatrefactorings are typically applied in sequences intended to set up preconditions for later refactorings.Pre- and postconditions are all described as first-order predicates; this allows the calculation ofproperties of sequences of refactorings.

Roberts also takes the position that a refactoring is correct if a program that meets its spec-ification continues to meet its specification after the refactoring. A suite of tests is understoodas a form of specification; the definition of correctness is based on test suites. In summary, arefactoring is correct if a program that passes a test suite continues to pass the test suite after therefactoring. There is no semantic-based proof that refactoring preserves the behaviour of a programor continues meeting its specification. He recognises that formal proofs of semantically equivalentreferences and operations are difficult to produce. His definition of refactoring is simply a pro-gram transformation that has a precondition that a program must satisfy for the refactoring to belegally applied. According to him, this avoids formal proofs of correctness. Roberts also examinestechniques for using run-time analysis to assist refactoring. He discusses dynamic refactoring inwhich the program, while running, checks for certain properties, applies appropriate refactorings,and then can retract those refactorings.

Roberts automates the basic refactorings proposed by Opdyke; composite refactorings can bedefined based on the basic refactorings. As part of his research, he developed the RefactoringBrowser, a tool to refactor Smalltalk programs [73].

Notice that both Opdyke and Roberts formalise refactorings for automation purposes only. Forthis reason, the condition Semantically Equivalent References and Operations presented by Opdykecannot be strictly checked. From Robert’s work, it is clear that the specification that a programmeets is a test suite, not a description formalised as a first-order predicate, for instance.

Most of the low-level refactoring presented by Opdyke are described by laws of programming inrool [17, 16]. For instance, refactorings delete member functions and create member function can

12 CHAPTER 2. REFACTORING—STATE OF THE ART

be seen as applications of law 〈method elimination〉 from left to right, and from right to left, respec-tively. In the case of delete member functions, maybe law 〈method elimination〉 should be appliedmore than one time. On the other hand, Opdyke’s refactoring convert instance variable to pointercannot be described in rool as it has a copy semantics. Other refactorings we have not ad-dressed are change class name and a similar one that concerns variable name. Class and variablerenaming are purely syntactic operations. Opdyke also presents composite refactoring that arebuilt on low-level refactorings. The composites refactorings abstract access to member variableand convert code segment to function are described, in the present work, as 〈Encapsulate Field〉and 〈Extract Method〉, respectively.

Roberts implements a subset of the refactorings proposed by Opdyke. Only those related torenaming are not addressed in the present work. Since Robert’s work extends that of Opdyke,some refactorings presented by Roberts are described as programming laws in rool [17, 16]. Forinstance, refactorings Pull Up Instance Variable and Push Down Instance Variable aresimilar to law 〈move attribute to superclass〉 when applied from left to right, and from right to left,respectively.

Tokuda [86, 85] uses the properties proposed by Opdyke for behaviour preservation. Heimplements the refactorings proposed by Opdyke for C++, and others that are not listed inOpdyke’s work, like inherit, which establishes a superclass-subclass relationship between two ex-isting classes. Tokuda views a refactoring as a parameterised behaviour-preserving program trans-formation. Refactorings check enabling conditions to ensure that program behaviour is preserved,identify source code affected by a change, and execute all changes. His experiments and analysisshowed that the invariants proposed by Opdyke are not sufficient due to complexities introducedby the language being transformed. For this reason, when a refactoring was found to change thebehaviour, he defined new invariants. One of these new invariants is No instantiation side-effects,which requires the constructor of a class to have no side-effects besides initialising the object cre-ated. He also identified new refactorings.

Tokuda takes the position that refactorings are behaviour-preserving due to good engineeringand not to any mathematical guarantee. He argues that, given a mature refactoring implementation,refactorings should be treated as trusted tools in the same way as compilers transform sourcecode to assembly even without mathematical proof to guarantee correctness. As Tokuda’s focusis the implementation of refactorings for the language C++, we cannot describe a refactoringlike decorator, which involves pointers. In fact, he also defines refactorings based on designpatterns [43]. We do not address the definition of transformation rules to introduce design patternsin a single step.

Fowler [42] presents a catalog of refactorings. Each refactoring is given a name and a shortsummary that describes it. A motivation describes why the refactoring should be done; there isalso a mechanic, a step-by-step description of how to carry out the refactoring, and, finally, anexample. Fowler suggests that, before starting a refactoring, one should have a solid suite of tests

2.2. REFACTORING 13

that must be self-checking. Every change must be followed by program compilation and test. Thereare no conditions to be satisfied in order to guarantee behaviour preservation. In fact, Fowler’sapproach to refactoring is based on compilation and test cycles. His book is a landmark in makingrefactoring known to programmers in general.

Back [6] studies a method for software construction that is based on incrementally extendingthe system with a new feature at a time. He refers to this method as stepwise feature introduction.Introducing a new feature may destroy some already existing features, so the method must allowchecking that old features are preserved. A layered software architecture is proposed to supportthis method. He also takes into account correctness conditions and reasons about their satisfactionin the refinement calculus. He assumes that each class in a system has a class invariant, whichexpresses the conditions on the attributes that must be established when the class is instantiated,and which must be preserved by each operation on the class. Methods have preconditions, whichstate the assumptions that must hold when the methods are called, and possibly postconditions,which express properties that hold when the calls return. Data refinement is used to prove thecorrectness of an implementation. Although the approach seems similar to ours, no programminglaws are presented or are explicitly used for refactoring programs.

2.2.1 Formalisms

A variety of formalisms has been used to deal with restructuring and refactoring. Snelting andTip [77] use concept analysis to restructure class hierarchies. Their method analyses a class hi-erarchy along with a set of applications that use it. A table is constructed that precisely reflectsthe usage of the class hierarchy. A concept lattice is constructed from the table, which factorsout information that variables, for instance, have in common. Situations in which a class can besplit can also be detected. They showed that the technique is capable of finding anomalies suchas redundant attributes. The class hierarchy that results from the application of the proposedtechnique is guaranteed to preserve the behaviour of the original hierarchy. The formal basis ofthis work is concept analysis.

Program slicing [83, 10] deals with a specific kind of restructuring: function or procedure ab-straction. Lakhotia and Deprez [52] present a transformation called tuck for restructuring programsby decomposing large functions into small functions: it breaks large code fragments and tucks theminto new functions. The challenge they faced was creating new functions that capture computa-tions that are meaningfully related. There are three basic transformations to tuck functions: (1)related code is gathered by driving a wedge (which is a program slice bounded with single-entryand a single-exit point) into the function, then (2) the code isolated by the wedge is split, and(3) the split code is folded into a function. These transformations even create functions fromnon-contiguous code.

Komondoor and Horwitz [51] address the conditions under which it is possible to move a set ofselected statements together so that they can be extracted while preserving semantics. They use

14 CHAPTER 2. REFACTORING—STATE OF THE ART

control flow graphs to represent pieces of code. They present an algorithm that move a selected setof control graph nodes together so that they can be extracted whilst preserving the semantics. Theyidentified conditions based on control and data dependence that are considered to be sufficient toguarantee semantic equivalence.

Restructuring can also be dealt with by means of graph transformations. The software isrepresented as a graph, and restructuring corresponds to transformation rules. Graph rewritingappears as a lightweight formalism [60]. Mens, Demeyer, and Janssens [61] present the formalisationof refactoring using graph rewriting, a transformation that takes an initial graph as input andtransforms it into a result graph. This transformation occurs according to some predefined rulesthat are described in a graph-production which is specified by means of left-hand and a right-handsides. The first one specifies which parts of the initial graph should be transformed, while the lastone specifies the result after transformation. Well-formedness is expressed by means of type graphsand forbidden subgraphs. A type graph is a meta-graph expressing restrictions on the instancegraphs that are allowed. A graph is well-formed only if there exists a graph morphism into atype graph. Forbidden graphs exclude illegal configurations in a graph, so that a graph satisfiesthe constraint expressed by a forbidden graph if there does not exist a morphism between thegraph and the forbidden graph. The notion of equivalence is that for each refactoring, one maycatalog that types of behaviour that need to be preserved. A refactoring is access preserving if eachmethod implementation accesses at least the same variables after refactoring as it did before therefactoring. They consider also two other types of behaviour: update preserving, a method updatesat least the same variables after a refactoring as it did before the refactoring; and call preserving ifeach method implementation performs at least the same method calls after a refactoring as it didbefore refactoring.

Graph rewriting is considered a suitable formalism for specifying refactoring because graphs area language-independent representation of the source code, rewriting rules are considered preciseand concise to specify source code transformation, and the formalism allows proving behaviourpreservation. However, they recognise that it is difficult to manipulate nested structures in methodbodies in refactoring such as move method and push down method so that it is necessary to usetechniques that tackle the inevitable complexity of large graphs.

These formalisms are usually used for the description of transformations or are used as theformal basis for transformations so that it is possible to guarantee that they do not change programbehaviour. However, they are not concerned with giving a language semantics, but describinga transformation. In this way, they may be useful in a refactoring tool, allowing us to checkrefactoring preconditions. Besides these formalisms, Philipps and Rumpe [70] suggest the existingrefinement approaches are a way to formally deal with the notion of behaviour preservation requiredby refactorings. Behaviour preservation is not a notion specific to the domain of refactoring, it alsooccurs, for instance, in the area of refinement techniques [65, 7]. Our work is in this direction. Wedescribe refactoring by using a language that has a weakest precondition semantics and a set of

2.2. REFACTORING 15

laws effectively used in the derivation of refactoring rules.

2.2.2 Languages

There are definitions for restructuring programs written in different programming languages. Aswe have already seen, the work of Griswold [45] deals with restructuring programs written in thefunctional programming language Scheme. Thompson and Reinke [81, 82] addressed refactoring ofprograms written in the Haskell programming language. They characterise refactoring as diffuse—refactoring requires changes throughout a module or a system of modules—, and bidirectional—itcan be applied in one direction and in the reverse direction. As an example of refactoring, theypresent demoting definition, a refactoring that moves the definition of an auxiliary function to thescope of the function that calls it, since the auxiliary function is not used elsewhere.

Class-based object-oriented languages have already been addressed. Roberts, Brant, and John-son [73] present a tool for refactoring Smalltalk programs. Refactoring for Java programs is pre-sented by Fowler [42]. Tokuda and Batory [85] automate refactorings for C++.

2.2.3 Refactoring Models

Refactorings can also be applied at higher levels of abstraction than source code. Design models,for instance, can be the target of refactorings. These models can be specified using, for example,the Unified Modelling Language [12].

Sunye et al. [80] present a set of design refactorings for models described in the Unified ModellingLanguage. They present refactorings of class diagrams and statecharts. In order to guaranteebehaviour preserving transformations of statecharts, they specify the constraints that must besatisfied before and after the transformation using the OCL at the meta-model level.

Astel [2] proposes using an UML tool as an aid in finding smells—a structure in code thatsuggest the possibility of refactoring—and performing some elaborate refactorings. It is a tool thatbases class diagrams directly on code, allowing code manipulation by the direct manipulation ofthe diagram. Among the reasons for refactoring in UML, he highlights the fact that many peopleprefer to visualise classes and their relationships, and that the level of abstraction is higher whencompared to code. Also, smell detection can be done by visualising the classes of a system. Forinstance, it is easy to visualise large classes. Refactoring can be done by simple drag-and-dropactions. He argues that it is necessary to use a tool that generates diagrams from code, and thetool needs to keep the code and the model synchronised.

Gheyi and Borba [44] introduce and formalise modelling laws; their emphasis is on refactoringof models described in Alloy [47]. An Alloy model is a sequence of signatures, which are usedto define new types, and formulas, used to record constraint information. Besides a basic type,a signature introduces relations. The basic laws they propose deal with properties of signatures,formulas, and relations. The laws they propose are supposed to be the basic transformations that

16 CHAPTER 2. REFACTORING—STATE OF THE ART

serve as a basis for more elaborate laws for practical applications of model transformation.

Bottoni, Parisi-Presicce, and Taentzer [18] present an approach to maintain the consistency ofspecification and code after refactoring. The specification can be composed of UML diagrams ofdifferent types; they show that some refactorings require modifications in several diagrams at once.Refactorings are expressed by pre- and postconditions. To ensure consistency between source codeand structural and behavioural models, they use graph transformations. Both code and models arerepresented by graphs. Each refactoring is described by means of a set of transformation schemes.

Porres [71] focus on the implementation of refactoring as a collection of transformation rules,which receive one or more model elements as parameters, and perform a basic transformation basedon the parameters. They use their own scripting language SMW to manipulate models based onthe Python programming language. A metaclass of the metamodel of UML is written as a classin Python; SMW scripts resemble OCL. One of the elements of the transformation rule is a guardthat defines when the rule can be applied; there is also a body that implements the effect of therule. As refactorings are group of rules, the guard of one rule can refer to the guards of otherrules in the same transformation. The execution of a transformation is described by a sequentialalgorithm that accepts a transformation to apply and a set of model elements.

A refactoring transformation is considered to be correct if the transformation terminates: thetransformed model is syntactically correct, and the transformation preserves some observable prop-erties of the model. Porres argues that the number of rules in a transformation and the number ofelements in a model are finite, so the transformation terminates. Syntactic correctness is ensured bythe fact that rules give as results well-formed models. Behaviour preservation requires a semanticinterpretation of UML given, for example, by graph transformations.

Boger et al. [11] present a refactoring browser integrated in a UML tool. They concentrateon the detection of conflicts that may be introduced after the application of a refactoring. Theyclassify conflicts as warnings and errors. Warnings indicate that conflicts might cause a side effect.For instance, they consider that renaming a method that overrides a method of a superclass maybe behaviour preserving in some cases, but an unwanted design change in others. Errors indicatethat an operation will cause damage to the model or code. They also address refactoring of statemachines, like merging of states and formation of composite states. In our case, we rule out anykind of conflicts, because we must always preserve a program’s behaviour. As a consequence, weavoid method overriding in refactorings.

2.3 Design Patterns

Patterns record the knowledge and expertise that has been built up along many years of softwareengineering. They can be found in any part of the development process, for instance, architecture,analysis, and design.

Patterns can also arise in specific areas like real-time programming. In fact, patterns come from

2.3. DESIGN PATTERNS 17

the observation of existing systems, motivated by the desire to uncover solutions that are repeatedlyapplied. In the context of the design of object-oriented systems, Coad [30] presents the conceptof patterns and its application to object-oriented analysis and design. He also explores sevenpatterns, presenting them by means of graphical notation, a textual description, and guidelines forthe application of each pattern.

Gamma et al. [40] propose design patterns as a mechanism for expressing design structures. Inthat work, they present a catalog of design patterns that they have discovered when building theirown class libraries and collected from the literature. Besides that, they classify patterns accordingto their common aspects [43].

Cinneide [29, 28] discussed the automatic introduction of design patterns through the applica-tion of refactorings. In developing a transformation for a particular design, certain motifs, observedto occur across catalogues of patterns, are defined as minipatterns that are combined in various waysto produce different patterns. For each minipattern identified, a minitransformation is developed,which comprises a set of preconditions, a sequence of transformation steps, a set of postconditionsand an argument demonstrating behaviour preservation. Each minitransformation is defined interms of low-level refactorings.

2.3.1 Formalization of Design Patterns

A formal description of design patterns has already been provided by Flores et al. in [41], whereelements that constitute a general object-oriented design and their formal model are presented.They use the RAISE Specification Language to formally specify properties of design patterns. Infact, they introduced a general model that allows describing an arbitrary object-oriented designand not only patterns. They also formally specify how to match a design against a pattern. In thisway, its is possible to verify that a given subset of a design corresponds to a given pattern. Thislink is given by using a renaming map, which associates the names of entities (classes, methods,attributes, and parameters) in the design with the names of corresponding entities in the pattern.Several consistency conditions must be satisfied in the renaming.

Eden [38] uses a declarative language called LePUS (LanguagE for Pattern Uniform Specifica-tion) [39], which is mostly graphic. A program in LePUS is modelled as a set of entities (classes andmethods) and relations (inheritance, method invocation, object creation etc). Every well-formedLePUS diagram translates to a formula in higher-order logic that allows reasoning about speci-fications. LePUS formulae are used to describe design patterns in the form of logic statements;patterns are transcribed to formulae.

Lano et al. [53] used theories similar to those used for giving the semantics of VDM++ [49],which consist of a collection of type, constant, attribute and action symbols, and a set of axiomsdescribing the types of attributes, the effects, and the dynamic properties of the actions. A systemD is said to refine a system C if there is a theory interpretation from the theory of C to the theoryof D . They characterise design patterns as a transformation from a “before” system consisting of

18 CHAPTER 2. REFACTORING—STATE OF THE ART

a set of classes into an “after” system consisting of a collection of classes organised according to adesign pattern. They prove that the “after” system is an extension, via a suitable interpretation, ofthe theory of the “before” system. An extension usually introduces new symbols which are definedby axioms. They use VDM++ to write the “before” and “after” systems, then they establish aninterpretation between these systems.

2.4 Conclusions

In this chapter we presented a survey about program restructuring. We concentrated on worksabout refactoring, with focus on the description of works related to formalisms for describingrefactoring, target languages for refactoring, and model refactoring. We also presented a survey ofworks on design patterns, mainly related to the their formalisation.

As can be observed from the presentation of current works, no work on the formalisation ofrefactoring relies in a uniform basis for the description of program transformations. In other words,to prove that a refactoring is correct, it is described using a specific formalism like graph transfor-mations. Existing refinement techniques can also be used as tools for the proof of correctness ofrefactorings. We can prove that a refactoring is correct in a uniform way, without changing thelanguage which is used to present a refactoring. A refactoring could be represented as a transfor-mation from a program to a refactored one, both written in a language, and the transformationfrom one to the other expressed almost in the same language used to write the program as weintroduce meta-variables for classes, attributes, methods, local variables. Such language must havea formal semantics and laws that serve as a sound basis for software development.

Chapter 3

ROOL and Laws

rool [21, 22], an acronym for Refinement object-oriented Language, is a Java-like imperative lan-guage with classes, inheritance, visibility control for attributes, dynamic binding, and recursion. Itallows reasoning about object-oriented programs and specifications, since both kinds of constructsare mixed as in refinement calculus languages [64, 65]. The semantics of rool, as usual for refine-ment calculi, is based on weakest preconditions. The imperative constructs of rool are based onthe language of Morgan’s refinement calculus [64], which is an extension of Dijkstra’s language ofguarded commands. In a refinement calculus, specifications are regarded as commands. In fact,we use the term command to refer to commands, in its usual sense, and programming constructsin which specifications and commands are mixed.

This chapter is organised as follows. First we present the abstract syntax of rool, then wepresent its typing system, its semantics, a notion of program and class refinement, and, finally, a listof programming laws. The sections about the syntax, typing, semantics, and refinement are basedon the technical report that introduces the language rool along with its weakest preconditionsemantics [22]. The section that presents the laws of rool is based on [16, 17, 14, 15, 33].

3.1 Syntax

First, we define the data types for rool. Data types are either class names (N ) or primitive (bool,int, and others). Data types T are the types of attributes, method parameters, local variables,and expressions.

T ∈ Typ ::= N | bool | int | . . . other primitive types

For writing expressions, rool provides typical object-oriented constructs (Table 3.1). We as-sume that x stands for a variable identifier, and f for a built-in function; self and super havea similar semantics to this and super in Java, respectively. The type test e is N has the samemeaning as in e instanceof N in Java: it checks whether non-null e has dynamic type N ; when

20 CHAPTER 3. ROOL AND LAWS

e ∈ Exp ::= self | super special ‘references’| null | error| new N object creation| x variable| f (e) application of built-in function| e is N type test| (N )e type cast| e.x attribute selection| (e; x : e) update of attribute

ψ ∈ Pred ::= e boolean expression| ψ ⇒ ψ| (∨ i • ψi)| ∀ x : T • ψ| e isExactly N strict type test

Table 3.1: Grammar for expressions and predicates

e is null, it evaluates to false. The expression (N )e is a type cast; the result of evaluating suchan expression is the object denoted by e if it belongs to the class N , otherwise it results in error.Attribute selection e.x results in a run-time error when e denotes null. The update expression(e1; x : e2) denotes a copy of the object denoted by e1 with the attribute x mapped to a copy ofe2. If e1 is null, the evaluation of (e1; x : e2) yields error. Indeed, the update expression createsa new object rather than updating an existing one.

The expressions that can appear on the left of assignments, as the target of a method call, andas result arguments constitute a subset Le of Exp. They are called left-expressions.

le ∈ Le ::= le1 | self .le1 | ((N )le).le1le1 ∈ Le1 ::= x | le1.x

The predicates of rool (Table 3.1) include expressions of type bool, formulas of the first-orderpredicate calculus, and strict type tests of the form e isExactly N .

The imperative constructs of rool, including those related to object-orientation concepts, arespecified in the Table 3.2. In a specification statement x : [ψ1, ψ2], x is the frame, and the predicatesψ1 and ψ2 are the precondition and postcondition, respectively. It concisely describes a programthat, when executed in a state that satisfies the precondition, terminates in a state that satisfiesthe postcondition, modifying only the variables present in the frame. In a state that does notsatisfy ψ1, the program x : [ψ1, ψ2] aborts: all behaviours are possible and nontermination too.The variable x is used to represent both a single variable and a list of variables; the context shouldmake clear the case. Two specification statements are distinguished: the first is x : [false, true]—we also refer to it as abort— which is never guaranteed to terminate (precondition false), andwhen it does, it can assign any values to the variables in x (postcondition true); the second is the

3.1. SYNTAX 21

c ∈ Com ::= le := e multiple assignment| x : [ψ1, ψ2] specification statement| pc(e) parameterised command application| c; c sequential composition| if []i • ψi → ci fi alternation| rec Y • c end recursion| Y recursive call| var x : T • c end local variable block| avar x : T • c end angelic variable block

pc ∈ PCom ::= pds • c parameterisation| le.m | ((N )le).m method calls| self .m | super.m

pds ∈ Pds ::= ∅ | pd | pd ; pds parameter declarationspd ∈ Pd ::= val x : T | res x : T

Table 3.2: Grammar for commands and parameterised commands

specification x : [true, false], also known as miracle, which terminates when execute in any stateand establishes false as postcondition.

In program derivation, it is also useful to assume that a condition φ holds at a given point inthe program text. This can be characterised as an assumption of φ, written {φ}, whose definitionis given by the specification statement : [φ, true]. If φ is false, the assumption reduces to abort.Otherwise, it behaves like skip, a program that always terminates and does nothing. The definitionof skip is given by the specification statement : [true, true]. The empty frame guarantees that novariables are changed.

Complementary to assumptions are coercions. A coercion to φ, written [φ], whose definitionis given by the specification statement : [true, φ], behaves like skip if φ is true, and miracle

otherwise.

We define methods as parameterised commands in the same style as Back [4, 27], becauseMorgan’s approach may lead to some inconsistencies [26]. Parameterised commands can havethe form val x : T • c, or res x : T • c, which correspond to the parameter passing mechanismsknown as call-by-value, and call-by-result, respectively. The parameterised command applicationpc(e) yields a command which behaves as the one obtained by passing the arguments e to thebody of the parameterised command. Parameters that are passed by different parameter passingmechanisms are declared in the usual way. For example, for parameters x and y which are passedby value and result, respectively, we have the following declaration: val x : T ; res y : T ′. Aparameterised command with an empty parameter declaration behaves like an ordinary command.

For alternation, we use an indexed notation for finite sets of guarded commands. A method inrool can use its name in calls to itself in its body. This is the traditional way to define a recursivemethod. rool also includes the construct rec Y • c end, which defines a recursive command using

22 CHAPTER 3. ROOL AND LAWS

Program ::= cds • ccds ∈ Cds ::= ∅ | cd cdscd ∈ Cd ::= class N1 extends N2

{pri x1 : T1; }∗{prot x2 : T2; }∗{pub x3 : T3; }∗{meth m = (pds • c)}∗

end

Table 3.3: Programs in rool

the local name Y . A (recursive) call Y to such a command is also considered to be a command.The iteration command can be defined using a recursive command.

Blocks var x : T • c end and avar x : T • c end introduce local variables. The former in-troduces variables that are demonically initialised; their initial values are arbitrary. The latterintroduces variables that are angelically chosen [7]. This kind of variable is also known as log-ical constant, logic variable, or abstract variable. In practice, angelic variables only appear inspecification statements.

As methods are seen as parameterised commands, which can be applied to a list of arguments,yielding a command, a method call is regarded as the application of a parameterised command. Acall le.m refers to a method associated to the object denoted by le. In a method call e1.m(e2), e1

must be a left expression.

A program in rool is a sequence of class declarations followed by a command (Table 3.3).A class declaration cd introduces a class named, for instance, N1. The clause extends indicatesthe immediate superclass of N1. If the superclass is omitted, the pre-defined class object is thesuperclass of the class being declared. The class object has no attributes or methods.

The visibility control clauses pri, prot, and pub introduce private, protected, and publicattributes, respectively. The variables x1, x2, and x3 along with their types T1, T2, and T3 canbe lists. Private attributes are visible just inside the class in which they are declared; protectedattributes are visible inside the class in which they are declared and in its subclasses; and publicattributes are visible to all declared classes. The visibility control clauses can appear zero or moretimes in a class declaration.

A class in rool can have a (possibly empty) list of method declarations. A method is introducedby a clause meth m = (pds • c), where m is the name of the method, and pds • c is the body ofthe method: a parameterised command. All methods in rool are public.

An example of a class in rool is presented in Figure 3.1. The class Person has private at-tributes name, areaCode, and homeTelNumber of type string. The method getName has a resultparameter arg to which is assigned the value of the attribute name of such class. The method

3.2. TYPING 23

class Personpri name : string;pri areaCode : string;pri homeTelNumber : string;meth getName = (res arg : string • arg := self .name)meth getTelephoneNumber = (res tel : string • tel := self .homeTelNumber)

end

Figure 3.1: A class in rool

getTelephoneNumber also has a result parameter and gives the telephone number of a person. Thisclass is similar to the one presented in Figure 1.1.

3.2 Typing

rool has as phrase types the data types T and those for predicate formulas, commands, parame-terised commands, and complete programs.

θ ::= T | pred | com | pcom(pds) | program

In the next sections we define typing environment, and typing rules for commands and programs.

3.2.1 Typing environment

The typing environment is a record that registers the typing and inheritance information of asequence of class declarations. It also registers typing information concerning method parameterand local variable declarations in scope. We use a dot for denoting field access, as usual.

There are two disjoint sets of names: the set CNames of class names and the set LNames oflocal names. A local may be either an attribute, a method, a method parameter, or a local variable.The class names object and main are distinct from all other class names. The class object is thesuperclass of all classes without an explicit superclass declared. The class main refers to the mainpart of a whole program in rool; it is not really a class.

A typing environment Γ is a record with six fields: attr , meth, vis, cnames, supcls, and locals.The first of these, attr , is a finite partial function from CName to LSignature. Formally, it iswritten CName 7 7→ LSignature. A LSignature associates a local name with a type. Formally, wehave LSignature = LName 7 7→ T . The field attr records the names and types of all declared andinherited attributes of every declared class. The meth field records the names and signatures ofall declared and inherited methods of all classes. Formally, meth has type CName 7 7→ MDecs,where MDecs = LName 7 7→ Pds.

The third field of a typing environment, vis, records the visibility of attributes of the declared

24 CHAPTER 3. ROOL AND LAWS

classes. The type of vis is given by CName 7 7→ (LName 7 7→ Visibility), where Visibility is given bythe set {pri , prot , pub, ipri}. Private attributes that are declared in a class, and not inherited, areassociated to pri ; the inherited private attributes are associated to ipri ; prot refers to the protected(either inherited or declared) attributes, and pub refers to the public attributes that were declaredor inherited by a class.

The cnames field is a set that contains the names of all declared classes. This set is the commondomain of attr , meth, and vis. The class name object is supposed to be in cnames, while main,which is not a class itself, is not in cnames. As the class object has no attributes or methods, itsfields attr and meth are associated to the empty signature (empty set).

The supcls field of a typing environment associates each class name to the name of its im-mediate superclass. The type of supcls is CName 7 7→ CName. All declared classes have a di-rect superclass, which can be object. On the other hand, object itself does not have a su-perclass. Moreover, the inheritance relationship is not allowed to have circularities. Formally,we have supcls+ ∩ idCName = ∅, where id T is the identity relation on T . We define the sub-type relation ≤Γ based on the inheritance relationship recorded in supcls, which is defined byT1 ≤Γ T2 ⇔ (T1,T2) ∈ (Γ.supcls)+ ∨ T1 = T2. If T1 and T2 are related by the transitive closureof Γ.supcls or are equal, then T1 is a subtype of T2.

The last field of a typing environment, locals, records the types of the visible attributes ofthe current class, and of method parameter and local variables in scope. The type of locals isLSignature.

The types of phrases, in the context of a collection of class declarations, a specific class, andsome method parameter and local variable declarations, are given by the typing relation B . Forexample, Γ,N B c : com asserts that c is a command that can appear in the body of a method inclass N , in a context captured by the typing environment Γ. Similarly, Γ,N B e : T attests that eis an expression of type T in a method of class N .

Any typing in the context of a typing environment Γ and of a class N holds only if Γ is well-formed and derivable using the typing rules that are presented later. A typing environment Γ iswell-formed if the following conditions are satisfied. First, the conditions above hold. Secondly,the current class must be declared: N 6= main ⇒ N ∈ Γ.cnames. Thirdly, all visible attributes ofN must be present in the domain of the locals field. In other words, all but the inherited privateattributes (those associated to ipri) must be in dom Γ.locals. If N is main, then Γ.locals containsonly parameter and local variables.

In the next section we illustrate the typing rules for commands, parameterised commands, andprograms. The whole set of rules can be found in Appendix H.

3.2.2 Typing Rules

The typing rules for expressions in rool are presented in the Table 3.4. The type of self is the oneof the current class. The type of a null object is that of any declared class. The expression e is N ′′

3.2. TYPING 25

N 6= main

Γ,N B self : N

N ′ ∈ Γ.cnames

Γ,N B null : N ′

Γ,N B e : N ′ N ′′ ≤Γ N ′

Γ,N B e is N ′′ : bool

Table 3.4: Typing of Expressions

(Γ; x : T ) B c : com par ∈ {val, res}Γ B (par x : T • c) : pcom(par x : T )

Γ,N B le : N ′ Γ.meth N ′ m = pds

Γ,N B le.m : pcom(pds)

Table 3.5: Typing of Parameterised Commands

Γ B le : T Γ B e : T ′ T ′ ≤Γ T sdisjoint le

Γ B le := e : com

Γ B (res x : T • c) : pcom(res x : T ) Γ B le : T ′ T ≤Γ T ′ sdisjoint le

Γ B (res x : T • c)(le) : com

Γ B le.m : pcom(pds) Γ B e : Tsdisjoint(le, rvrargs pds e) aptype Γ pds e T

Γ B le.m(e) : com

Table 3.6: Typing of Commands

is well-typed when the type of e is a superclass of N ′′. This condition is also applicable to the typecast (N ′′)e.

Typing rules for parameterised commands appear in Table 3.5. The type of a parameterisedcommand records its parameter declarations. The parameterised command (par x : T • c) hastype pcom(par x : T ), provided the command c is well-typed in an environment that records theparameters x . The parameter passing mechanism is any of those present in rool (val, res). Theparameterised command le.m is well-typed only if the type of le is a class with a method namedm. The method parameters are recorded in the meth field of the typing environment.

Commands

The typing rules for commands are presented in Table 3.6. An assignment le := e is well-typed ifthe type of e is a subtype of that of le. The condition sdisjoint le requires that, if le is a list, then nomember of le is a prefix of another one after deleting self and type casts, in order to avoid aliasing.For instance, neither x , x .y nor x , self .x is sdisjoint , but x , y .x is. For a result parameter, theparameterised command can only be applied to left-expressions. An application of (res x : T • c)to a result argument le is well-typed if T is a subtype of the type of le. The command le.m(e) canpotentially modify le. So, it is required that le and the arguments passed by result are sdisjoint ,

26 CHAPTER 3. ROOL AND LAWS

avoiding aliasing. The types of the list e of arguments must satisfy the condition aptype Γ pds T ,which enforces these types to be adequate with respect to the parameter passing mechanisms thatare used. The constraints imposed by aptype are similar to those that appear in the typing rulesfor explicit parameterised commands.

Programs

The typing rule for a program is shown in what follows. The typing (∅; x : T ) B cds • c : program

asserts that the program cds • c is well-typed in a typing environment in which only global variablesx are in scope. The free variables of a program are those used for input and output. In (∅; x : T )information about the global variables x : T is recorded in the locals field of the typing environment.

The valid environment Γ, in which the command c is required to be well-typed, is determined bythe sequence of class declarations cds and variable x . The environment Γ contains information aboutthe class object. The function VDecs extracts information from the sequence of class declarationscds. It also checks its validity, as explained in what follows. The condition VMeth Γ cds checksthat the method bodies in the sequence of class declaration cds are well-typed in the environmentΓ. The conditions ‘¿cds is well-founded’ and ‘noredandrec Γ cds’ verify that mutually recursivecalls and recursive definitions for methods with more than one definition, respectively, do not existin the sequence cds.

Γ,main B c : com Γ = ((VDecs cds main); x : T )Vmeth Γ cds ¿cds is well-founded noredandrec Γ cds

(∅; x : T ) B cds • c : program

The function VDecs is defined based on the function Decs, which extracts the typing and visi-bility information about attributes and methods, and the inheritance relationship from a sequenceof class declarations. The application of Decs to a sequence of class declaration cds, like a typingenvironment, is a record with four fields: attr , meth, vis, and supcls. The function Decs is totaland it does not guarantee that there are no inappropriate or missing declarations in the sequenceof class declarations. If the sequence of class declarations does not contain invalid declarations,and N is either main or a class declared in cds, then VDecs cds N yields the typing environmentfor cds which is extracted by the function Decs. The locals field of this environment contains thevisible attributes of N , if it is not main; it is empty if N is main. The domain of VDecs cds Nis characterised by some conditions. First, main is not declared in cds. Secondly, there is noredeclarations (hiding) of an attribute in a subclass. Methods can be overridden in a subclass, butits signature has to be maintained. Finally, the class N has to be declared in cds or it is main.

The typing rule for programs also restricts method declarations. The restrictions are describedby the function Vmeth Γ cds: the method bodies in the sequence of class declarations cds arewell-typed in the typing environment Γ. The body of a method m is checked in a context where

3.3. SEMANTICS 27

the locals are the visible attributes of N , the class in which the method is declared.The relation ¿ associates a method m of class N , represented by (N ,m), with a method m ′ of

class N ′, written as (N ′,m ′). We write (N ,m) ¿cds (N ′,m ′) when in the sequence of class decla-rations cds, the body of m of class N can call the method m ′ in class N ′. If ¿cds is well-founded,there is no mutual recursion in cds. In other words, ¿cds has no circularities. For instance, it ex-cludes the relation {(D ,m2) 7→ (C ,m1), (D ,m2) 7→ (C ′,m1), (C ′,m1) 7→ (D ,m2)}, in which thereis mutual recursion involving method m1 and m2 of class C and D , respectively.

The ¿ relation does not capture situations in which recursion is introduced in the same chainof inheritance by means of recursive calls; it only looks for calls to methods, in the same chain ofinheritance, that have distinct names. The condition noredandrec Γ cds establishes that if a method(N1,m) contains a call to (N2,m), then either N1 and N2 are not in the same chain of inheritance(they are not superclasses of one another) or there is no redefinition of m in a proper superclass orsubclass of N1. For instance, for classes C and C ′, such that C ′ ≤cds C , and a method m declaredby C and redefined by C ′ the relation {(C ,m) 7→ {(C ,m), (C ′,m)}, (C ′,m) 7→ ∅} does not satisfythe condition noredandrec, as (C ,m) is included in the set related to (C ,m) itself, and C and C ′

are paired to m in the domain. So, there is a redefinition of m, which is originally recursive. Also,for the relation {(C ,m) 7→ ∅, (C ′,m ′) 7→ {(C ,m), (C ′,m)}}, in which C is a superclass of C ′, thecondition noredandrec is not satisfied because (C ′,m) is associated to (C ′,m) and (C ,m) is in thedomain.

3.3 Semantics

The semantic functions, denoted by [[ ]], are defined for each derivable typing, except methodcall, by induction on the typing rules. Some of the constructs are treated by means of syntactictransformations; and the semantics of method calls goes beyond structural recursion on typingderivations; it is discussed later. In the semantics definition proposed in [22], there are assignmentsto self , which is not in the grammar of rool as proposed in Section 3.1. Also, semantic definitionspresented in [22] use a value-result parameter passing mechanism (vres), which is not present inthe syntax of rool as we present here. These constructs play a central role in the semantics, butshould not really appear in user programs. Since the emphasis of our work is on laws of programtransformation, we left out of the grammar the constructs we do not need to consider in our laws.

3.3.1 Environments and states

Most semantic functions take an environment η as argument. An environment is a finite par-tial function that associates a class name to its meaning (CName 7 7→ CMeaning). The meaningof a class is described by a function that associates method names to parameterised commands(LName 7 7→ PCom). The parameterised commands have an extra parameter me, passed by value-result, which provides the attributes of the object upon which the method is called.

28 CHAPTER 3. ROOL AND LAWS

The set of environments that are compatible with a given typing environment Γ is denotedby [[Γ]]. The environments η in this set have the following characteristics. First, all declared classesin Γ have a meaning in η (dom η = Γ.cnames). Secondly, the methods that appear in η associatedwith a class N are exactly the methods declared in Γ.meth, including the inherited ones. Formally,we have ∀N : dom η • dom(η N ) = dom(Γ.meth N ). Lastly, the parameter declarations for thesemethods in η are those recorded in the meth field of the typing environment (Γ.meth) together withthe extra value-result parameter me.

∀N : dom η; m : dom(η N ) • ∃ c : Com • η N m = (vres me : N ; Γ.meth N m • c)

The command c is derived as a fixpoint in the environments we construct later.

A state records the values of the attributes of the current class, and the values of the parametersand local variables. In other words, it associates values to the elements of LName. The state alsorecords the class of the current object. Object values associate values to attribute names. In bothcases, the values must be type-correct.

3.3.2 Extended typing

The restrictions imposed by typing rules are appropriate for user programs, but not for the seman-tics. Some of these constraints are relaxed in the definition of what we call an extended typingsystem; it can be characterised by making three changes to the rules presented in Section 3.2.2

The first change drops the constraints involving the predicate visib. With this change, attributesof the parameter me become visible in the context of a method call.

The second change drops the subtyping constraint in typing rules for type tests and type casts.For instance, e is N ′′ requires that e has type N ′ with N ′′ ≤Γ N ′; this condition is dropped. Fromthe semantic point of view, e is N ′′ can only convey useful information if N ′′ is a subtype of thedeclared type of e. This constraint, however, is incompatible with the semantics of assignment.Consider, for example, that we have a class A extended by B , which, in turn, is extended by C .Suppose we have variables a : A, b : B , c : C in Γ.locals. In this way, the command a := c, andthe predicate a is B are well-typed. The weakest precondition of a := c with respect to a is B ,however, involves the substitution (a is B)[c/a], resulting in the predicate c is B . The originaltyping system disallows this predicate, because the type of c is not a supertype of B . We needtypability to be preserved by substitution on formulas, and this only holds in the extended typesystem.

We also add a condition on the rules for le.m, (res x : T • c)(le), and (vres x : T • c)(le).This condition restricts le only to casts of subclasses of the declared types, so that they still satisfythe subtyping conditions in rules for casts of the original typing system. This is the third changeto the extended typing system.

In the next section, we present the semantics for commands and parameterised commands.

3.3. SEMANTICS 29

(val x : T • c)(e) −→ var l : T • l := e; c[l/x ] end if l 6∈ (FV e) ∪ (FV c)(res x : T • c)(le) −→ var l : T • c[l/x ]; le := l end if l 6∈ (FV le) ∪ (FV c)(vres x : T • c)(le) −→

var l : T • l := le; c[l/x ]; le := l end if l 6∈ (FV le) ∪ (FV c)(pd ; pds • c)(e, e ′) −→ (pd • (pds • c)(e ′))(e) if α(pd) 6∈ (FV e ′)(• c)() −→ cle.x := e −→ le := (le; x : e)le.x , y := e, e ′ −→ le, y := (le; x : e), e ′

le.x .x1, le.y .x2 := e, e ′ −→le := (le; x , y : upd (le.x ) x1 e, upd (le.y) x2 e ′)

(N )x := e −→ x := e(N )le.x := e −→ le := ((N )le; x : e)(N )x , y := e, e ′ −→ x , y := e, e ′

(N )le.x , y := e, e ′ −→ le, y := ((N )le; x : e), e ′

le, le ′ := e, e ′ −→ le ′, le := e ′, e

Table 3.7: Syntactic Transformations

3.3.3 Commands and parameterised commands

The semantic equations for commands take an environment η as argument. The semantics ofa command [[Γ,N B c : com]] η is given by a function from formulas to formulas: a predicatetransformer representing weakest preconditions.

The semantics of assignment to simple variables are interpreted as substitutions on formulas.

Γ B x : T Γ B e : T ′ T ′ ≤Γ T

[[Γ B x := e : com]]η ψ = (e 6= error ∧ ψ[e/x ])

Assignment to general left-expressions are manipulated by means of syntactic transformations,yielding assignments of update expressions to simple variables and to self .

Based on the following semantic definition, which refers to the relation −→ that appears inTable 3.7, syntactic transformations can be used to simplify parameter passing and assignmentsinvolving general left-expressions.

c −→∗ c′ [[Γ,N B c′ : com]]η = g

[[Γ,N B c : com]]η = g

The transitive closure −→∗ reduces a command that has a derivable typing to one that has a directsemantic definition.

The transformations that deal with parameter passing are the first five ones in Table 3.7. Theparameter passing mechanism vres corresponds to the traditional convention of call-by-value-result.FV e stands for the set of free variables of e, similarly for commands c. We use α(pd) to denote thevariables declared by pd . The last eight transformations deal with assignment to left-expressions,

30 CHAPTER 3. ROOL AND LAWS

[[Γ B c : com]]η = f [[Γ B c′ : com]]η = f ′

[[Γ B c; c′ : com]]η ψ = f (f ′ψ)

[[Γ B ci : com]]η = fi

[[Γ B if []i • ψi → ci fi : com]]η ψ = (∨ i • ψi) ∧ (∧ i • ψi ⇒ fi ψ)

[[Γ; x : T B c : com]]η = f

[[Γ B (var x : T • c end) : com]]η ψ = (∀ x : T • f ψ)

[[Γ; x : T B c : com]]η = f

[[Γ B (avar x : T • c end) : com]]η ψ = (∃ x : T • f ψ)

Table 3.8: Semantics of some commands

rewriting them into assignments to simple variables and self , using update expressions. Thefunction upd , when applied to a left-expression le, to a list of attributes x , and to an expression e,results in an object copied from le but with each attribute in x changed to take the correspondingvalue in the list e.

In the case of syntactic transformations for parameter passing, assignments to self occur whenthe argument corresponding to the me parameter is self . In the semantics for method calls, self isalways assigned an object of the current class, so that the target and the source of the assignmenthave the same type.

Γ,N B e : N ′ N ′ ≤Γ N

[[Γ,N B self := e : com]]η ψ =(∨N ′′≤ΓN ′• e isExactly N ′′ ∧ ψ[e, e.x/self , x ])

where x = dom(Γ.attr N ′′)

The weakest precondition that guarantees that self := e establishes ψ is a disjunction over thesubclasses N ′′ of the type N ′ of e. The test e isExactly N holds when the value of e is an objectof class N , but not of any of its subclasses. Each disjunct requires ψ to hold when self takes thevalue e, and the attributes x of N ′′ take the value e.x . There is no need to check that e is noterror because error isExactly N ′′ is false, for all N ′′. If self is assigned an object of the currentclass, the semantics simplifies to e 6= error ∧ ψ[e, e.x/self , x ].

The semantics of specification statements is similar to Morgan’s definition:

[[Γ; x : T B x : [ψ1, ψ2] : com]]η ψ = ψ1 ∧ (∀ x : T • ψ2 ⇒ ψ)

The semantics of control constructs and blocks is standard. They appear in Table 3.8.

3.3. SEMANTICS 31

3.3.4 Programs and method calls

The meaning of a complete program is the meaning of its main command in a proper typingenvironment Γ that includes the global variables x of the command c. The typing environment Γis extracted by the function VDecs.

[[Γ,main B c : com]]η = f Γ = ((VDecs cds main); x : T )η = Meths Γ cds

[[∅; x : T B cds • c : program]] = f

The environment η records the methods available for the object of the classes declared in cds. Thisenvironment is extracted from the sequence of class declarations cds by the function Meths.

The semantics of method calls cannot rely on the copy rule due to dynamic binding. To definethe semantics of method call, we need to consider all methods that could be called; an environmentis used to record the meaning of these methods.

We assume there is an enumeration (Ni ,mi), with i ≥ 1, of methods declared in a programcds • c. In the sequence (Ni ,mi), a method is listed after all those it can call. If a method hasseveral definitions, then a definition in a superclass is listed before one in a subclass. The meaningof a method (Ni ,mi) in this sequence depends only on the meaning of methods (Nj ,mj ), with j < i .

We define Meths Γ cds to be the last of a sequence of environments ηi . The first environmentis η0; for all classes N in Γ.cnames \ {object} and m in dom(Γ.meth N ), it is defined as follows.

η0 N m = (vres me : N ; pds • abort), where pds = Γ.meth N m

We also define η0 object = ∅. In order to define ηi from ηi−1, we establish the semantics of themethod (Ni ,mi) to be associated to (N ,mi), for all N ≤Γ Ni . A method (N ,mi) is available in Ni

and in all subclasses of Ni . A redefinition of mi in class N , a subclass of Ni , occurs in a positionj of the sequence of methods, with j > i , and the meaning of mi is recorded in ηj N mi . Thedefinition for these is the following.

ηi N = ηi−1 N ⊕ {mi 7→ µηi−1mi

(vres me : N ; pds • meI Γ′ N m c)}

The parameterised command (pds • c) is the body of (Ni ,mi), and⊕ denotes the function overridingoperator. The locals field of the typing environment Γ′, differently from that of Γ, includes theattributes of N , the parameter me, and the variables declared by pds. Accesses to attributes of Nor calls to methods of N in c need to be made through me. Recursive calls receive the adequateextra argument. These changes are performed by the function meI [22]. For instance, if x and mare an attribute and a method of N , respectively, after the application of meI they become me.xand me.m. Only free occurrences of attributes of N are changed by meI ; occurrences of self arereplaced with me.

32 CHAPTER 3. ROOL AND LAWS

The semantics of the explicit recursion construct uses fixpoints.

[[Γ B µY c : com]]η = f

[[Γ B rec Y • c end : com]]η = f

Similarly to a method body, the body of a recursion construct is regarded as a context. The contexthere is a function from commands to commands; µY is the least fixpoint of c, as a function of Y .The lattice for this fixpoint is that of monotonic predicate transformers in the state space [[Γ,N ]],where N is the current class.

We present the semantics of method calls le.m(e). The method to be applied is given by theenvironment η, according to the dynamic type of le in a particular state. For all subclasses N ′ ofthe static type N ′′ of le, the parameterised command η N ′ m has the form (vres me : N ′; pds • c).We define fN ′ to be [[Γ,N B (vres me : N ′; pds • c)((N ′)le, e) : com]]η. The cast (N ′)le is neces-sary because the me parameter of η N ′ m is passed by value-result and has type N ′. We define[[Γ,N B le.m(e) : com]]η ψ to be fN ′ ψ. Thus, the semantics of method calls is the disjunctionof (le isExactly N ′ ∧ fN ′ ψ), over the possible classes N ′.

[[Γ,N B (η N ′ m)((N ′)le, e) : com]]η = fN ′ all N ′ ≤Γ N ′′, for N ′′ the type of le

[[Γ,N B le.m(e) : com]]η ψ = (∨N ′≤ΓN ′′• le isExactly N ′ ∧ fN ′ ψ)

The predicate is false in states where le is null as null isExactly N ′ = false. In order for thisequation be satisfied (η N ′ m) must be typable in Γ,N . Attributes in the body of m are accessedby the me parameter. These attributes are not necessarily visible in the context of a method call,thus references to them are only typable in the extended typing system.

3.4 Refinement

The objective of refining a program is to derive an efficient and executable program from an initialspecification. In rool, this initial specification can range from a specification statement—as intraditional refinement calculi—with an empty sequence of class declarations, to a program, withan arbitrary number of class declarations. Even if we begin the refinement with a specificationstatement, typically the objective is to obtain a program that possibly uses classes. So, we need toestablish a refinement relationship between programs.

We refine a program by refining its command part and its class declarations.

Definition 1 For sequences of class declarations cds and cds ′, commands c and c′ with the samefree variables x : T, define (cds • c) v (cds ′ • c′) if and only if, for all ψ,

[[∅, x : T B (cds • c) : program]] ψ ⇒ [[∅, x : T B (cds ′ • c′) : program]] ψ

3.5. LAWS 33

This is the standard definition for refinement in the context of a weakest precondition semantics.The refinement of commands has already been presented by Cavalcanti and Naumann [22]; theyproved that the command constructors of rool are monotonic with respect to their constituentscommands (Theorem 3 in [22]).

The refinement of a class is related to data refinement because a class is a data type. We mustconsider the refinement of a class declaration cd1 by another class declaration cd2 in a contextof a sequence of class declarations cds. Class names play an important role in object-orientedprograms. For instance, classes with distinct names describe different types even if they have thesame attributes and methods.

If cd1 and cd2 declare classes with the same name, cd1 is refined by cd2 in the context ofcds, if and only if, cds cd1 and cds cd2 are well formed, and for all commands c, we havethat (cds cd1 • c) v (cds cd2 • c).

On the other hand, if cd1 declare a class with a distinct name from those present in cds, thedeclaration of cd1 can appear in the same program representing a different design that implementsthe same functionality. In this situation, we have that (cds • c) v (cds cd1 • c).

Theorem 1 The command constructors are monotonic with respect to refinement of their con-stituent commands.

The proof of this theorem is based on two lemmas. The first lemma (Lemma 15 in [22])establishes refinement between parameterised commands; the second lemma (Lemma 16 in [22])establishes that the weakest preconditions defined are monotonic predicate transformers.

3.5 Laws

In this section we present some of the laws of rool. The whole set of laws can be found inAppendices D and E. These laws were firstly presented in [14, 15, 33]. We have proved all thelaws correct against the weakest precondition semantics of rool. The proofs can be found inAppendices F and G. We also need to apply class refinement, which is a notion related to datarefinement. This is achieved by the application of the simulation laws presented in the next section.

In the laws we write ‘(→)’ when some conditions must be satisfied for the application of thelaw from left to right. We also use ‘(←)’ to indicate the conditions that are necessary for applyinga law from right to left. We use ‘(↔)’ to indicate conditions necessary in both directions.

3.5.1 Simulation Laws

Simulation links concrete and abstract states, allowing us to change the representation from abstractto concrete. A formula, known as coupling invariant, relates existing (abstract) variables to new(concrete) ones.

34 CHAPTER 3. ROOL AND LAWS

Traditional techniques of data refinement deal with modules that encapsulate variables. This isthe case when we deal with private attributes of a class. Law 〈private attribute-coupling invariant〉in what follows allows us to change private attributes in a class, relating them with new attributes.The application of this law changes the bodies of the methods declared in the class. The changesfollow the traditional laws for data refinement [64]. Some of these laws are presented in Appendix D.By convention, the attributes denoted by x are abstract, whereas those denoted by y are concrete.The coupling invariant CI relates abstract and concrete attributes. The notation CI (mts) indicatesthe application of CI to each of the methods in mts: applying CI changes the methods accordingto the laws of data refinement [64], that is, guards are augmented in order to assume the couplinginvariant and every command is extended by modifications to the concrete variables so that theymaintain the coupling invariant. We write pri a : T ; ads to denote the attribute declarationpri a : T and all declarations in ads; whereas mts stands for declarations of methods and initialisers.The symbol ¹ indicates that this law involves a simulation between attributes that are related bythe coupling invariant CI .

Law 〈private attribute-coupling invariant〉class A extends C

pri x : T ; adsmts

end

cds • c

¹CI

class A extends Cpri y : T ′; adsCI (mts)

end

cds • c

2

Law 〈superclass attribute-coupling invariant〉 below allows us to change attributes in a class,relating them with already existing attributes by means of a coupling invariant. The applicationof this law changes the bodies of the methods declared in the class and in its subclasses. Similarlyto the previous law, the changes follow the traditional laws for data refinement [64]. The notationCI (cds ′) indicates that CI acts on the class declarations of cds ′. The application of CI to a classdeclaration changes the methods of such a class according to the laws of data refinement [64], asin the previous law. In order to apply this law the coupling invariant CI must refer only to publicand protected attributes in adsA, since it is used in the subclasses of A.

Law 〈superclass attribute-coupling invariant〉class A extends C

adsAmts

end

cds ′ cds

¹CI

class A extends CadsCCI (mts)

end

CI (cds ′) cds

3.5. LAWS 35

provided

CI refers only to public and protected attributes in adsA;

cds ′ only contains subclasses of A

cds contains no subclasses of A

2

While law 〈private attribute-coupling invariant〉 is a standard simulation law for modules, law〈superclass attribute-coupling invariant〉 is an original contribution of a joint work presented in [17,16]. It is worth emphasising that the simulation relations are sound, which means that, for well-formed contexts cds • c, if cds1 ¹cds,c,CI cds2, then (cds cds1 • c) v (cds cds2 • c). This has beenproved in [25] for law 〈private attribute-coupling invariant〉.

The law 〈Data refinement—variable blocks with initialisation〉, in what follows, is a data refine-ment law for variable blocks. It considers variable blocks whose bodies start with an initialisationof the abstract variables.Law 〈Data refinement—variable blocks with initialisation〉

var vl ; avl • avl : [true, init ]; c1 end

v

var vl ; cvl • cvl : [true, (∃ avl • CI ∧ init ]; c2 end

provided

c1 ¹ c2

The variables of cvl are not free in init and c1, and are not in avl ;

The variables of avl are not free in c2;

2

The command c2 is a data refinement of command c1 and can be calculated from the originalcommand c1, the abstract variables avl , the concrete variables cvl , and the coupling invariant CIusing data refinement laws [64]. The law 〈Data refinement—variable blocks with initialisation〉 isbased on a similar law presented in [20].

The laws presented in this section allows us to change the representation of attributes andvariables. This is useful, for instance, to relate attributes of a class with attributes of another class.It

3.5.2 Laws of Commands

In this section we present the programming laws of rool that apply to the commands of thelanguage, which are regarded as small grain constructs. The whole set of laws for commands can

36 CHAPTER 3. ROOL AND LAWS

be found in Appendix D.

Assigning a left expression to itself leaves the state of a program unchanged, so it is equivalentto skip. We require the left expression not to be error, otherwise the program aborts.

Law 〈:= skip〉 If le 6= error, then (le := le) = skip 2

Branches of an alternation can be eliminated if their guards are always false.

Law 〈if elim〉 If i ranges over 1..n and ¬ (ψ ∧ ψi), for all i , then

if ψ →

if ψ → c

[] ([]i • ψi → ci)

fi

[] ([]j • ψj → cj )fi

=if ψ → c

[] ([]j • ψj → cj )

fi

2

If miracle precedes another command, such a composition behaves as miracle, in other words,miracle is a left zero of sequential composition. The same is true for abort.

Law 〈; -miracle left zero〉 miracle; c = miracle 2

The sequential composition of two assignments can be combined into just one assignment. Thenotation e2[e1/le] stands for the replacement of every free occurrence of le in e2 with e1.

Law 〈; − := combination〉 (le := e1; le := e2) = (le := e2[e1/le]) 2

We can move a variable declaration which is present in a branch of an alternation to outsidethe alternation, provided the variable does not occur free in the guards.

Law 〈var-; if dist〉 If i ranges over 1..n and x is not free in ψi , thenif []i • ψi → (var x : T • ci end) fi = var x : T • if []i • ψi → ci fi end

2

The relation between angelic and demonic variable blocks is stated in the following law. Theangelic variable block avoids abortion by choosing a value to x equal to that of e. The local variableblock avoids a miracle by choosing a value to x equal to that of e.

3.5. LAWS 37

Law 〈avar - var relationship〉 If x is not free in e, thenavar x : T • {x = e}; c end = var x : T • [x = e]; c end 2

A very useful command law in the context of object-oriented programs deals with the eliminationof method calls. When there are no redefinitions or visibility concerns, the elimination of a methodcall can be characterised by the copy rule.

Law 〈method call elimination〉Consider that the following class declaration

class C extends Dadsmeth m = pcmts

end

is included in cds. Then

cds,A B le.m(e) = {le 6= null ∧ le 6= error}; pc[le/self ](e)

provided

(↔) m is not redefined in cds and does not contain references to super; and all at-tributes which appear in the body pc of m are public.

2

Using the above law, we can replace a call le.m with the body of the method m, which isdefined by the parameterised command pc, substituting every occurrence of self for le. If a privateattribute of class C appears in the body of m, this substitution would cause a compilation error dueto visibility concerns. This is the reason for requiring the attributes to be public. We also requirethat super does not appear inside m because, after class elimination, the parameterised commandwe obtain is located inside a different class from the one that declares the method. These classesmay have different superclasses leading to a compilation error or to a behaviour distinct from thatof the method call. A method call le.m(e) aborts when le is null or error. On the right-handside, we have the assumption {le 6= null ∧ le 6= error}, which also aborts when le is null or error.This assumption behaves like skip when le is not null nor error.

The law 〈command refinement-class refinement〉 in what follows states that the refinement of acommand in a class leads to the refinement of such a class as a whole. This can be expressed bythe following law.

38 CHAPTER 3. ROOL AND LAWS

Law 〈command refinement-class refinement〉class N

adsn ;meth m = (pds • c1)mtsn

end

vcds,c

class Nadsn ;meth m = (pds • c2)mtsn

end

provided

c1 v c2

2

This law is a consequence of the theorem presented in Section 3.4 and class refinement.

3.5.3 Laws of Classes

The following laws apply to classes, but they are still basic in the sense that more elaborate laws,which can be applied to practical program transformation, need to be derived. Here we use thenotation cd1 =cds,c cd2 as an abbreviation to (cds cd1 • c) = (cds cd2 • c), meaning that the classdeclarations cd1 and cd2 are equivalent in the context of the sequence of class declarations cds andmain command c. The whole set of laws for classes can be found in Appendix E.

The notation B .a, which appears in provisos, denotes the use of the name a by means ofexpressions of type B , strictly. The subclass relation is denoted by ≤; it is an abbreviation for ≤Γ,where Γ is the typing environment corresponding to the relevant sequence of class declarations.

The following law allows changing the visibility of attributes from private to public. Applyingthis law from left to right makes a private attribute public; in this direction there are no provisos.For applying this law from right to left, the attribute cannot be used anywhere outside the classwhere it is declared; this is required by the proviso.

Law 〈change visibility: from private to public〉class C extends D

pri a : T ; ads;mts

end

=cds,c

class C extends Dpub a : T ; ads;mts

end

provided

(←) B .a, for any B ≤ C , does not appear in cds or c.

2

Using the following law, we can remove a method from a class. In order to remove a methodfrom a class, it cannot be called by any class in cds, in the main command c, nor inside class C .

3.6. CONCLUSIONS 39

For applying this law from right to left, the method m cannot be already declared in C nor in anyof its superclasses or subclasses. In other words, we can always introduce a new method in a class.

Law 〈method elimination〉class C extends D

ads;meth m = (pds • c) mts

end

=cds,c

class C extends Dads;mts

end

provided

(→) B .m does not appear in cds, c nor in mts, for any B such that B ≤ C ;

(←) m is not declared in mts nor in any superclass or subclass of C in cds.

2

As already said, the whole set of laws can be found in Appendices D and E.

3.6 Conclusions

In this chapter we presented the language rool. Besides the usual commands expected in object-oriented languages, rool includes specification statements as commands, supporting reasoningabout object-oriented programs. The semantics of rool is based on weakest preconditions. Wediscussed the context in which program refinement holds. Finally, we presented some programminglaws of rool.

40 CHAPTER 3. ROOL AND LAWS

Chapter 4

Compositional Refactorings

Refactoring is the process of restructuring a program without changing its behaviour [69, 42]. Inpractice, the verification that the behaviour of a program is not changed after refactoring relies onlooking for type errors detected by means of compilation and also on running test suites. The wordrefactoring is also used to mean a change that is made to a program.

In this chapter we present a list of refactoring rules written in rool. These rules are inspired bythe work presented by Fowler [42]. Strictly, some of them are not the same refactorings presentedby Fowler; differences between them are discussed along the presentation. The (copy) semantics ofrool is the main cause of differences between our refactorings and Fowler’s ones. As a consequence,in our refactorings, we restrict type of parameters to be basic. The refactorings we present herecover most of the refactorings presented by Opdyke in his pioneering work [69], whose focus is theautomated refactoring of C++ programs. Indeed, most of the low-level refactorings presented byOpdyke are captured by the laws of commands and classes of rool that appear in Chapter 3, andAppendices D and E. For instance, the refactoring create member variable presented by Opdyke [69,p. 56] is equivalent to the Law 83 〈attribute elimination〉 of rool, when applied from right to left.More elaborate refactorings proposed by Opdyke are also presented by Fowler, like the one foradding a function argument.

In this chapter we present refactoring rules whose application does not affect the context of theclasses being refactored. In other words, the fact that these classes are being modified does notaffect classes other than those to which we apply the refactoring rule. Also, the application of therefactoring rule does not affect the main program. In this sense, we say that these refactorings arecompositional, even though we may impose restrictions (side-conditions) on classes that are notbeing refactored and on the main program.

We present refactorings that deal mainly with methods and attributes. These basic refactoringscan be used in the derivation of others. We exemplify this by the proof of a refactoring that allowsthe extraction of classes. Refactorings that deal with commands are also presented in this chapter,but their proofs are relegated to Appendix A.

42 CHAPTER 4. COMPOSITIONAL REFACTORINGS

4.1 Notation

The refactoring rules are described by means of two boxes written side by side, along with where

and provided clauses. We use the where clause to write abbreviations. The provisos for applyinga refactoring rule are listed in the provided clause of the rules. The left-hand side of the rulepresents the class or classes before the rule application; the right-hand side presents the classesafter the rule application: the transformed classes. We must note, however, that many of therefactoring rules are equalities and can be applied in both directions. The equivalence of sequencesof class declarations cdsLHS and cdsRHS—which appear, respectively, on the left-hand side and onthe right-hand side of a rule—is denoted by cdsLHS =cds,c cdsRHS . This is an abbreviation for thebehavioural equivalence: cdsLHS cds • c = cdsRHS cds • c. The refinement of a sequence of classdeclarations cdsLHS by a sequence of class declarations cdsRHS is denoted by cdsLHS vcds,c cdsRHS .The notation cds,N B c asserts that c is a command that appears in the body of a method in classnamed N , whose declaration is in cds.

In class declarations, we write pri a : T ; ads to denote the attribute declaration pri a : T andall additional declarations in ads. This declaration is similar for protected and public attributes.Also, mts stands for declarations of methods. A method m is defined by means of a parameterisedcommands in the form (pds • c). The parameters of m are pds, and the names of such parametersinside m is indicated by α(pds).

We also use the notation c[c′] to express that in the command c there may be occurrences of thecommand c′; later occurrences of c[c′′] denote the command obtained by replacing the occurrencesof c′ with c′′. Similarly, the notation c[exp] expresses that there might be occurrences of theexpression exp in the command c. In the same way, exp1[exp2] expresses that exp2 may occur inthe expression exp1. Also, we express that a command c1 and an expression e1 may occur insidea command c by using the notation c[c1][e1]. Meta-variables with different names denote differentvalues and variables.

The notation B .m refers to uses of the name m via expressions of type B . For instance, if wewrite that B .m does not appear in mts, we mean that mts contains no expressions such as e.a, forany e of type B , strictly.

For the derivation of the refactoring rules, we assume that the conditions that appear in eachrule are satisfied. Also, in the derivations, we write ‘(l/r)’ or ‘(r/l)’ after the name of a law toindicate that we apply the law from left to right or from right to left, respectively. If a law isapplied more than once, we also indicate this with the number of times between parentheses, likein (2x), which indicates two applications of the law.

4.2. REFACTORING RULES 43

Rule 4.1 〈Extract/Inline Method〉class A extends C

ads;meth m1 = (pds1 • c1[c2[a]])mts

end

=cds,c

class A extends Cads;meth m1 = (pds1 • c′1)meth m2 = (pds2 • c2[α(pds2)])mts ′

end

where

c′1 = c1[self .m2(a)/c2[a]]

mts = mts ′[c2[a]/self .m2(a)]

a is the finite set of free variables of command c2, not including attributes of class A;

provided

(↔) Variables in a have basic types;Parameters in pds2 must have types the same types as those of variables in a;

(→) m2 is not declared in mts nor in any superclass or subclass of A in cds;

(←) m2 is not recursively called;B .m2 does not appear in cds, c nor in mts, for any B such that B ≤ A.

4.2 Refactoring Rules

In this section we present some compositional refactoring rules. The first rule we present is usedto extract or inline a method. We also present rules for moving methods and attributes. Anotherrule allows us to pull up or push down a method in a hierarchy. Finally, we present a rule for classextraction.

Each refactoring rule is presented along with an explanation of the rule itself and of its provisos.Then, we present its derivation.

4.2.1 Extract and Inline Method

Rule 4.1, when considered from left to right, coincides with the refactoring Extract Method presentedby Fowler [42, p. 110], whereas the application in the reverse direction corresponds to the refactoringInline Method [42, p. 117]. It turns a command c2, which is present in a method m1, into a newmethod m2. Occurrences of the command c2 in the original method m1 are replaced by calls to thenewly introduced method.

The meta-variable a represents a list containing the free variables that appear in the commandc2 of method m1 which are not attributes of class A. On the left-hand side of this rule, c1[c2[a]]represents the command c1, which may have occurrences of the command c2, which in turn may

44 CHAPTER 4. COMPOSITIONAL REFACTORINGS

have occurrences of a. The class C that appears in the extends clause, and in the others thatfollow, is present in the sequence of class declarations cds or is the class object.

On the right-hand side of this rule, the method call self .m2(a) replaces the occurrences of thecommand c2[a] in the command c1 of method m1; the resulting command is c′1. In the command c2

of method m2, the variables indicated by a are replaced with the parameters α(pds). If a variableis only read in c2, it could be passed as a value argument. A variable that is only written could bepassed as result argument. Variables that are both read and written must be passed as both valueand result arguments. The free variables, represented by a, that are passed as arguments in thecall to m2 may involve all arguments of method m1 as well as local variables that appear in c2. Ofcourse, all the free variables that appear in c2 must become parameters of m2.

The method m2 must be new: not declared in a superclass of A, in A itself, nor in any of itssubclasses. To apply this rule, we require the types of variables in a to be basic. Also parameters inpds2 must have the same types as those of a. Applying this rule from right to left replaces methodcalls to m2 with the body of this method and removes m2 from class A. To apply this rule in thisdirection, there must be no recursive calls in the method m2 (note that this is not a limitation inpractice because c2 can be a recursive command of the form rec X • c3 end). Also, the method m2

cannot be called in cds, c nor in mts.

The rule 〈Extract/Inline Method〉 improves the legibility and maintenance of a class. If a com-mand is present in several methods of a class, this command can be extracted into a new method.The methods in which the command occurred can then just call this new method. Consequently,they become shorter than they were before the rule application; this improves legibility. More-over, changing a command that appears in several methods can lead to inconsistency if one ofthe methods is not properly modified, whereas changing only one method is easier. This improvesmaintainability.

The rule 〈Extract/Inline Method〉 as we present here differs from the corresponding refactoringspresented by Fowler [42], since we restrict the types of the variables passed as argument to bebasic types. This limitation is a consequence of the laws used for introduction of parameterisedcommands from an arbitrary command. This is the only difference between our rule and Fowler’sone.

Derivation. We begin the derivation with the class A that appears on the left-hand side. Weassume that the required conditions for the application of this rule hold. However, it is not possibleto have a fully general derivation, in the sense that we do not define a parameter for the methodbeing extracted, rather we have to introduce a parameterised command along with a specific pa-rameter passing mechanism in order to be able to conduct the proof. Moreover, in the derivationwe consider that the set of variables a has just one element, a variable named a. Also, we considerthat such variable is only read, implying that the value parameter passing mechanism is the oneapplicable for the parameter to be defined in the extracted method. The derivation for a result

4.2. REFACTORING RULES 45

parameter is similar.

class A extends Cads;meth m1 = (pds1 • c1[c2[a]])mts

end

We introduce a method named m2 in class A by using the Law 90 〈method elimination〉, fromright to left. This requires that the method to be introduced is not declared in the superclass of theclass to which the law is applied, in the class itself nor in any of its subclasses. As the refactoringrule requires the same conditions to be satisfied, we can apply Law 90 〈method elimination〉.

= Law 90 〈method elimination〉 (r/l)

class A extends Cads;meth m1 = (pds1 • c1[c2[a]]) ¢

meth m2 = (val arg : T • c2[arg ])mts

end

The command c2 that is present in the method m1 also appears in the method m2. Our aimis to introduce a call to the method m2. We introduce a parameterised command that is appliedto the argument a by using Lemma 9 presented in Appendix C. The occurrences of variable a,in command c2, are replaced with the parameter arg . The symbol ¢ indicates the focus of ourrefinement. This lemma requires that the argument that is applied to the parameterised commandis not a method call target. Consequently, there is no sense in having as argument an object onwhich we cannot call a method inside the parameterised command. For this reason we restricted ato have basic type.

= Lemma 9

(val arg : T • c2[arg ])(a)

46 CHAPTER 4. COMPOSITIONAL REFACTORINGS

The class A now is as follows.

class A extends Cads;meth m1 = (pds1 • c1[(val arg : T • c2[arg ])(a)]) ¢

meth m2 = (val arg : T • c2[arg ])mts

end

The parameterised command that occurs in command m1 is the same as that of method m2.By using Lemma 1 (Appendix C), from left to right, we introduce in m1 a call to m2, obtaining thefollowing class.

= Lemma 1

class Aads;meth m1 = (pds1 • c1[self .m2(a)])meth m2 = (val arg : T • c2[arg ])mts

end

This completes the derivation for a value parameter. 2

The derivation for an arbitrary number of parameters is similar, but it involves the applicationof Law 66 〈pcom merge〉. Similarly to the inline method refactoring presented by Fowler [42, p.117], we replace each call to the method we inline with the method body. Also, we remove themethod definition.

The method moreThanFiveLateDeliveries is public and it is the target of refactoringInline Method described by Fowler [42, p. 117]. However, there is no restrictions on calls to suchmethod around the program. Maybe, this is consequence of the refactoring strategy that relies onprogram compilation for detecting errors such as calling a method that is not declared in the classof the target object. Similarly, the Inline refactoring implemented in the Eclipse IDE [37] doesnot give any alert to the user about calls to a public method that is target of this refactoring. Onlyin compilation, which is accomplished just after the refactoring application, errors are detected.During the refactoring application, there is no check that, when we inline a public method, it maylead to errors because such public method, for instance, may access attributes of the class in whichit is declared. It is necessary to check this condition to allow a correct refactoring application.

4.2.2 Move Method

One of the most disseminated practices in the development of object-oriented programs is mov-ing methods between classes. It is usually required when classes are highly coupled. Moving

4.2. REFACTORING RULES 47

methods between classes helps to make them simpler and clearer, improving legibility. The rule〈Move Method〉 (Rule 4.2) allows us to move a method that already indirectly reads and writes anattribute of the class to which the method is being moved.

On the left-hand side of this rule, the method m1 of A reads and writes to the attribute xof B by means of its get and set methods. The method calls occur inside the command c1 of themethod m1 and have as target the attribute b. The variable aux holds the result of the call tothe method getX of B . Such variable may occur on the right-hand side of an assignment to anexpression le. In the command c1, there may also be occurrences of the parameters that appear inpds, which is indicated by α(pds), where α(pds) gives the list of parameter names declared in pds.For instance, if pds is the declaration (val x : T , res y : T ), the list given by α(pds) is x , y . Theclass B on the left-hand side declares no method like m1 of the class A.

On the right-hand side of this rule, the method m1 in A becomes just a delegating method: itcalls the corresponding method of class B and passes the parameters in pds as arguments. Theclass B declares a method called m1 similar to the method m1 that appears on the left-hand sideof the rule. The attribute x is accessed by means of the get and set methods declared in B itself.

To apply this rule, we assume that b 6= null and that b 6= error along the lifetime of an objectof type A, otherwise a call to the method m1 of the class A would abort because this methodcalls methods of the class B . So, the predicate b 6= null ∧ b 6= error is an invariant for class A.We assume this based on the condition about the initialiser of class A: the proviso requires thatthe attribute b is initialised with an object of type B and the initialiser terminates. Also, theparameters arg1 and arg2 must have basic types.

The notion of class invariant we use is similar to those of Meyer [62] and Opdyke [69]. Accordingto Meyer, an invariant for a class is a set of assertions that every instance of such a class will satisfyat all observable states, that is, after its creation, and before and after every call to a class method.In rool, we write invariants as predicates.

In order to apply this rule from left to right, the method m1 must not be declared in B , norin any of its superclasses or subclasses, and there should be no occurrences of super in m1 Also,attributes declared in A are not accessed in m1, and methods declared in A are not called inside m1.The reason for the last two provisos is that, to move a method in which there are occurrences ofattributes or calls to methods of the source class (the one that introduces the method), it wouldbe necessary to pass self as argument in the calls to the method of the target class (the class towhere we move the method). In this way, the parameter declaration of the method in the targetclass would include an additional parameter: one whose type is the source class. Also, clients of thetarget class that call the method that was moved would also need to declare an object of the sourceclass and pass such an object as argument in the method call. To avoid the additional parameter,

48 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.2 〈Move Method〉

class A extends Cpri b : B ; adsa ;meth m1 = (pds •

c1[var aux : T • self .b.getX (aux );le := exp1[aux ] end,

self .b.setX (exp2), α(pds)])new = self .b := new Bmtsa

end

class B extends Dpri x : T ; adsb ;meth getX =

(res arg ′ : T • arg ′ := self .x )meth setX =

(val arg ′ : T • self .x := arg ′)mtsb

end

=cds,c

class A extends Cpri b : B ; adsa ;meth m1 = (pds • self .b.m1(α(pds)))new = self .b := new Bmtsa

end

class B extends Dpri x : T ; adsb ;meth getX =

(res arg ′ : T • arg ′ := self .x )meth setX =

(val arg ′ : T • self .x := arg ′)meth m1 = (pds •

c1[var aux : T • self .getX (aux );le := exp1[aux ] end,

self .setX (exp2), α(pds)])mtsb

end

where

α(pds) gives the names of parameters in pds;

provided

(↔) b 6= null ∧ b 6= error is an invariant of A;

arg1 and arg2 have basic types;

(→) m1 is not declared in mtsb nor in any superclass or subclass of B ;

super does not appear in m1;

self .a does not appear in m1, for any a declared in adsa ;

self .p does not appear in m1, for any method p in mtsa ;

(←) N .m1 does not appear in mtsb , cds, or c, for any N such that N ≤ B .

we restrict the method m1 not to access attributes nor call methods declared in A.

For applying this rule from right to left, the method m1 must not be called in mtsb , cds, or c,as this method is removed from B .

4.2. REFACTORING RULES 49

Derivation. We begin the derivation by introducing a method m1 in class B . Such methodis similar to that of class A, but it reads and writes the attribute x by means of the get andset methods already present in B . In the derivation, it is not possible to deal with an arbitraryparameter declaration pds in method m1, since pds may have any number of parameters withdifferent parameter passing mechanisms. So, it is necessary to have a specific list of parameters.We define the list val arg1 : T1; res arg2 : T2 to be the parameters of such method. This does notmean a lack of abstraction, as the derivation for a longer parameter list is similar. We also changethe visibility of attribute x from private to public.

class B extends Dpri x : T ; adsb ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsb

end

= Law 90 〈method elimination〉 (r/l), Law 85 〈change visibility: from private to public〉 (l/r)

class B extends Dpub x : T ; adsb ;meth getX = (res arg ′ : T • arg ′ := self .x )meth setX = (val arg ′ : T • self .x := arg ′)meth m1 = (val arg1 : T1; res arg2 : T1 •

c1[var aux : T • self .getX (aux ); le := exp1[aux ] end, self .setX (exp2), arg1, arg2]mtsb

end

In the method m1 of class A we introduce the same parameterised command as the one thatdefines the method m1 of class B . For this, we first introduce a parameterised command with aformal result argument that is applied to arg2.

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 •

c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg1, arg2])

new = self .b := new B()mtsa

end

50 CHAPTER 4. COMPOSITIONAL REFACTORINGS

= Lemma 10

(res arg2 : T2 •c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg1, arg ′2])(arg2)

We introduce a parameterised command with a formal value argument that is applied to theargument arg1. Then we merge the two parameterised commands.

= Lemma 9

(val arg1 : T1 • (res arg2 : T2 •c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg ′1, arg′2])(arg2))(arg1)

= Law 66 〈pcom merge〉 (r/l)

(val arg1 : T1; res arg2 : T2 •c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg ′1, arg2])(arg1, arg2)

In class A, we introduce the class invariant {b 6= null ∧ b 6= error} as the last command ofmethod m1. Then we move this assumption to the beginning of m1.

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 •

(val arg1 : T1; res arg2 : T2 •c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg ′1, arg2])(arg1, arg2)new = self .b := new B()mtsa

end

4.2. REFACTORING RULES 51

= Law 107 〈introduce class invariant〉 (l/r)

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 •

(val arg1 : T1; res arg2 : T2 •c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg ′1, arg2])(arg1, arg2){b 6= null ∧ b 6= error}new = self .b := new B()mtsa

end

Then, we eliminate the call to getX on self .b that appears in c1.

= Law 95 〈method call elimination〉 (l/r)

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 •

(val arg1 : T1; res arg2 : T2 •c1[var aux : T • {self .b 6= null ∧ self .b 6= error}

(res arg ′ : T • arg ′ := self .b.x )(aux ); le := exp1[aux ] end,self .b.setX (exp2), arg ′1, arg2])(arg1, arg2){b 6= null ∧ b 6= error}

new = self .b := new B()mtsa

end

= Law 53 〈assumption before or after command〉 (r/l)

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 •{b 6= null ∧ b 6= error}(val arg1 : T1; res arg2 : T2 •c1[var aux : T • {self .b 6= null ∧ self .b 6= error}

(res arg ′ : T • arg ′ := self .b.x )(aux ); le := exp1[aux ] end,self .b.setX (exp2), arg ′1, arg2])(arg1, arg2)

new = self .b := new B()mtsa

end

Now we introduce the call to method getX on self .b in command c1.

52 CHAPTER 4. COMPOSITIONAL REFACTORINGS

= Law 95 〈method call elimination〉 (r/l)

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 •{b 6= null ∧ b 6= error}(val arg1 : T1; res arg2 : T2 •c1[var aux : T • self .b.getX (aux ); le := exp1[aux ] end,

self .b.setX (exp2), arg ′1, arg2])(arg1, arg2)new = self .b := new B()mtsa

end

With the sequential composition constituted by the assumption and the parameterised commandapplied to the argument arg1, we can introduce a call to method m1 of class B . Notice that theparameterised command is the same as the one used in the definition of method m1 of class B .

= Law 95 〈method call elimination〉 (r/l)

class A extends Cpri b : B ; adsa ;meth m1 = (val arg1 : T1; res arg2 : T2 • self .b.m1(arg1, arg2))new = self .b := new B()mtsa

end

Finally, by applying Law 85 〈change visibility: from private to public〉, from right to left, wechange the visibility of attribute x of class b back to private . This finishes the derivation of therefactoring rule 〈Move Method〉. 2

Notice that we have just considered one attribute in class A. But we could also deal with anarbitrary number of attributes, each of them with appropriate get and set methods. The proof forthis situation is similar to the one we have presented here.

Roberts [74] states in the postcondition of his refactoring for moving methods between classesthat the moved method can refer to attributes of its original class. For this, the method in the newclass must take an additional parameter for objects of the original class. We have not presented thisrefactoring with such additional parameter because rool has a copy semantics. As a consequence,if self is an argument in the call to the moved method, any modification to attributes of the originalclass is not reflected in the object that originates the call to the moved method. Indeed, in our rulethe types of the parameters of parameterised command we introduce in derivation are required tobe basic.

4.2. REFACTORING RULES 53

4.2.3 Move Attribute

Moving attributes between classes is also a common activity during program development. If anattribute is used by methods of another class—through get and set methods—more than by thosemethods of the class in which it is declared, then such an attribute probably belongs to that otherclass; it is intrinsic to the concept described by another class.

We can apply rule 〈Move Attribute〉 (Rule 4.3) for moving private attributes between classes.It moves an attribute x of a class A to a class B , when applied from left to right. In A, insteadof x , we end up with an attribute of type B . When applied from right to left, we move x from Bto A.

The class A, from which we move the attribute x , after the application of this rule from left toright, has an attribute b of type B that cannot be declared in A. This attribute is initialised in themethod new of class A with an object of B . The attribute to be moved cannot be already declaredin class B , the target class. Get and set methods are declared in B in order to allow indirect accessto x . These methods cannot be already declared in any superclass of B , in B itself, nor in any ofits subclasses. Commands in A that read and write the attribute x have to use the get and setmethods introduced in B . In order to call these methods in class A, we use the attribute b. Noticethat it leads to changes in A as whole, the new methods are denoted by mts ′a .

After the application of this rule from right to left, the class A has an attribute x of type T .Class B has no declaration of x , and methods getX and setX are removed from this class. Theproviso requires x not to be declared in A nor in any superclass or subclass of A. The methods getXand setX must also not be called inside B , nor in cds or c. Also, we require b 6= null ∧ b 6= error

to be an invariant of class A. This avoids program abortion due to calls to methods of B .

Derivation. We begin with the left-hand side of the rule 〈Move Attribute〉. Our intention is tomove the attribute x from class A to class B .

class Apri x : T ; adsa ;meth m1 = (pds1 • c[le := exp[self .x ], self .x := exp])mtsa

end

class Badsb ;mtsb

end

The first step is to introduce an attribute x of type T in class B . In other words, we introducean attribute that has the same type as the one we want to move. As we required the attribute xmust not to be declared in B , so we can apply the law for attribute elimination, from right to left.Then we change the visibility of x from private to public.

54 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.3 〈Move Attribute〉class A extends C

pri x : T ; adsa ;meth m1 = (pds1 •

c1[le := exp[self .x ],self .x := exp])

meth getX =(res arg : T • arg := self .x )

meth setX =(val arg : T • self .x := arg)

mtsaend

class Badsb ;mtsb

end

=cds,c

class A extends Cpri b : B ; adsa ;meth m1 = (pds1 • c′1)meth getX =

(res arg : T • self .b.getX (arg))meth setX =

(val arg : T • self .b.setX (arg))new = self .b := new B();mts ′a

end

class Bpri x : T ; adsbmeth getX =

(res arg ′ : T • arg ′ := self .x )meth setX =

(val arg ′ : T • self .x := arg ′)mtsb

end

where

c′1 = c1[var aux : T • self .b.getX (aux ); le := exp[aux ] end, self .b.setX (exp)/le := exp[self .x ], self .x := exp]

mts ′a = mtsa [var aux : T • self .b.getX (aux ); le := exp[aux ] end, self .b.setX (exp)/le := exp[self .x ], self .x := exp]

provided

(↔) b 6= null ∧ b 6= error is an invariant of A’

x has basic type;

(→) x is not declared in adsb nor in any superclass or subclass of B ;

b is not declared in adsa nor in any superclass or subclass of A;

the initialiser of class B terminates;

getX and setX are not declared in mtsb nor in any superclass or subclass of B ;

(←) x is not declared in mtsa nor in any superclass or subclass of A in cdss ;

N .getX and N .getX do not appear in mtsb , cds or c, for any N ≤ B .

4.2. REFACTORING RULES 55

= Law 83 〈attribute elimination〉 (r/l), Law 85 〈change visibility: from private to public〉 (l/r)

class Bpub x : T ; adsb ;mtsb

end

Also in class B , using Law 90 〈method elimination〉 twice, we introduce get and set methodsfor the new attribute x .

= Law 90 〈method elimination〉 (r/l)(2x)

class Bpri x : T ; adsb ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsb

end

Now we turn our attention to class A.

class Apri x : T ; adsa ;meth m1 = (pds1 • c[le := exp[self .x ], self .x := exp])meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

We apply the Law 78 〈simple specification〉 so that we can apply the rules for data refinementlater. This law is applied to assignments in which the variable we want to substitute appear on theright-hand side of the assignment. Notice that we want to substitute the attribute x of class A byattribute x of class B .

= Law 78 〈simple specification〉 (l/r)

class Apri x : T ; adsa ;meth m1 = (pds1 • c[le : [le = exp[self .x ]], self .x := exp])meth getX = (res arg : T • arg : [arg = self .x ])meth setX = (val arg : T • self .x , b.x := arg , arg)mtsa

end

56 CHAPTER 4. COMPOSITIONAL REFACTORINGS

In class A we perform a data refinement: we introduce the private attribute b of type B alongwith the coupling invariant self .x = b.x ∧ self .b 6= null ∧ self .b 6= error. The application of thislaw changes specification, assignments, and guards involving the attribute x , which is considered anabstract variable in the context of this data refinement, in the whole class A. Here we concentrateon method m1.

= Law 108 〈private attribute-coupling invariant〉

CI = self .x = b.x ∧ self .b 6= null ∧ self .b 6= errorclass A

pri b : B ;pri x : T ; adsa ;meth m1 = (pds1 • c[le, b.x : [le = exp[self .x ] ∧ CI ], self .x , self .b.x := exp, exp])meth getX = (res arg : T • arg : [arg = self .x ∧ CI ])meth setX = (val arg : T • self .x , self .b.x := arg , arg)mtsanew = self .b := new B()

end

In the specification statement we substitute the expression self .x with b.x , as their relationshipis stated in the coupling invariant CI .

= Predicate calculus

CI = self .x = self .b.x ∧ b 6= null ∧ b 6= errorclass A

pri b : B ;pri x : T ; adsa ;meth m1 = (pds1 • c[le, b.x : [le = exp[self .b.x ] ∧ CI ], self .x , self .b.x := exp, exp])meth getX = (res arg : T • arg : [arg = self .b.x ∧ CI ])meth setX = (val arg : T • self .x , self .b.x := arg , arg)mtsanew = self .b := new B()

end

We assume that the initialiser of class B terminates, so that this invariant is established by themethod new. It is also preserved by other methods because b is an attribute recently introduced andit is not assigned in methods of A. So, we introduce the predicate self .b 6= null ∧ self .b 6= error

as a class invariant. We define classAInv as an abbreviation for this predicate.

4.2. REFACTORING RULES 57

= Law 107 〈introduce class invariant〉 (l/r), Law 53 〈assumption before or after command〉 (r/l)

classAInv = self .b 6= null ∧ self .b 6= errorclass A

pri x : T ; pri b : B ; adsa ;meth m1 = (pds1 • {classAInv};

c[le, b.x : [le = exp[self .x ] ∧ CI ], self .x , self .b.x := exp, exp])meth getX = (res arg : T • {classAInv} arg := self .b.x )meth setX = (val arg : T • {classAInv} self .b.x := arg)new = self .b := new B()mtsa

end

By using Law 69 〈assignment〉, we refine the specification le, b.x : [le = exp[b.x ] ∧ CI ] to theassignment le := exp[b.x ]. The assignment self .x , self .b.x := exp, exp becomes self .b.x := exp, byusing Law 73 〈diminish assignment〉.

v Law 69 〈assignment〉, Law 73 〈diminish assignment〉

CI = self .x = b.x ∧ b 6= null ∧ b 6= errorclass A

pri b : B ;pri x : T ; adsa ;meth m1 = (pds1 • {classAInv}; c[le := exp[self .b.x ], self .b.x := exp]])meth getX = (res arg : T • arg := self .b.x )meth setX = (val arg : T • self .b.x := arg)mtsanew = self .b := new B()

end

As already said, the attribute b was not present in class A before the derivation, and we assignto b an object of class B in the method new. Besides that, we only assign to attributes of theobject denoted by b, not to b itself. Therefore, after the data refinement, a null object is notassigned to b. So, we can assume in all points in method m1 that b is a non-null object. So, theassumption we introduced above is innocuous because the predicate b 6= null ∧ b 6= error is trueat all points of m1 and, consequently, the assumption behaves as skip, which does not affect thebehaviour of m1. We can distribute such assumption in the command c of m1.

58 CHAPTER 4. COMPOSITIONAL REFACTORINGS

= Law 55 〈assumption distribution〉

class Apri x : T ; pri b : B ; adsa ;meth m1 = (pds1 • c[{classAInv} le := exp[self .b.x ], ¢

{classAInv} self .b.x := exp]) (i)meth getX = (res arg : T • {classAInv} arg := self .b.x )meth setX = (val arg : T • {classAInv} self .b.x := arg)new = self .b := new B()mtsa

end

We introduce the local variable aux to which we assign the value of the attribute x of the objectdenoted by b. This assignment is introduced at the end of the variable block.

= Law 25 〈var- elim〉 (r/l), Law 30 〈var- := final value〉 (r/l)

var aux : T • {classAInv} le := exp[self .b.x ]; aux := self .b.x end

The variable aux is new and, for this reason, we can move the assignment to it inside thevariable block. This assignment does not influence other commands.

= Law 59 〈order independent assignment〉

var aux : T • {classAInv} aux := self .b.x ; le := exp[self .b.x ] end

The expression b.x that occurs on the right-hand side of the assignment to aux also occurs inexpression exp. The assignment to aux occurs just before the command le := exp[self .b.x ], thus inthis command we can replace self .b.x with aux .

= Law 60 〈assignment seq comp exp substitution〉 (l/r)

var aux : T • {classAInv} aux := self .b.x ; le := exp[aux ] end

The command aux := self .b.x reads the attribute x of the object denoted by the attribute b.We can use the method getX of class B to get the value of such attribute. To introduce a call togetX , we need a parameterised command. First, we introduce a variable block that is equivalent to aparameterised command with a result parameter as getX . The variable aux is replaced with the newlocal variable. Recall that we defined classAInv to be the predicate self .b 6= null ∧ self .b 6= error.

4.2. REFACTORING RULES 59

= Law 63 〈var block-res〉 (l/r)

var aux : T • {self .b 6= null ∧ self .b 6= error}var p aux : T •

p aux := self .b.x ;aux := p aux

end;le := exp[aux ]

end

Then, we write the parameterised command equivalent to the variable block just introduced.

= Law 65 〈pcom elimination-res〉 (r/l)

var aux : T •{self .b 6= null ∧ self .b 6= error} (res arg ′ : T • arg ′ := self .b.x )(aux ) ¢

le := exp[aux ]end

Using the Law 95 〈method call elimination〉, from right to left, we introduce a call to the methodgetX of class B . Notice that we have the required sequential composition of an assumption with aparameterised command in order to apply such law.

= Law 95 〈method call elimination〉 (r/l)

var aux : T •self .b.getX (aux )le := exp[aux ]

end

The command self .b.x := exp is an assignment to the attribute x of the object denoted by b.We can use the method setX of class B to indirectly assign a value to this attribute. We followthe same steps as we have done in the case of method getX above. However, here we introduce aparameterised command with a parameter passed by value.

(i) = Law 62 〈var block-val〉 (l/r)

{self .b 6= null ∧ self .b 6= error}var p arg ′ : T •

p arg ′ := exp;self .b.x := p arg ′

end

60 CHAPTER 4. COMPOSITIONAL REFACTORINGS

= Law 64 〈pcom elimination-val〉 (r/l)

{self .b 6= null ∧ self .b 6= error} (val arg ′ : T • self .b.x := arg ′)(exp)

= Law 95 〈method call elimination〉 (r/l)

self .b.setX (exp)

Now the classes A and B are as follows.

class Apri b : B ;pri x : T ; adsa ;meth m1 = (pds1 •

c[var aux : T • self .b.getX (aux );le := exp[aux ] end,self .b.setX (exp)])

meth getX = (res arg : T • {self .b 6= null ∧ self .b 6= error} arg := self .b.x )meth setX = (val arg : T • {self .b 6= null ∧ self .b 6= error} self .b.x := arg)new = self .b := new B()mtsa

end

class Bpub x : T ; adsb ;meth getX = (res arg ′ : T • arg := self .x )meth setX = (val arg ′ : T • self .x := arg)mtsb

end

We proceed in the same way to introduce calls to the methods getX and setX of class B inthe methods getX and setX of class A. After that, the attribute x of class A is no longer usedinside this class, and we can remove it by applying the Law 83 〈attribute elimination〉, from left toright. Direct accesses to attribute x that might exist in mtsa are replaced with calls to get and setmethods related to attribute x of class B , similarly to the changes in method m1. This is denotedby mts ′a

= Law 83 〈attribute elimination〉 (l/r)

class Apri b : B ; adsa ;meth m1 = (pds1 •

c[var aux : T • self .b.getX (aux );le := exp[aux ] end,self .b.setX (exp)])

meth getX = (res arg : T • self .b.getX (arg))meth setX = (val arg : T • self .b.setX (arg))new = self .b := new B()mts ′a

end

4.2. REFACTORING RULES 61

By using Law 85 〈change visibility: from private to public〉, from right to left, we privatise theattribute x of class B as it is not directly accessed from outside class B . We finish the derivationwith this step.

= Law 85 〈change visibility: from private to public〉 (r/l)

class Bpri x : T ; adsb ;meth getX = (res arg ′ : T • arg := self .x )meth setX = (val arg ′ : T • self .x := arg)mtsb

end

The proof of this rule from right to left is similar to the one we presented here. First wechange the visibility of x from private to public in B . Then, we eliminate calls to getX and setXin A. We prepare class A for data refinement and introduce the attribute x of type T with thecoupling invariant we used for the proof from left to right. After this, we proceed with diminishingspecification statements, assignments and guards, so that there are no references to b in A. Weeliminate b from A, x and methods getX and setX from B . As both sides are refinement of eachother, we conclude that they are equal.

2

If the visibility of the attribute we want to move is public, we should first apply the refactor-ing rule 〈Encapsulate Field〉 (presented in Chapter 5), and then apply the rule 〈Move Attribute〉presented here. The rule 〈Encapsulate Field〉 is not compositional, consequently, moving a pub-lic attribute from one class to another is a non-compositional transformation. Differently fromFowler’s refactoring, our rule requires that the attribute that we move from one class to anotherto have basic type. This is a consequence of restrictions of laws used to introduce parameterisedcommands, a means to introduce method calls.

4.2.4 Pull Up and Push Down Method

In a class hierarchy, methods defined by the same parameterised command, in different branchesof the hierarchy, should not be duplicated. Changes to one method may not be applied to theother, resulting in inconsistent methods. In order to avoid this situation, we should move themethods to a common superclass, obtaining just one definition. This is the purpose of the refac-toring 〈Pull Up/Push Down Method〉(Rule 4.4). When applying this rule from left to right, wemove methods with the same definition to the superclass of the classes in which these definitionswere present. In practice, the most common use of this rule involves its application for pulling upmethods. On the other hand, if a method is called just on objects of a particular subclass, we canpush down a method, and then remove it from classes whose objects are not target of calls to such

62 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.4 〈Pull Up/Push Down Method〉class A extends D

adsa ;mtsa

endclass B extends A

adsb ;meth m = (pdsm • c′)mtsb

endclass C extends A

adsc ;meth m = (pdsm • c′)mtsc

end

=cds,c

class A extends Dadsa ;meth m = (pdsm • c′)mtsa

endclass B extends A

adsb ;mtsb

endclass C extends A

adsb ;mtsb

end

provided

(↔) super and private attributes do not appear in c′;

(→) m is not declared in mtsa , and can only be declared in a class N , for any N ≤ A,if it has parameters pdsm ;

m is not declared in any superclass of A in cds;

(←) m is not declared in mtsb or mtsc ;super.m does not appear in mtsb or mtsc nor in any subclass of A, which are

not subclasses of B or C ;N .m, for any N ≤ A and N � B or N � C , does not appear

in cds, c, mtsa , mtsb or mtsc .

method.

On the left-hand side of this rule, the classes B and C , which are subclasses of A, declare themethod m with the same parameterised command (pds • c′). These methods are not redefinitionsof methods declared by A. On the right-hand side, the class A declares the method m, and theclasses B and C inherit m.

In order to apply this rule, super and private attributes must not appear in c′. For applyingthis rule from left to right, we require that any other subclass of A, different from B and C , whichdeclares a method named m, must define it with the same parameters as the method m that ispulled up. We also require that the method m is not declared in A.

In order to apply this rule from right to left, the method m must not be already declared in thesubclasses to which we push down the method. We also require that super .m must not appear inthe classes to which we push m down nor in any subclass of A. Also, there must be no calls to m

4.2. REFACTORING RULES 63

that have as target expressions which are not subclasses of the classes to which we push down m,appearing in cds or c.

Notice that in m, the method being pulled up, there should be no accesses to attributes declaredin the class in which m is declared. Also, inside m there should be no calls to methods declared inthe class in which m is declared. This is a consequence of having command c′ in the definitions ofmethod m in B and C .

Derivation. We assume that the provisos are valid and begin the derivation with the left-handside. As we want to move the method m, of classes B and C , to A, we have to apply laws thatdeal with moving methods up in a hierarchy. The Law 91 〈move original method to superclass〉,which moves an original method to a superclass, and the one for moving a redefined method toa superclass (Law 89 〈move redefined method to superclass〉) require that occurrences of self inmethods to be moved are cast. So, our first step is to introduce casts in occurrences of self

in the method m of classes B and C . We sequentially compound the command : [true, true]with commands in which there are occurrences of self . This composition is equivalent to thesequential composition of skip with commands in which self occurs. The specification statement: [true, true] is equivalent to the assumption {true}. According to the Law 101 〈is test true〉,from right to left, occurrences of assumption {true} can be written as {self is A}. By applyingLaw 98 〈eliminate cast of expressions〉, from right to left, we cast self to A in expressions. Thesame changes are applied to class C . The result is denoted by c′′.

class A extends Dadsa ;mtsa

end

class B extends Aadsb ;meth m = (pds • c′′)mtsb

end

class C extends Aadsc ;meth m = (pds • c′′)mtsc

end

By applying the Law 91 〈move original method to superclass〉, we move the method m from Bto A, as m is not declared in mtsa . The provisos of this law are also present in the provisos of therefactoring rule. The classes A, B , and C are now as follows.

= Law 91 〈move original method to superclass〉 (l/r)

class A extends Dadsa ;meth m = (pds • c′′)mtsa

end

class B extends Aadsb ;mtsb

end

class C extends Aadsc ;meth m = (pds • c′′)mtsc

end

Now, there is already a definition of the method m in the class A. In order to move themethod m from C to A we apply the Law 89 〈move redefined method to superclass〉. This applica-

64 CHAPTER 4. COMPOSITIONAL REFACTORINGS

tion introduces an alternation in the method m declared in A, yielding the following.

= Law 89 〈move redefined method to superclass〉 (l/r)

class A extends Dadsa ;meth m = (pds •

if ¬ (self is C ) → c′′

[] self is C → c′′

fi)mtsa

end

class B extends Aadsb ;mtsb

end

class C extends Aadsc ;mtsc

end

The disjunction of the guards of the alternation that appears in the method m is true, andthe same command is guarded in both branches of the alternation. In this way, regardless of theguard that is evaluated to true, the same command is executed. To simplify this alternation weapply Law 44 〈if identical guarded commands〉. We obtain the original command c′ by applyingLaw 97 〈introduce trivial cast in expressions〉, from right to left.

= Law 44 〈if identical guarded commands〉 (l/r),Law 97 〈introduce trivial cast in expressions〉 (r/l)

class A extends Dadsa ;meth m = (pds • c′)mtsa

end

class B extends Aadsb ;mtsb

end

class C extends Aadsc ;mtsc

end

With this step we finish the derivation of the rule 〈Pull Up/Push Down Method〉.2

The derivation of a rule that considers an arbitrary number of subclasses is similar. First, castsmust be introduced and then methods must be pulled up. This results in an alternation whosebranches are defined by the same command. So the command to be executed, in spite of evaluationof guards, is the same. By Law 44 〈if identical guarded commands〉, we simplify the alternation tothe guarded command.

The refactoring we presented here is similar to the refactoring Pull Up Method presentedby Fowler [42, p.322], as he moves methods with the same name and bodies from two subclasses totheir common superclass. On the other hand, our definition slightly differ from the one presentedby Fowler for refactoring Push Down Method [42, p. 328], as a method is pushed down to aspecific subclass. In fact, our refactoring rule is more general than Fowler’s refactoring, in thesense that we push down a method from a superclass to all its immediate subclasses. After this,

4.2. REFACTORING RULES 65

if a method is called on object of just one of the subclasses, we can remove such method from thesubclasses whose objects are not target of calls to the method we push down.

The Eclipse IDE [37] implements a refactorings that are useful for moving methods and at-tributes up (Pull up...) and down (Push down...) a hierarchy. The refactoring Pull up...

restricts the access to an attribute in a class from a method that is moved to the superclass of suchclass: this access cannot use casts. A warning is given to the Eclipse user about the impossibilityof accessing the attribute, which is in the subclass, from the superclass even via an expression witha cast. If the warning is ignored and the refactoring is completed, the refactored code compileswithout problems and the resulting program behaves as the one before refactoring. This situationis a consequence of an implementation decision for the refactoring that does not take casts intoaccount in refactorings [84]. In fact, casts may not improve a program design, but it should bepossible to refactor a program with casts, otherwise it should be clear that programmers shouldnot write programs that use casts.

An inconsistency appears in a refactored program, in the Eclipse IDE [37], when we movemethods with the same name, but different code, from different classes to their common superclassof such classes. This happens, for instance, when the methods we move to the common superclassis different from each other only as a consequence of the occurrence of casts to the classes in whichthe methods are declared. These casts appear in expressions that access attributes declared in thesubclasses. During the refactoring, only a warning concerning the access of the attributes declaredin the subclasses from the method that we move to the superclass is given to the user. There is nowarning concerning the differences between method bodies, so it seems that there is no problemmoving methods with the same names, but with different bodies, from classes to the commonsuperclass of them. This leads to a break in program behaviour.

In the case of pushing down a method from a superclass to subclasses, the Eclipse IDE [37]does not give any warning when we push down a method to subclasses, excluding a subclass whoseinstances are target of calls to the method we are pushing down. This leads to a compilation error.

Although Opdyke [69] does not present a refactoring as the one presented here, when he presentsthe use of refactorings for creating a superclass, the methods to be abstracted have the same bod-ies. For methods that have the same body but different names, renaming is a solution. In thiscase, it is necessary to apply the rule 〈Rename Method〉 (Rule 5.6), presented in Chapter 5, asmany times as necessary, before applying 〈Pull Up/Push Down Method〉. The refactoring rule〈Pull Up/Push Down Method〉 still remains compositional; it is just preceded by an applicationof a contextual refactoring. On the other hand, if we assume in 〈Pull Up/Push Down Method〉that methods may have different names, the first step in the derivation is the application of〈Rename Method〉. Consequently, 〈Pull Up/Push Down Method〉 would be contextual. From astrict point of view, this would not be 〈Pull Up/Push Down Method〉.

66 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.5 〈Replace Parameter with Method〉class A extends Cadsa ;meth m1 = (pds1 • c1;

var x , y : T1,T2 • c3[x ];self .m2(x , y)end)

meth m2 =(val arg1 : T1; res arg2 : T2 •

c2[arg1, arg2])mtsa

end

=cds,c

class A extends Cadsa ;meth m1 = (pds1 • c1;

var y : T2 • self .m2(y)end)meth m2 = (res arg2 : T2 •

var x : T1 • self .m3(x );c2[x , arg2] end)

meth m3 = (res arg : T1 • c3[arg ])mtsa

end

provided

(↔) The types of variables x and y are basic;

(→) m3 is not declared in mtsa nor in any subclass or superclass of A;N .m2 does not appear in cds or c, for any N such that N ≤ A;α(pds1) are not free in c3;The local variable y does not occur free in c3

(←) N .m3 does not appear in cds or c, for any N such that N ≤ A.

4.2.5 Replace Parameter with Method

In Rule 4.5, the method m1, on the left-hand side of the rule, calls the method m2 passing x , alocally declared variable, as a value argument. After application of this rule, the method m1 stillcalls m2. The major changes occurs in m2. The command c3 in which x occurs in the original m1

is extracted into the method m3, which has a result argument arg corresponding to x . Instead ofpassing the result of the call to m3, as an argument, in the call to m2, the method m1 just callsm2, which is responsible for calling m3 with argument x . Consequently, the number of parametersof m2 is smaller than it was originally. The local variable x that is present in the method m2, onthe right-hand side, replaces the parameter arg1 in the original m2.

To apply this rule, the types of x and y must be basic. In order to apply this rule, from leftto right, the method m3 cannot be declared in any superclass of A, in A itself, nor in any of itssubclasses. Method m2 cannot be called outside class A. Also, parameters of m1 must not appearin c3, otherwise we could not turn this command into a method independent of m1. For applyingthis rule from right to left, method m3 must not be called in cds or c, since it is removed.

4.2. REFACTORING RULES 67

Derivation The derivation involves only class A.

class Aadsa ;meth m1 = (pds1 • c1;

var x , y : T1,T2 • c3[x ]; self .m2(x , y)end)meth m2 = (val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])

end

The first step is to introduce the method m3 defined by a parameterised command with a resultparameter and body c3.

= Law 90 〈method elimination〉 (r/l)

class Aadsa ;meth m1 = (pds1 • c1;

var x , y : T1,T2 • c3[x ]; self .m2(x , y)end)meth m2 = (val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])meth m3 = (res arg : T1 • c3[arg ])

end

In method m1, we eliminate the call to m2 having self as target. This results in the parame-terised command that defines the method m2.

= Lemma 1 (l/r)

class Aadsa ;meth m1 = (pds1 • c1;

var x , y : T1,T2 • c3[x ];(val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])(x , y)

end)meth m2 = (val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])meth m3 = (res arg : T1 • c[arg ])

end

68 CHAPTER 4. COMPOSITIONAL REFACTORINGS

= Law 61 〈var dec separation〉 (l/r)

class Aadsa ;meth m1 = (pds1 • c1;

var y : T2 •var x : T1 • c3[x ];

(val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])(x , y)end

end)meth m2 = (val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])meth m3 = (res arg : T1 • c3[arg ])

end

From the command c3 that appears inside the method m1, we can introduce a call to themethod m3, passing x as a result argument: since there is no assignment to x before c3, only theresult of x in c3 is of interest. If a value were assigned to x , we should use both value and resultmechanisms.

c3[x ]

= Lemma 10

(res arg : T1c3[arg ])(x )

The method m1 is now as follows.

meth m1 = (pds1 • c1;var y : T2 •

var x : T1 • (res arg : T1c3[arg ])(x );(val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])(x , y)

endend)

As inside m1 appears the same parameterised command that defines the method m3, we intro-duce a call to such method.

4.2. REFACTORING RULES 69

= Lemma 1 (l/r)

meth m1 = (pds1 • c1;var y : T2 •

var x : T1 • self .m3(x );(val arg1 : T1; res arg2 : T2 • c2[arg1, arg2])(x , y)

endend)

We separate the declarations of the parameters arg1 and arg2 into two parameterised commandsapplied to the arguments x and y .

= Law 66 〈pcom merge〉 (r/l)

meth m1 = (pds1 • c1;var y : T2 •

var x : T1 • self .m3(x );(val arg1 : T1 • (res arg2 : T2 • c2[arg1, arg2])(y))(x )

endend)

We eliminate the parameterised command in which the command c2 appears. With this elimi-nation, the parameters arg1 and arg2 are replaced with the arguments x and y , respectively.

= Lemma 10 (r/l), Lemma 9 (r/l)

meth m1 = (pds1 • c1;var y : T2 •

var x : T1 • self .m3(x );c2[x , y ]

endend)

In the class A we remove the method m2. This is allowed by the fact the m2 is no longer calledinside or outside A. Then we introduce a definition for a new method m2.

= Law 90 〈method elimination〉 (l/r), Law 90 〈method elimination〉 (r/l)

meth m2 = (res arg2 : T2 •var x : T1 • self .m3(x );

c2[x , arg2]end)

70 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Notice that the above definition of m2 is similar to the command that appears inside the blockthat declares the variable y in the method m1. We introduce a call to m2 inside m1. First weintroduce a parameterised command from the command in the body of the block that declares y .This parameterised command is defined with a result parameter, and is applied to the argument y .

meth m1 = (pds1 • c1;var y : T2 •

var x : T1 • self .m3(x );c2[x , y ]

endend)

= Lemma 10 (l/r)

meth m1 = (pds1 • c1;var y : T2 •

(res arg2 : T2 • var x : T1 • self .m3(x ); c2[x , arg2] end)(y)end)

As the parameterised command introduced is equal to the parameterised command that definesthe method m2, we introduce a call to such method.

= Lemma 1 (r/l)

meth m1 = (pds1 • c1; var y : T2 • self .m2(y) end)

The final class A is as follows.

class Aadsa ;meth m1 = (pds1 • c1; var y : T2 • self .m2(y) end)meth m2 = (res arg2 : T2 • var x : T1 • self .m3(x ); c2[x , arg2] end)meth m3 = (res arg : T1 • c3[arg ])

end

This finishes the derivation of rule 〈Replace Parameter with Method.〉 2

This refactoring was proposed by Fowler [42, p. 292]. Our rule is more strict than Fowler’s, aswe require the type of parameters to be basic ones. Also, we require not to exist calls to m2 in theprogram, just inside class A. This avoids looking for calls to m2 around the program to check ifparameter arg1 is used uniformly, i. e., if it is preceded by the command c3. The strategy proposedby Fowler would lead to a contextual refactoring, in our terminology. As we require m2 not to becalled outside A, our refactoring is compositional.

4.2. REFACTORING RULES 71

4.2.6 Extract Class

A common practice in object-oriented software development is the partitioning of a class into severalones. This can be done by using the rule 〈Extract Class〉 (Rule 4.6) [42, p. 149] . This rule createsa new class B with some attributes and methods from an original class A, which ends with anattribute of type B . In A, original direct accesses to attributes that are now in B are replacedwith calls to the get and set methods of B . Original methods of A that act on the attributes thatwere moved to B are moved to B as well; in A we keep delegating methods: they just call thecorresponding methods of B .

To apply this rule, we require the types of parameters arg and those in pds to be basic. Inan application from left to right, the attribute b cannot be already declared in A, nor in itssuperclasses or subclasses. Also, attributes of A, except x , cannot be present in expressions le andexp2, otherwise it would be necessary to pass self as argument. The attribute x of A is moved intoB along with get and set methods. An attribute b of type B is introduced in class A and initialisedin the new method with an object of B . This attribute is the target of calls to the get and setmethods of class B . Original get and set methods that act on attributes that are declared in Bmust use the corresponding methods of class B . In this way, there is no impact on clients of A thatuse the get and set methods. Methods declared in A that act on attributes present in B use theget and set methods present in A itself. The method m1 acts only on the attribute x , indicatingthat it is related to the concept introduced by the attribute x . Therefore, it is provided by B . Onthe right-hand side of the rule 〈Extract Class〉, the method m1 of class B is similar to the definitionof m1 in A, but the attribute x is read and written by means of get and set methods declared inB itself. In order to get the value of x , we declare a variable that is passed as argument in the callto getX . We use setX to write to x .

To apply this rule from left to right, the class B , which is being extracted from class A, cannotbe declared in the sequence of class declarations cds. In order to apply this rule from right to left,class B cannot be used in cds or c: it is not superclass of any class in cds, it is not type of anyattribute, parameter, or local variable in cds or c.

This refactoring improves reuse and extensibility. Classes should describe single concepts ofthe real world. Describing different concepts in one class mingles attributes and methods thatare intrinsic to distinct concepts. This can result in complex classes that are hard to reuse andextend. Extracting a class from a complex class simplifies the original class and favours reuse andextensibility of the resulting classes. The refactoring rule we present here is similar to Fowler’srefactoring for class extraction [42, p.149].

Derivation. The starting point for the derivation is the left-hand side of this rule. Extracting aclass from an existing one is equivalent to moving attributes and methods necessary to describe aconcept that is different from that presented in the original class into a new class. Initially we havejust the class A.

72 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.6 〈Extract Class〉

class A extends Cpri x : T ; adsa ;meth getX =

(res arg : T • arg := self .x )meth setX =

(val arg : T • self .x := arg)meth m1 = pds •

c[le := exp1[self .x ],self .x := exp2, α(pds)])

mtsaend

=cds,c

class A extends Cpri b : B ; adsa ;meth getX =

(res arg : T • self .b.getX (arg))meth setX =

(val arg : T • self .b.setX (arg))meth m1 = (pds • self .b.m1(α(pds))new = self .b := new B()mts ′a

end

class Bpri x : T ;meth getX =

(res arg : T • arg := self .x )meth setX =

(val arg : T • self .x := arg)meth m1 = (pds •

c[var aux : T • self .getX (aux );le := exp1[aux ] end,

self .setX (exp2), α(pds)])end

where

mts ′a = mtsa [var aux : T • self .b.getX (aux ); le := exp[aux ] end, self .b.setX (exp)/le := exp[self .x ], self .x := exp]

provided

(↔) The types of parameters arg and those in pds are basic;

(→) The class B is not declared in cds;

The attribute b is not declared in adsa nor in any subclass or superclass of A.

Attributes of A, except x , cannot be present in le or exp2;

(←) The class B is not used in cds or c

As we have done in the derivation of rule 〈Move Method〉 (Rule 4.2), we do not deal with arbi-trary parameters pds, but with clearly defined parameters. For method m1, we define parameters

4.2. REFACTORING RULES 73

val arg1 : T1; res arg2 : T2.

class Apri x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)meth m1 = (val arg1 : T1; res arg2 : T2 • c1[le := exp1[self .x ], self .x := exp2, arg1, arg2])mtsa

end

We introduce an empty class B to which we move attributes and methods.

= Law 82 〈class elimination〉 (r/l)

class Apri x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)meth m1 = (val arg1 : T1; res arg2 : T2 • c1[le := exp1[self .x ], self .x := exp2, arg1, arg2])mtsa

end

class Bend

By applying rule 〈Move Attribute〉 (Rule 4.3), we move the attribute x from A to B , in whichget and set methods are declared. In A, an attribute b of class B is declared and initialised.Occurrences of previous accesses to x are replaced by calls to get and set methods of class B ,having b as call target.

= 〈Move Attribute〉(Rule 4.3)(l/r)

class Apri b : B ; adsa ;meth getX = (res arg : T • b.getX (arg))meth setX = (val arg : T • b.setX (arg))meth m1 = (val arg1 : T1; res arg2 : T2 •

c1[var aux : T • self .b.getX (aux ); le := exp[aux ] end,self .b.setX (exp), arg1, arg2])

new = self .b := new B()mtsa

end

74 CHAPTER 4. COMPOSITIONAL REFACTORINGS

class Bpri x : T ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)

end

Finally, we move the method m1 from A to B , since this method essentially uses get and setmethods of B in order to indirectly access the attribute x .

= 〈Move Method〉 (Rule 4.2)(l/r)

class Apri b : B ; adsa ;meth getX = (res arg : T • self .b.getX (arg))meth setX = (val arg : T • self .b.setX (arg))meth m1 = (val arg1 : T1; res arg2 : T2 • self .b.m1(arg1, arg2))new = self .b := new B()mtsa

end

class Bpri x : T ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)meth m1 = (val arg1 : T1; res arg2 : T2 •

c1[var aux : T • self .getX (aux ); le := exp1[aux ] end,self .setX (exp2), arg1, arg2])

end

This finishes the derivation of the rule 〈Extract Class〉. 2

The derivation was based on the application of rules 〈Move Attribute〉 (Rule 4.3) and 〈Move Method〉(Rule 4.2), a derivation strategy similar to the strategy proposed by Fowler [42]. In this way, wehave just considered one attribute and one method; the derivation of a rule that considers an ar-bitrary number of attributes with get and set methods, as well as an arbitrary number of methodsthat must be moved to a newly extracted class, is similar to the one we presented here. Our rulepresents a limitation when requiring the type of parameters to be basic, because one of the lawsused for the introduction of parameterised commands requires variables not to be method call tar-gets. These variables in a latter derivation step are changed to be arguments. There is no sense inpassing to a method an object that is not a method call target.

The similarity between 〈Extract Class〉 and 〈Move Attribute〉 comes from the view that data(attributes) determine abstractions to be modelled by classes. Consequently, as we are defining

4.3. NEW REFACTORINGS 75

a new class, the attributes that we perceive to describe another class must be moved from theircurrent class to such new class.

4.3 New refactorings

In this section we present two new refactorings which do not appear in refactoring catalogs [69, 42].They deal basically with the relationship between a class and its clients.

4.3.1 Clientship Elimination

For the derivation of some refactoring rules, it is necessary to eliminate a clientship relation betweentwo classes. This is useful when it is necessary to change the client of a class, and it is the aim ofthe refactoring rule 〈Clientship Elimination〉 (Rule 4.7).

On the left-hand side of this rule, class A is a client of B ; it declares the attribute b of type Band initialises it with an object of B . In method m of A, we assume that there are occurrences ofcalls to a method n of B . The class B declares the attribute x of type T and attributes adsb . Inmethod n of B , there might be occurrences of the expression self .x .

On the right-hand side, the class A does not declare an attribute of type B , but the attribute xthat is also declared in B . The method n is also declared in A, and the call to the method n of B ,that occurred in method m on the left-hand side, is replaced with a call to n on self .

To apply this rule, super must not appear in method n that is called inside A, otherwise wecould not move such method. We require that b is not null or error avoiding program abortion.Also, method n of class B must not access any attribute declared in adsb . To apply this rule fromleft to right, we require that n refers only to attribute x . This is because we cannot establish acoupling invariant between inherited attributes of a class and attributes of its clients. We alsorequire that inside n there are no calls to methods declared in mtsb . There must be no referencesto attribute b in methods in mtsa , otherwise we cannot remove it from class A. The method mof A calls the method n of B with arguments represented by an , and b as target. The method nmust not be declared in mtsa nor in any subclass or superclass of A. Similarly, attribute x mustnot be declared in adsa nor in any superclass or subclass of A. Methods in mtsa must not refer tothe attribute b.

In order to apply this rule from right to left, b must not be declared in adsa nor in any subclassor superclass of A. As we are interested in the refinement of the method m, we assume that methodsin mtsa do not refer to the attribute x . The method n must be called only inside method m, becauseit will be removed from A. Finally, the method n of class A must not refer to any attribute in adsa .

Derivation. Below we present the derivation of 〈Clientship Elimination〉, from left to right, i.e.,in the direction of elimination of the client relation between A and B .

76 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.7 〈Clientship Elimination〉class A extends C

pri b : B ; adsameth m = (pdsm • cm [self .b.n(an)])new = self .b := new Bmtsa

end

class B extends Dpri x : T ; adsbmeth n = (pdsn • cn [self .x ])mtsb

end

=cds,c

class A extends Cpri x : T ; adsameth m = (pdsm • cm [self .n(an)])meth n = (pdsn • cn [self .x ])mtsa

end

class B extends Dpri x : T ; adsbmeth n = (pdsn • cn [self .x ])mtsb

end

provided

(↔) (1) super does not appear in n; (2) b 6= null ∧ b 6= error is an invariant of A;(3) self .b does not appear in n of class B , for any attribute b that is declaredin adsb ;

(→) (1) self .a does not appear in n, for any public or protected attribute a thatis declared by D or by any of its superclasses; (2) self .p does not appear inn, for any method p declared in mtsb or in any superclasses of B ; (3) self .bdoes not appear in mtsa ; (4) n is not declared in mtsa nor in any subclass orsuperclass of A in cds; (5) x is not declared in adsa nor in any superclass orsubclass of A;

(←) (1) b is not declared in adsa nor in any superclass or subclass of A; (2) self .xdoes not appear in mtsa ; (3) D .n does not appear in mtsa , cds or c, for anyD such that D ≤ A; (4) self .a, for any a in adsa , does not appear in methodn of class A.

class A extends Cpri b : B ; adsameth m = (pdsm • cm [self .b.n(expn)])mtsanew = self .b := new B

end

class Bpri x : T ; adsbmeth n = (pdsn • cn)mtsb

end

First, we apply Law 85 〈change visibility: from private to public〉, from left to right, to changethe visibility of attribute x of class B . Then, we eliminate the call to method n of class B that

4.3. NEW REFACTORINGS 77

occurs inside method m of A. This yields a sequential composition of an assumption about self .b,the target of the method call, and the parameterised command that defines the method n inwhich occurrences of self are replaced with self .b. Every access to self .x that appears inside theparameterised command that defines the method n is replaced with self .b.x . This parameterisedcommand is applied to the arguments represented by an .

= Law 85 〈change visibility: from private to public〉 (l/r), Law 95 〈method call elimination〉 (l/r)

class A extends Cpri b : B ; adsameth m = (pdsm •

cm [{self .b 6= null ∧ self .b 6= error}(pdsn • cn)[self .b/self ](an)])

mtsanew = self .b := new B

end

class Bpub x : T ; adsbmeth n = (pdsn • cn)mtsb

end

Now we prepare the class A for a class refinement. We apply the Law 78 〈simple specification〉exhaustively to assignments of the form t := self .b, transforming them into the specificationstatement t : [true, t = self .b]. As one condition for applying 〈Clientship Elimination〉, from leftto right, is that self .b does not appear in methods in mtsa , these methods are not changed by theapplication of the Law 78 〈simple specification〉. So, only the method m is changed; its new bodyis denoted by writing csspec

m .

= Law 78 〈simple specification〉 (r/l)

class A extends Cpri b : B ; adsameth m = (pdsm •

csspecm [{self .b 6= null ∧ self .b 6= error}(pdsn • cn)[self .b/self ](an)])

mtsanew = self .b := new B

end

We then apply the Law 108 〈private attribute-coupling invariant〉, introducing the attribute xin A. The coupling invariant CI , relating x with the attribute x of class B , is self .x = self .b.x .It states that the new attribute x in A represents the attribute x of class B . In terms of datarefinement, the new attribute x is a concrete variable.

The application of CI changes guards and commands in the methods m and in those in mtsa .In fact, the application of CI to mtsa does not affect such methods because one of the condi-tions of the rule 〈Clientship Elimination〉 is that self .b does not appear in mtsa . Consequently,

78 CHAPTER 4. COMPOSITIONAL REFACTORINGS

only the method m is modified. For this reason, in what follows, instead of writing CI (mtsa),we write just mtsa . Guards and commands of the method m are changed according to the lawsof data refinement. Guards are augmented to assume the coupling invariant. Each new guardcan be just the conjunction of the old guard with the coupling invariant. In specification state-ments, the frame is expanded with the concrete variable and the coupling invariant is conjoinedwith the existing pre- and postconditions. The specification statement t : [true, t = self .b.x ] be-comes x , t : [CI , t = self .b.x ∧ CI ]. Assignments of the form self .b.x := exp are augmented toself .x , self .b.x := exp, exp.

¹ Law 108 〈private attribute-coupling invariant〉

CI = self .x = self .b.xclass A extends C

pri x : T ;pri b : B ; adsameth m = (pdsm • CI (csspec

m [{self .b 6= null ∧ self .b 6= error}(pdsn • cn)[self .b/self ](an)]))

mtsanew = self .b := new B

end

The next step is the elimination of occurrences of self .b.x in the method m. Guards must bealgorithmically refined. Specification statements like x , t : [CI , t = self .b.x ∧ CI ] are refined, by us-ing Law 69 〈assignment〉, to the assignment t := self .x . An assignment self .x , self .b.x := exp, expbecomes self .x := exp. We write c′m to represent the command cm of the method m in which wereplace occurrences of self .b.x with self .x . For this reason, now we do not write the substitu-tion [self .b/self ] for the parameterised command (pdsn • cn).

class A extends Cpri x : T ;pri b : B ; adsameth m = (pdsm • c′m [{self .b 6= null ∧ self .b 6= error}(pdsn • cn)(an)])mtsanew = self .b := new B

end

The next step is to remove the assumption about the attribute b that appears in the method m.This is possible since a proviso in the rule already states that b 6= null and b 6= error. We finishwith just one reference to such an attribute, the one in the method new.

4.3. NEW REFACTORINGS 79

v Law 77 〈remove assumption〉, Law 16 〈; −skip unit〉

class A extends Cpri x : T ;pri b : B ; adsameth m = (pdsm • c′m [(pdsn • cn)(an)])mtsanew = self .b := new B

end

We use the parameterised command (pdsn • cn) to define a new method in A. We name suchmethod as n.

= Law 90 〈method elimination〉 (r/l)

class A extends Cpri x : T ;pri b : B ; adsameth m = (pdsm • c′m [(pdsn • cn)(an)])meth n = (pdsn • cn)mtsanew = self .b := new B

end

As the parameterised command that defines the method n is applied in the command cm tothe arguments an , we can introduce a call to n in the command cm .

= Lemma 1 (r/l)

class A extends Cpri x : T ;pri b : B ; adsameth m = (pdsm • c′m [self .n(expn)])meth n = (pdsn • cn)mtsanew = self .b := new B

end

We remove the method new by applying Law 90 〈method elimination〉, from left to right. Then,we apply Law 83 〈attribute elimination〉, from left to right, for removing the attribute b fromclass A.

80 CHAPTER 4. COMPOSITIONAL REFACTORINGS

= Law 90 〈method elimination〉 (l/r), Law 83 〈attribute elimination〉 (l/r)

class A extends Cpri x : T ; adsameth m = (pdsm • c′m [self .n(expn)])meth n = (pdsn • cn)mtsa

end

Finally, we apply Law 85 〈change visibility: from private to public〉, from right to left, changingthe visibility of attribute x of class B back to private. This finishes the derivation of the refactoringrule 〈Clientship Elimination〉, from left to right. The proof of the reverse direction is similar andalso constitutes a refinement between the programs involved. Because both sides are refinement ofeach other, we conclude that they are equal.

2

Notice that this rule is only valid in a language with a copy semantics. When we apply this rulefrom left to right, we copy an attribute an the method that accesses such attribute to another class.In the class to which we copied the attribute and the method, there is no assignment involving theattribute in this class and the one of the source class. So, we have these attributes refer to differentobjects.

For simplicity, in this rule we considered just one attribute and one method. However, clientsmay call distinct methods that use different attributes. In this situation, we should follow the samesteps for the proof. After eliminating method calls and preparing client classes for data refinement,we introduce new attributes that are related with those attributes used in the methods called. Afterthis, we continue with data refinement and introduction of method calls. In the case of inheritedattributes, its is not possible, for now, to couple such attributes with attributes of clients of theclass that inherits the attributes by means of an invariant.

This rule, in fact, does not appear in any of the existing list of refactorings. Indeed, it is easyto argue that it does not lead to an improvement of design of code; eliminating clientship is nota good practice, since we can possibly mix concepts described in different classes. On the otherhand, introducing clientship justifies this rule as a refactoring, even though finding a class that hassimilar attributes and methods to another one is not so easy in practice. Moreover, this rule isjustified as a step in the derivation of other rules. From this point of view, we can classify it to bea transformational rule: it preserves behaviour.

4.3.2 Delegation Elimination

A particular case of Rule 4.7 is the rule 〈Delegation Elimination〉 (Rule 4.8). On the left-hand sideof this rule, class A is a delegating class. Any call to the method m of class A is forwarded to theclass B . The class A also declares the attribute b of type B and initialises it with an object of B .

4.4. FURTHER COMPOSITIONAL REFACTORING RULES 81

Rule 4.8 〈Delegation Elimination〉class A extends C

pri b : B ; adsameth m = (pds • self .b.n(α(pds)))mtsanew = self .b := new.B

endclass B extends D

pri x : Tmeth n = (pds • c)mtsb

end

=cds,c

class A extends Cpri x : T ; adsameth m = (pds • c)mtsa

endclass B extends D

pri x : Tmeth n = (pds • c)mtsb

end

provided

(↔) (1) super does not appear in n;(2) b 6= null ∧ b 6= error is an invariant of A;

(→) (1) self .a does not appear in n, for any public or protected attribute a that isdeclared by D or by any of its superclasses;

(2) self .p does not appear in n, for any method p declared in mtsb or in anysuperclasses of B ;

(3) self .b does not appear in mtsa ;(4) x is not declared in adsa nor in any superclass or subclass of A;

(←) (1) b is not declared in adsa nor in any superclass or subclass of A;(2) self .x does not appear in mtsa ;

The class B declares the attribute x of type T and attributes adsb . In the method n of B theremight be occurrences of the expression self .x .

On the right-hand side, the class A does not declare an attribute of type B , but the attribute xthat is also declared in B . The method m of A is defined by the same parameterised commandthat defines the method n of B .

Notice that in Rule 4.7, we require, for application from right to left, that method n of class Ais not called in the program. This condition is not necessary for Rule 4.8, as we do not remove anymethod in class A when applying this law from right to left.

4.4 Further Compositional Refactoring Rules

In this section we present refactoring rules related with commands, without their correspondingderivations. For their derivations see Appendix A.

82 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.9 〈Inline Class〉class A extends C

pri b : B ; adsa ;meth getX =

(res arg : T • self .b.getX (arg))meth setX =

(val arg : T • self .b.setX (arg))meth m = (pds •

self .b.m(α(pds)))new = self .b := new B();mtsa

end

class Bpub x : T ;meth getX =

(res arg ′ : T • arg ′ := self .x )meth setX =

(val arg ′ : T • self .x := arg ′)meth m = (pds •

cm [var aux : T • self .getX (aux );le := exp1[aux ]end,

self .setX (exp2), α(pds)])end

vcds,c

class A extends Cpri x : T ; adsa ;meth getX =

(res arg : T • arg := self .x )meth setX =

(val arg : T • self .x := arg)meth m = (pds •

cm [le := exp1[self .x ],self .x := exp2, α(pds)])

mtsaend

class Bpub x : T ;meth getX =

(res arg ′ : T • arg ′ := self .x )meth setX =

(val arg ′ : T • self .x := arg ′)meth m = (pds •

cm [var aux : T • self .getX (aux );le := exp1[aux ]end,

self .setX (exp2), α(pds)])end

provided

(1) b 6= null ∧ b 6= error is an invariant of A; (2) The types of parameters argand those in pds are basic; (3) x is not declared adsa , in any of its superclasses orsubclasses; (4) self .b does not appear in mtsa , except in target of method calls;(5) n is not declared in mtsa , in any subclass or superclass of A.

4.4.1 Inline Class

The purpose of a class in a system must be well-justified. When the role of a class is not clear, thefirst step in order to remove it is to inline it: all clientship relations with respect to such class areeliminated from the whole program. This is the purpose of the rule 〈Inline Class〉 (Rule 4.9). If

the class that is inlined is not used as a type of any kind of variable in the program nor itis a superclass of any class, we can remove it. In this case, this rule is exactly the reverse of

4.4. FURTHER COMPOSITIONAL REFACTORING RULES 83

rule 〈Extract Class〉.The class A on the left-hand side of this rule is a client of B . It declares the attribute b of

type B . The methods getX and setX just call the corresponding methods of class B . Also, themethod m just calls the method m of B . The class B declares an attribute x of type T along withget and set methods for it. Also, B declares a method m in which accesses to x are carried out bymeans of the get and set methods. We assume that all other clients of B are in the sequence ofclass declaration denoted by cds1. This sequence is empty if A is the only client of B . The sequencedenoted by cds2 contains classes that are not clients of B .

On the right-hand side of this rule, the class A declares an attribute x of type T . The get andset methods directly use this attribute instead of calling get and set methods of B . The method mof A now, instead of calling the method m of B , has a copy of the command cm that is present inthe method m of B . However, accesses to the attribute x are direct, and not by means of get andset methods.

To apply this law, we require that b is not null or error avoiding program abortion. Also,parameters arg and those in pds must have basic types. The attribute x must not be declared in Anor in any of its subclasses or superclasses. As we want to remove the attribute b from A and otherclients of B , the expression self .b must not appear in mtsa , except as method call target. Themethod m of B that is copied to A must not be declared in mtsa , in any subclass or superclassof A.

In the refactoring 〈Inline Class〉 presented by Fowler, after eliminating clientship, if B is notused as type of any local variable in the whole program, it is not the type of any method parameternor superclass of any class in cds, we can eliminate B . In this case, the refactoring rule 〈Inline Class〉is the inverse of rule 〈Extract Class〉 (Rule 4.6). Another difference between our rule and Fowler’srefactoring is that we restrict parameters to have basic types.

4.4.2 Self Encapsulate Field

Accessing attributes of a superclass from a subclass is only allowed if the attributes are declared asprotected or public. In order to allow subclasses—and all other classes—to have access to privateattributes already declared in a superclass, get and set methods have to be declared. The rule〈Self Encapsulate Field〉 (Rule 4.10) introduces get and set methods for an attribute x declared inthe class A.

In method m1 on the left-hand side of the rule, the attribute x appears in the expression exp1

and there is also an assignment to this attribute. On the right-hand side of the rule, the occurrenceof self .x in expression exp1 is replaced by the local variable aux declared in m1. This variablereceives the result of the call to method getX . The assignment is accomplished by a call to methodsetX , passing by value the expression exp2. These changes also occur in mtsa .

To apply this rule from left to right, the methods getX and setX cannot be declared in thesuperclass of A, in A itself, nor in any of its subclasses. To apply this rule in the reverse direction,

84 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.10 〈Self Encapsulate Field〉

class A extends Cpri x : T ; adsameth m1 = (pds1 •c1[le1 := exp1[self .x ],

self .x := exp2])mtsa

end

=cds,c

class A extends Cpri x : T ; adsameth m1 = (pds1 • c′1)meth getX = (res arg : T •

arg := self .x )meth setX = (val arg : T •

self .x := arg)mts ′a

end

where

c′1 = c1[var aux : T • self .getX (aux ); le1 := exp1[aux ] end, self .setX (exp2)/le1 := exp1[self .x ], self .x := exp2]

mts ′a = mtsa [var aux : T • self .getX (aux ); le1 := exp1[aux ] end,self .setX (exp2)/le1 := exp1[self .x ], self .x := exp2]

provided

(→) getX is not declared in any superclass or subclass of A in cds;setX is not declared in any superclass or subclass of A in cds;

(←) le.getX and le.setX do not appear in mts ′a , cds or c, for any le such that le ≤ A.

the methods getX and setX cannot be called in cds, c, or A.

In this rule, we considered just one attribute. To encapsulate fields inside a class implies in theapplication of this rule the same number of times as the number of attributes to be encapsulated.

4.4.3 Decompose Conditionals

Conditionals are one of the causes of long methods. It is possible to write conditionals to do varioustasks depending on different conditions, which in rool are written as guards. This leads to longmethods, decreasing legibility. The refactoring rule 〈Decompose Conditional〉 (Rule 4.11) simplifiesa conditional by extracting methods for each guarded command. Free variables that appear inthese commands must be passed as arguments in the method calls. Also, the boolean guards areextracted into a new method that is called before reaching the conditional. In rool, we use theterm alternation for conditionals.

On the left-hand of this rule, the alternation that appears inside the method m1 presents twobranches. One of the branches is guarded by the expression exp and the corresponding guardedcommand is cm1 [ai ], in which free variables represented by ai may appear. The other branch isguarded by the expression ¬ exp; the corresponding guarded command in this branch is cm1 [aj ]′ inwhich the free variables aj may appear.

4.4. FURTHER COMPOSITIONAL REFACTORING RULES 85

Rule 4.11 〈Decompose Conditional〉

class Aadsameth m1 = (pds1 •

if exp → cm1 [ai ][] ¬ exp → c′m1

[aj ]fi)

mtsaend

=cds,c

class Aadsameth m1 = (pds1 •

var b : bool • self .m2(b);if b → self .m3(ai)[] ¬ b → self .m4(aj )fi

end)meth m2 = (res arg : bool • arg := exp)meth m3 = (pds3 • cm1)meth m4 = (pds4 • c′m1

)mtsaend

provided

(↔) • ai and aj have basic types;

(→) ai ⊆ FV (cm) and aj ⊆ FV (c′m);

m2 is not declared in mtsa nor in any superclass or subclass of A;

m3 is not declared in mtsa nor in any superclass or subclass of A;

m4 is not declared in mtsa nor in any superclass or subclass of A;

(←) N .m2, N .m3, and N .m3 do not appear in mtsa , cds or c, for any N ≤ A;

On the right-hand side, we declare in the method m1 the boolean variable b. We also introducein the class A the method m2 with a result parameter of type bool. To such a parameter isassigned the value of the expression exp that appears in one of the branches of the alternation onthe left-hand side. We also introduce the methods m3 and m4. The method m3 is defined by aparameterised command with parameters pds that appear in the command cm1 . This commandappears in the alternation on the left-hand side guarded by the expression exp. Similarly, themethod m4 is defined by a parameterised command with the command c′m1

.

In the method m1 on the right-hand side, the variable b holds the result of the call to themethod m2, which is a boolean value corresponding to the evaluation of the expression exp. In theguards, the variable b replaces the expression exp. The guarded commands are substituted withcalls to methods m3 and m4. Free variable that appeared in the commands cm1 and c′m1

may bepassed as arguments in the method call.

86 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.12 〈Introduce Explaining Variable〉cds,C B c[e] = cds,C B var x : T • x := e; c[x ] end

provided

(↔) cds,C B e : Tx is not free in c and ec does not assign free variables in e

Rule 4.13 〈Consolidate Conditional Expressions〉cds,C B if ψ1 → c [] ψ2 → c [] (ψi → ci) fi = if (ψ1 ∨ ψ2) → c [] ([]i • ψi → ci) fi

provided

(↔) i ranges over 3..n

To apply this rule, the variables ai and aj must have basic type. In order to apply this rule fromleft to right, the methods m2, m3 and m4 must not be declared in A nor in any of its subclasses orsuperclasses. The variables ai and aj represent free variables that may appear in the commands cm1

and c′m1, respectively. Their types are given by T3 and T4, respectively. To apply this rule from

right to left, the methods m2, m3 and m4 must not be called inside A nor in cds or c.

4.4.4 Introduce Explaining Variable

In order to simplify an expression and make clear its use, we can introduce a variable and assignto it the whole expression. This improves the readability of a program due to the simplification ofthe expressions and the use of a variable which should have a name that explains the meaning ofthe expression. We model this refactoring by using local (ordinary) variables (Rule 4.12), becauseconstant declarations like Java’s final1 is not available in rool.

On the left-hand side of this rule, in class C , we have the command c in which the expression expappears. On the right-hand side, we declare the variable x to which we assign the expression exp;the variable x replaces the occurrence of exp in the command c.

In order to apply this rule, the variable x must not occur free in the command c nor in theexpression e. We assume that the type of e is T .

4.4.5 Consolidate Conditional Expression

An alternation that presents different guards whose corresponding guarded commands are the samecan be consolidated by combining the guards using the logic connective or. This is expressed in

1This modifier establishes that the variable value cannot be changed after object initialisation.

4.4. FURTHER COMPOSITIONAL REFACTORING RULES 87

Rule 4.14 〈Consolidate Duplicate Conditional Fragments〉cds,C B if []i • ψi → (ci ; c) = if []i • ψi → ci fi; c

provided

(↔) i ranges over 1..n

the Rule 4.13.

On the left-hand side of this rule, command c appears in the branches guarded by ψ1 and ψ2.On the right-hand side, these guards appears as a disjunction in one of the branches whose guardedcommand is c. In fact, this refactoring corresponds to the application of the Law 8 〈if− ∨ distrib1 〉of rool (presented in Appendix D), which joins two branches of the same guarded command.

4.4.6 Consolidate Duplicate Conditional Fragments

When a command appears as the last command of every branch of an alternation, we can removesuch a command from the branches of the alternation and place it just after the alternation. Thisis the purpose of the rule 〈Consolidate Duplicate Conditional Fragments〉 (Rule 4.14).

On the left-hand side of this rule, command c appears as the last command of every branch ofthe alternation. On the right-hand side, command c appears just after the alternation. In fact,this refactoring corresponds to the application of the Law 20 〈; -if left dist〉 of rool, which dealswith the distribution of a command over an alternation, from right to left.

4.4.7 Substitute Algorithm

Replacing an algorithm with another one is a refactoring that aims at making a program better,since we are expected to introduce a more efficient algorithm. This is the practical view of algorithmsubstitution. In rool, besides this view, substitution of algorithms can be done with the intentionof refining a program in order to reduce nondeterminism, for instance. So, an algorithm that is arefinement of the original one takes its place. The refactoring 〈Substitute Algorithm〉 is presentedin Rule 4.15; it relies on the simple property of monotonicity of parameterised commands withrespect to command refinement.

On the left-hand side, the method m1 is defined by the parameterised command (pds • c1).On the right-hand side, the same method is defined by the parameterised command (pds • c′1); werequire c′1 to refine c1.

We restricted this refactoring to deal only with methods, but the refinement relation betweencommands c v c′ in rool allows us to substitute an algorithm in any context. Methods are aparticular case of algorithm substitution.

88 CHAPTER 4. COMPOSITIONAL REFACTORINGS

Rule 4.15 〈Substitute Algorithm〉class A

adsameth m1 = (pds1 • c1)mtsa

end

vcds,c

class Aadsameth m1 = (pds1 • c′1)mtsa

end

provided

c1 v c′1

4.5 Conclusions

In this chapter we presented 12 refactorings based on the work of Fowler [42]. These are concernedmainly with the structure of classes and methods. Some of the refactorings that deal with dataorganisation were not formalised because they involve references, class attributes and methods, andcollections, for instance. These features are not available in rool. However, in this chapter wepresented a rule for self encapsulating attributes (refactoring Self Encapsulate Field [42, p.171])

The refactorings have constraints that must be satisfied in order to allow their application.Moreover, the refactorings are presented, in its majority, as algebraic rules. The application of arule in different directions (from left to right or from right to left) usually correspond to differentrefactorings.

We can classify some of the refactorings to be basic, as they can be used in the derivationof other refactorings too, and do not have a derivation that relies on other refactorings. Rules〈Extract/Inline Method〉 (Rule 4.1), 〈Move Method〉 (Rule 4.2), and 〈Move Attribute〉 (Rule 4.3)are basic refactorings. This is evidenced by the fact that the derivation of 〈Extract Class〉 uses〈Move Attribute〉 and 〈Move Method〉.

We presented the refactorings as rules that are derived by means of object-oriented programminglaws, assuring their correctness. This allows us to reason about what underlies changes in an object-oriented program. We can observe, for instance, the role of data refinement in refactorings.

We also presented in this chapter some new refactoring rules that help in the derivation ofother refactoring rules. For instance, when it is necessary to break the clientship relation betweenclasses, the application of the rule 〈Clientship Elimination〉 avoids explicit data refinement of theclass that is currently the client of another class. We actually believe that these rules are usefulfor object-oriented program transformation in general and not only to refactoring. Recall that anapplication of 〈Clientship Elimination〉may not lead to code improvement, one of the characteristicsof refactorings, but can transform an object-oriented program into another leaving its behaviour

4.5. CONCLUSIONS 89

unchanged.

The practical methodology adopted for refactoring object-oriented programs relies on cycles oftest and compilation [42]. Tests deal with the detection of functional errors that may be introducedin the refactoring process; compilation aims at detecting type errors that also may be introducedwhile refactoring. In summary, test and compilation are used to guarantee that refactored code isvalid and equivalent to the original one. In this practical approach, the conditions that must besatisfied for the application of a refactoring are not clearly stated for a developer.

In our refactoring approach, the application of programming laws leads to programs that arecorrect by construction, so that compilation and tests are not compulsory. In fact, we should rely onthe use of tools for checking if the conditions of a refactoring rule are satisfied, since non-automatedchecks are error-prone.

Opdyke presents a set of small refactorings that serve as a basis for the definition of morecomplex refactorings. Associated with each small refactoring, there are a set of preconditions that,when satisfied, assure that the refactoring does not change the meaning of a program. In our rules,the preconditions of a refactoring are presented in the provisos, according to the direction in whichthe rule is applied.

Besides preconditions, Roberts [74] presents the postconditions of refactorings. However, insteadof just presenting the refactored code as a result, he writes the preconditions as assertions using thesame language that is used to specify the preconditions. So, he moves the discourse from programsto the language used for writing assertions. This allows calculating the conditions that must besatisfied in order to apply a sequence of refactorings: a chain, to use Roberts’ terminology. In ourapproach, we relate program fragments directly

As observed by Roberts, the conditions for a chain of refactorings is not determined by simplyconjoining the preconditions of all refactorings in a chain. The reason is that some preconditionsof a refactoring are satisfied due to the application of another previous refactoring. Calculatingthe whole precondition for a sequence of refactorings implies in the evaluation of the conditionsfor each refactoring against the program obtained from the application of a previous refactoringrule. The conditions for applying a refactoring may be satisfied by the program that results from arefactoring rule application. Those conditions not satisfied should be part of the conditions of thewhole chain of refactorings.

As the programming laws related to object-oriented constructs have, in general, the same pur-pose of the basic refactorings presented by Opdyke [69], some of the conditions for the refac-toring rule we presented in this chapter are the same as conditions of the laws used in thederivation of refactoring rules. For instance, a method we want to move to the superclass ofthe class in which it is declared must not exist in the superclass. This condition appears inLaw 91 〈move original method to superclass〉 as well as in the refactoring rule. However, the refac-toring rule does present any condition about casts. This is a consequence that the bodies of themethods, which we move from classes to the common superclass, must be the same. In this way,

90 CHAPTER 4. COMPOSITIONAL REFACTORINGS

a programming law may present restrictions that do not appear in refactoring rules, even if law isused in the derivation of a refactoring rule.

A refactoring chain could be expressed as a single transformation rule along with the provisosthat must be satisfied for the rule application using tactics for refinement [67]. The work in [68]defines a language that can be suitably extended.

Chapter 5

Contextual Refactorings

In this chapter we present refactoring rules that change the context in which the class beingrefactored is present. In this way, refactoring a class leads to changes in other classes and, possibly,in the main program. Consequently, differently from the derivation of compositional refactorings,whose changes do not affect the auxiliary class declarations and the main program, for the derivationof contextual refactorings, we have to consider modification in classes, other than those in whichwe are applying the refactoring rule, and in the main program.

This chapter is organised as follows. First, we present a refactoring rule that is used in thederivation of other refactorings. After this, we present a list of refactoring rules, based on theinformal work of Fowler [42], along with their proofs. Those proofs not presented in this chaptercan be found in Appendix B. Finally, we summarise our results.

The notation we use to express refactoring rules that change the context is similar to thatused in Chapter 4. In addition, we write cds[c] to indicate that the command c may appear inclasses declared in the sequence of class declarations cds; we can also indicate a list of commandsthat may appear in cds by writing cds[c1, c2, ..., cn ]. We write cds[c′/c] to express that the com-mand c′ replaces every occurrence of the command c in cds; in the case of a list of commands,we write cds[c′1, ..., c

′n/c1, ..., cn ] to indicate that commands c′1, ..., c

′n replace commands c1, ..., cn ,

respectively, in cds. Moreover, we express the fact that a sequence of classes cds ′ is defined froma sequence of classes cds with some substitutions by writing cds ′ = cds[c′/c], where c′ may be anew command that replaces c. In some of the rules we present in this chapter, the program on theright-hand side refines that on left-hand side, rather than being equivalent.

5.1 Refactoring Rules

In this section we present some contextual refactoring rules. One rule changes the clientship betweenclasses in a hierarchy. We also present a rule that moves a common attribute of subclasses to theirsuperclass. Another rule deals with extraction of a superclass from two classes; another one allowsus to remove a class from a class hierarchy. We also present rules for method renaming, method

92 CHAPTER 5. CONTEXTUAL REFACTORINGS

parametrisation, and attribute encapsulation.

5.1.1 Changing clientship between classes in a hierarchy

Rule 〈Change clientship: from subclass to superclass〉 (Rule 5.1) changes clients of a class to beclients of its superclass. On the left-hand side of this rule, clients of a class C call its method p,which accesses attribute x . On the right-hand side, the attribute x and the method p are declaredin class B , the superclass of C . Previous clients of C are now clients of B . Notice that in thisrule, we do not modify the inheritance hierarchy. This rule is new; it is not presented in refactoringcatalogs [69, 74, 42].

The application of this rule, from left to right, turns clients of C into clients of B , implyingin changes to attributes and methods. Attributes of type B replace former attributes of type C .As expected, attributes of type B are initialised with objects of B , substituting initialisation ofattributes of type C . Previous calls to p on attributes of type C are substituted with calls onobjects of type B . All these changes are expressed in the where clause.

For the application of this rule in any direction, super must not appear in the method p. Also,the method p must not be declared by any superclass of B in cds, avoiding the introduction ofmethod redefinition. To apply this rule from left to right, the attribute x must not be declaredby any subclass of B other than C . Also, if subclasses of B , excluding C , declare a method withname p, this method must have the same parameter declaration pdsp . The class B cannot declarea method with name p. As we introduce an attribute named b of type B in clients of C , whenapplying this rule from left to right, we require such attribute not to be declared in these clients.

We consider clients of C that call just the method p, which accesses only the attribute x . Werequire p not to call any other method available in C nor to access any attribute of C or of any ofits superclasses, because we are just dealing with one method and one attribute. In clients of C ,attributes of type C appear only in methods that call p, so that we can replace such attributes withattributes of type B . Also, there must be no parameters or local variables of type C in methodsof clients of C , otherwise it would not be possible to eliminate the clientship with C .

To apply this rule from right to left, the attribute x must not be accessed by any expressionof strict type B in the whole program. Also, there must be no calls to p with targets of type B .Finally, the new attribute of type C , which is the target of calls to p, must not be declared in anysuperclass or subclass of clients of B .

5.1. REFACTORING RULES 93

Rule 5.1 〈Change clientship: from subclass to superclass〉class B extends A

adsbmtsb

end

class C extends Bpri x : T ; adscmeth p = (pdsp • cp [self .x ])mtsc

end

cds • c

=

class B extends Aadsb ; pri x : Tmtsb ;meth p = (pdsp • cp [self .x ])

end

class C extends Badscmtsc

end

cds ′ • c

where

cds ′ = cds[pri b : B , new = self .b := new B ,

meth m = (pdsm • c′m [self .b.p(expp)])/

pri at : C , new = self .at := new C ,

meth m = (pdsm • c′m [self .at .p(expp)])]

provided

(↔) (1) super does not appear in p; (2) p is not declared by any superclass of Bin cds;

(→) (1) The attribute name x is not declared by the subclasses of B in cds; (2) pis not declared in mtsb , and can only be declared in a class D , for any D ≤ Band D � C , if it has the same parameters as pdsp ; (3) b is not declared by anyclient of C nor by any superclass or subclass of these clients; (4) self .a doesnot appear in p, for any protected attribute a that is declared by B or by anyof its superclasses, nor is declared in adsc ; (5) self .m does not appear in p,for any method m declared in mtsc ; (6) self .w does not appear in methods ofclients of C that do not call p, for any w : C ; (7) there are no parameters orlocal variables of type C in methods of clients of C ;

(←) (1) self .x does not appear mtsb ; (2) p is not declared in mtsc ; (3) D .p appearsin cds ′, c, mtsb , and mtsc only for a D such that D ≤ C (4) at is not declaredby clients of B nor by any of their superclasses or subclasses.

94 CHAPTER 5. CONTEXTUAL REFACTORINGS

Derivation. For the derivation of the rule 〈Change clientship: from subclass to superclass〉, weintroduce a client of class C , in order to make explicit what happens to clients of C .

class B extends Aadsbmtsb

endclass C extends B

pri x : T ; adscmeth p = (pdsp • cp [x ])mtsc

end

class D extends Epri at : C ; adsdmeth m = (pdsm • c′m [self .at .p(expp)])new = self .at := new C

end

For each client of class C we apply the rule 〈Clientship Elimination〉 (Rule 4.7), from left toright. In this example, we have an explicit client of C , the class D . However, the changes wepresent here are also valid to other clients of C .

= 〈Clientship Elimination〉 (l/r)

class B extends Aadsbmtsb

endclass C extends B

pri x : T ; adscmeth p = (pdsp • cp)mtsc

end

class D extends Epri x : T ; adsdmeth m = (pdsm • c′m [self .p(expp)])meth p = (pdsp • cp)

end

By applying the Law 85 〈change visibility: from private to public〉, from left to right, we changethe visibility of the declaration of x in C to public. Then we move the attribute x from C to itssuperclass B .

5.1. REFACTORING RULES 95

= Law 85 〈change visibility: from private to public〉 (l/r),Law 87 〈move attribute to superclass〉 (l/r)

class B extends Apub x : T ; adsb ;mtsb

endclass C extends B

adscmeth p = (pdsp • cp)mtsc

end

class D extends Epri x : T ; adsdmeth m = (pdsm • c′m [self .p(expp)])meth p = (pdsp • cp)

end

As we require the method p not to be declared in mtsb , we apply the law that moves an originalmethod from a class to its superclass.

= Law 91 〈move original method to superclass〉 (l/r)

class B extends Aadsb ; pub x : Tmeth p = (pdsp • cp)mtsb

endclass C extends B

adscmtsc

end

class D extends Epri x : T ; adsdmeth m = (pdsm • c′m [self .p(expp)])meth p = (pdsp • cp)

end

The attribute x and the method p that were originally in class C are in B , the superclass of C .We privatise such attribute by applying an adequate law. Then, we introduce a clientship relationbetween classes that were clients of class C , in the beginning of the derivation, with class B . Asa consequence, class D is made a client of B . This also holds for all classes that were originallyclients of C .

96 CHAPTER 5. CONTEXTUAL REFACTORINGS

= Law 85 〈change visibility: from private to public〉 (r/l), 〈Clientship Elimination〉(r/l)

class B extends Aadsb ; pri x : Tmeth p = (pdsp • cp)mtsb

endclass C extends B

adscmtsc

end

class D extends Epri b : B ; adsdmeth m = (pdsm • c′m [self .b.p(expp)])new = self .b := new B

end

2

In this rule, we considered that clients of C call just method p, which accesses only attribute x .This simplification allows us to apply rule 〈Clientship Elimination〉 (Rule 4.7). Dealing with anarbitrary number of attributes and methods is also possible; it would imply in the application of〈Clientship Elimination〉 according to the number of attributes and methods. Again, we considerpairs of methods and attributes that are accessed. If the method called by a client calls othermethods, it is necessary to eliminate such calls. The rule 〈Clientship Elimination〉 should deal withmethods that possibly access more than one attribute in order to be applied in this situation. Wehave already discussed such a situation in the description of 〈Clientship Elimination〉.

For simplificity, we have also considered that no superclass of B introduces a definition of p.With a definition of p in any superclass of B , when moving p from C to B we are moving a redefinedmethod to B , the superclass, since B inherits a definition of p.

As with rule 〈Clientship Elimination〉, the rule 〈Change clientship: from subclass to superclass〉is more adequately classified as a rule for program transformation rather than as an actual refac-toring rule. It can be used, for instance, when a method and an attribute associated with such amethod should be part of the concept described by a superclass, not a subclass.

5.1.2 Pull Up and Push Down Field

Subclasses developed independently can have attributes (fields) with the same purpose. Theseattributes may have different names, but surely they have the same type. Also, classes combinedthrough refactoring may end with similar attributes. If attributes are used in a similar way, theycan be unified, eliminating duplication. This is the purpose of rule 〈Pull Up/Push Down Field〉(Rule 5.2).

On the left-hand side of the rule, the classes B and C are subclasses of A. The class B declaresthe attribute x , whereas the class C declares an attribute named y . Both attributes have the sametype. The sequence of class declaration cds1 contains the subclasses of B and C that refer to theattributes x and y .

On the right-hand side of the rule, the class A declares a protected attribute z with the same type

5.1. REFACTORING RULES 97

as x and y . However, these attributes are not declared by these classes any more. Occurrences of xand y in methods of B and C , respectively, are replaced with z . This is indicated by the notationmtsb [z/x ] and mtsc [z/y ]. Also, occurrences of x and y in the subclasses of B and C that refer tosuch attributes are replaced with z . We indicate this by the notation cds1[z , z/x , y ].

To apply this rule from left to right, the attribute z must be new: not declared in the classA, B , C , nor in any subclass or superclass of A that is present in cds. In order to apply thisrule in the reverse direction, the attributes x and y must not be already declared in A. Moreover,the attribute x must not be declared in B , or in any subclass of B in cds1[z , z/x , y ], nor in anysuperclass of B in cds. Similar restrictions apply to attribute y .

Derivation. Here we prove the derivation of this refactoring from left to right. We first applylaw Law 87 〈move attribute to superclass〉, from left to right, twice to move the attributes x and yof classes B and C to their common superclass A; at this point x and y are public as required.

class A extends Dadsa ;mtsa

end

class B extends Apub x : T ; adsb ;mtsb

end

class C extends Apub y : T ; adsc ;mtsc

end

= Law 87 〈move attribute to superclass〉 (l/r) (2x)

class A extends Dpub x : T ; pub y : T ;adsa ;mtsa

end

class B extends Aadsb ;mtsb

end

class C extends Aadsc ;mtsc

end

For simplicity, we omit cds1 in the derivation because modifications to the methods of classesin cds1 are similar to those done to mtsb and mtsc .

The next step is to prepare A and its subclasses for a data refinement in which x and yare the abstract attributes, and z is the concrete attribute. This preparation consists of theexhaustive application of Law 78 〈simple specification〉 [64]. It transforms assignments of the formt := self .x into the specification statement t : [true, t = self .x ], where t is a local variable or amethod parameter. This transformation should be carried out in all subclasses of A in which thereare occurrences of x and y in assignments. We denote the operations of classes A, B , and C , afterthese changes, by mtssspec

a , mtssspecb , and mtssspec

c , respectively.

98 CHAPTER 5. CONTEXTUAL REFACTORINGS

Rule 5.2 〈Pull Up/Push Down Field〉class A extends D

adsa ;mtsa

end

class B extends Apub x : T ; adsb ;mtsb

end

class C extends Apub y : T ; adsc ;mtsc

end

cds1

=cds,c

class A extends Dpub z : T ; adsa ;mtsa

end

class B extends Aadsb ;mts ′b

end

class C extends Aadsc ;mts ′c

end

cds ′1

where

mts ′b = mtsb [z/x ]

mts ′c = mtsc [z/y ]

cds ′1 = cds1[M .z ,N .z/M .x ,N .y ], for any M ≤cds B and N ≤cds C

provided

(↔) cds contains no subclasses of B and C in which there are references to x and y ;

N .x , for any N ≤cds B , does not appear in cds or c, and N .y , for any N ≤cds C ,does not appear in cds or c;

cds1 contains only subclasses of B and C in which there are references to x andy ;

(→) The attribute name z is not declared in adsa , adsb , adsc , nor in any subclass orsuperclass of A in cds;

N .z , for any N ≤cds A, N �cds N and N �cds C , does not appear in cds or c.

(←) x (y) is not declared in adsa , adsb (adsc), nor in any subclass or superclass of B(C ) in cds and cds ′1

5.1. REFACTORING RULES 99

= Law 78 〈simple specification〉 (multiple application)

class A extends Dpub x : T ; pub y : T ;adsa ;mtssspec

a

end

class B extends Aadsb ;mtssspec

b

end

class C extends Aadsc ;mtssspec

c

end

We then apply Law 109 〈superclass attribute-coupling invariant〉, introducing the attribute zin A. The predicate ((self is B) ⇒ z = x ) ∧ ((self is C ) ⇒ z = y) is the coupling invariant CI ,relating z with x and y . It states that z represents x in objects of B , and y in objects of C . Theresult is shown below.

class A extends Dpub z : T ;pub x : T ; pub y : T ;adsa ;CI (mtssspec

a )end

class B extends Aadsb ;CI (mtssspec

b )end

class C extends Aadsc ;CI (mtssspec

c )end

The application of CI changes guards and commands of classes A, B , and C according to thelaws of data refinement the way already described in the derivation of the Rule 4.7. Since theattributes x and y are new in class A, there are no occurrences of them in mtssspec

a . Consequently,we can reduce CI (mtssspec

a ) to mtsa by using refinement laws from [64]. The classes are now asfollows.

class A extends Dpub z : T ;pub x : T ; pub y : T ;adsa ;mtsa

end

class B extends Aadsb ;CI (mtssspec

b )end

class C extends Aadsc ;CI (mtssspec

c )end

The next step is the elimination of occurrences of x and y in the subclasses of A. We pro-ceed with diminishing assignments of the form self .x , self .z := exp, exp to self .z := exp using theLaw 73 〈diminish assignment〉 [64].

In order to simplify the conjunction of the coupling invariant in specification statements ofthe form t , z : [CI , t = self .x ∧ CI ], we apply Law 101 〈is test true〉 and Law 102 〈is test false〉.Inside B , Law 101 〈is test true〉 states that the test self is B is true. On the other hand, thetest self is N , for a class N that is not a superclass or a subclass of B is false inside B , ac-cording to Law 102 〈is test false〉. Consequently, the coupling invariant is simplified to the predi-cate (true ⇒ z = x ) ∧ (false ⇒ z = y) which is equivalent to z = x . The specification statementt , z : [z = x , t = self .x ∧ z = x ], at this moment, is refined to the assignment t := self .z ; this can

100 CHAPTER 5. CONTEXTUAL REFACTORINGS

be written as t := self .x [z/x ], a renaming of the original code in mtsb .

We proceed in the same way with the commands of C . The methods in the classes B and Cthat we obtain are the same as the original, except that all occurrences of x and y in the commandsare replaced with z .

class A extends Dpub z : T ;pub x : T ; pub y : T ;adsa ;mtsa

end

class B extends Aadsb ;mtsb [z/x ]

end

class C extends Aadsc ;mtsc [z/x ]

end

Since the abstract attributes x and y are no longer read or written in B or C and theirsubclasses, where they were originally declared, we can remove them from A. First we ap-ply Law 85 〈change visibility: from private to public〉, from right to left, in order to change thevisibility of these attributes to private, since they are not read or written outside the class in whichthey are declared. Then we apply Law 83 〈attribute elimination〉, from left to right, that allows usto remove a private attribute that is not read or written inside the class where it is declared. Weproceed in the same way for y .

= Law 85 〈change visibility: from private to public〉 (r/l) (2x), Law 83 〈attribute elimination〉 (l/r)(2x)

class A extends Dpub z : T ; adsa ;mtsa

end

class B extends Aadsb ;mts ′b

end

class C extends Aadsc ;mts ′c

end

Notice that we replace mtsb [z/x ] and mtsc [z/x ] with mts ′b and mts ′c , respectively, because thelast ones are abbreviations of the former, as stated in the rule.

This finishes the proof of the refactoring rule 〈Pull Up/Push Down Field〉, from left to right.The proof of the reverse direction is similar to the one presented here. Equality is a consequence ofrefinement in both directions. We have considered just two subclasses. The derivation for a greaternumber of subclasses is similar to the one presented here.

2

In this refactoring, we considered attributes with different names. In this sense, our refactoringis more general than the one presented by Fowler [42] and the one implemented in Eclipse [37].Also, Roberts [74] consider that variables that are moved to the superclass have the same name.The language rool does not allow attributes with the same name in different classes in a hierarchy.If subclasses of a common superclass have attributes with the same name, it is necessary to renamethese attributes so that they end up with different names, otherwise, it is not possible to moveany of the attributes up. This is the opposite of the mechanics proposed by Fowler [42], because

5.1. REFACTORING RULES 101

his refactorings are written for Java, which allows attributes with the same name in a hierarchy.Type and visibility changes, if necessary, can be made by using Law 86 〈change attribute type〉,and the adequate laws for visibility change (Law 84 〈change visibility: from protected to public〉 orLaw 85 〈change visibility: from private to public〉), in a similar way as the suggested by Opdyke [69,p. 93], when discussing refactoring for creation of an abstract superclass.

5.1.3 Extract Superclass

The rule 〈Extract Class〉 (Rule 4.6) is adequate for delegation. Inheritance is adequate when twoclasses share behaviour. The rule 〈Extract Superclass〉 (Rule 5.3) extracts attributes and methodscommon to two classes A and B , declaring them in a new class C that is declared to be thesuperclass of A and B . In the case of methods in distinct classes that have the same parametersand one is a refinement of the other one, the application of rule〈Substitute Algorithm〉 (Rule 4.15)permits obtaining just one definition for both methods.

On the left-hand side of this rule, class B extends object and declares the attribute x of type T ,and a method m1, which is defined by the parameterised command (pds1 • c1). This class alsoinitialises the attribute x . Similarly, class C extends object and declares the attribute y of typeT , and a method m1 defined by the parameterised command (pds1 • c1). It also initialises theattribute y .

On the right hand-side, classes B and C extends class A, which declares the attribute z andthe method m1 defined by the parameterised command (pds1 • c1). Accesses to attributes x and yin classes B and C , respectively, are replaced with accesses to z . Also, subclasses of B and Caccesses z instead of x and y . This is indicated by cds ′[z , z/x , y ].

In order to apply this rule, attributes declared in adsb or in adsc must not appear in c1. Toapply this rule from left to right, the class A must not be declared in cds or cds ′; an attribute withname z must not be declared. Also, no expressions of type B or of any subtype of B are used toaccess the attribute x of class B incds or c. The same applies to expressions of type C or of anysubtype of C . To apply this rule from right to left, the method m1 must not be declared in mtsbor mtsc . The expression super must not appear in methods of classes B and C ; the method m1

must not be called on expression of type A that are not of type B or C ; the attribute z is notaccessed by expressions of type A or of any subtype of A in cds or in methods declared by classes Band C . The attributes x and y are not declared in classes B and C , respectively, nor in any oftheir subclasses. Casts involving classes B and C must not appear in the program. Finally, typetests with class A involving attributes, variables or parameters declared to be of types B and C orof any of their subtypes must not appear in the whole program.

102 CHAPTER 5. CONTEXTUAL REFACTORINGS

Rule 5.3 〈Extract Superclass〉

class Bpub x : T ; adsbmeth m1 = (pds1 • c1)new = (val arg : T • self .x := arg)mtsb

end

class Cpub y : T ; adscmeth m1 = (pds1 • c1)new = (val arg : T • self .y := arg)mtsc

end

cds ′

=cds,c

class Apub z : T ;meth m1 = (pds1 • c1)new = (val arg : T • self .z := arg)

end

class B extends Aadsbmtsb [z/x ]

end

class C extends Aadscmtsc [z/y ]

end

cds ′[N .z ,M .z/N .x ,M .y ]

where

N ≤ B and M ≤ C

provided

(↔) (1) Attributes declared in adsb or adsc do not appear in c1;

(2) cds contains no subclasses of B or C in which there are references to x or y ;

(→) (1) The class A is not already declared in cds or cds ′; (2) an attribute namedz is not declared by adsb or adsc (3) N .x , for any N ≤ B , does not appear incds or c, and N .y , for any N ≤ C , does not appear in cds or c;

(←) (1) m1 is not declared in mtsb or mtsc ; (2) super.m1 does not appear inmtsb [z/x ] or mtsc [z/y ]; (3) N .m1, for any N ≤ A and N � B or N � C , doesnot appear in cds, c, mtsa , mtsb or mtsc . (4) N .z , for any N ≤ A, N ≤ B ,and N ≤ C , does not appear in cds or c; (5) x (y) is not declared in , adsb(adsc), nor in any subclass of B (C ) in cds or cds ′; (6) Casts involving B andC do not appear in mtsb [z/x ], mtsc [z/y ], c, cds or cds ′; (7) Type tests withclass A involving attributes, variables or parameters declared to be of types Band C or of any of their subtypes do not appear in mtsb [z/x ], mtsc [z/y ], c,cds or cds ′.

5.1. REFACTORING RULES 103

Derivation. We begin the derivation with the set of classes on the left-hand side. First weintroduce class A, so that it is used as the superclass of classes B and C .

class Bpub x : T ; adsameth m1 = (pds1 • c1)new = (val arg : T • self .y := arg)mtsa

end

class Cpub y : T ; adsameth m1 = (pds1 • c1)new = (val arg : T • self .y := arg)mtsb

end

= Law 82 〈class elimination〉 (r/l)

class Aend

As classes B and C have object as superclass, we can change their superclass from object toA as this class is a subclass of object and is empty.

= Law 105 〈change superclass: from object to any class〉 (2x)

class Aend

class B extends Apub x : T ; adsameth m1 = (pds1 • c1)new = (val arg : T • self .z := arg)mtsa

end

class C extends Apub y : T ; adsbmeth m1 = (pds1 • c1)new = (val arg : T • self .z := arg)mtsb

end

Now we move to A what B and C have in common. First, we move common attributes. Weconsider attributes with different names, but this is not a drawback as they could be renamed toa common name. We apply refactoring rule 〈Pull Up/Push Down Field〉 (Rule 5.2), from left toright, resulting in the following classes.

= 〈Pull Up/Push Down Field〉 (l/r)

class Apub z : T ;

end

104 CHAPTER 5. CONTEXTUAL REFACTORINGS

class B extends Aadsameth m1 = (pds1 • c1[z/x ])new = (val arg : T • self .z := arg)mtsa [z/x ]

end

class C extends Aadsbmeth m1 = (pds1 • c1[z/y ])new = (val arg : T • self .z := arg)mtsb [z/y ]

end

The next step moves the common methods of classes B and C to A. The common methods ofthese classes are m1 and new. Recall that in rool the initialiser new is just a method. Here, weconsider it to have the same body in both classes. Of course, if it were defined by distinct bodies,it would not be possible to move it to A.

= 〈Pull Up/Push Down Method〉 (l/r) (2x)

class Apub z : T ;meth m1 = (pds1 • c1)new = (val arg : T • self .z := arg)

end

class B extends Aadsamtsa [z/x ]

end

class C extends Aadsbmtsb [z/y ]

end

This finishes the derivation of the rule 〈Extract Superclass〉.2

We considered the case of moving to the superclass two attributes and one method. This is aspecial case of moving an arbitrary number of attributes and methods. In this case, we should applythe laws for moving attributes and methods up to the superclass as many times as the number ofattributes and methods.

Notice that the conditions of rule 〈Extract Superclass〉 are not exactly the union of the condi-tions of rules 〈Pull Up/Push Down Method〉 and 〈Pull Up/Push Down Field〉. Because we intro-duce class A in the derivation, and this is not an already existing class, as required by one of theconditions of 〈Extract Superclass〉. As a consequence, it is not necessary to require super not toappear in m1, since in 〈Extract Class〉 this method is always located in classes that have object assuperclass.

The proof of this refactoring is similar to the steps adopted by Fowler [42] for its application. Wedo not consider, as presented by [69], heuristics that could be applied in order to make the methodsignatures compatible by renaming, retyping and reordering parameters, and changing visibility of

5.1. REFACTORING RULES 105

attributes that may be used by the methods. In the case of a tool that implements such heuristics,suggestions of possible changes that could allow more methods to be abstracted might be givenfor a developer. Opdyke takes the position that primitive refactorings can be performed to makemethods more structurally similar. For each heuristics, the name of a corresponding refactoring ispresented. Similarly, we can change the type of a parameter by applying a law, according to theparameter passing mechanism, just to mention a case.

5.1.4 Collapse Hierarchy

After moving attributes and methods up or down in a hierarchy, a class may end up not playingan important role; it may not add any valuable feature. Such a class can be merged with anotherclass, resulting in an empty class that can then be removed. This is the purpose of refactoringCollapse Hierarchy [42, p. 344]. We can merge a class with a superclass or a subclass. We treatthese cases separately. Rule 〈Collapse Hierarchy - Superclass〉 (Rule 5.4) merges a class with itssuperclass, whereas rule 〈Collapse Hierarchy - Subclass〉 (Rule 5.5) merges a class with one of itssubclasses.

Collapse Hierarchy - Superclass

Rule 〈Collapse Hierarchy - Superclass〉 (Rule 5.4) removes a class C from a class hierarchy; its onlyattribute and its only method are moved to its superclass B . Consequently, attributes of type C ,on the left-hand side, that are initialised with objects of type C , are turned into objects of type B ,and properly initialised with objects of B . Variables and parameters of type C are turned intotype B . Subclasses of C are made subclasses of B , and variables initialised with objects of C are,now, assigned with objects of B . Local variables in the main command of type C are changed totype B . Also, occurrences of ‘new C ’ are changed to ‘new B ’.

In order to apply this rule, there must be no occurrences of super in p, as we move this methodfrom C to B . The name x cannot be used by any subclass of B that is not C . Class C cannot beused in types test in the program, as we cannot remove them. The method p cannot be declaredin mtsb and, if declared by any subclass of B that is not C , it must have the same parameters asp. The attribute name b is not used by superclasses or subclasses of clients of C , as we introduce

such attribute in clients of C . We also require references to public attributes or protected attributesof superclasses of C not to appear in p; only x can occur in p. The reason is that we are dealing withjust one attribute and one method. A possible generalisation is discussed later. There must be nocalls to methods inherited by C inside p. We also require that attributes of type C that are targetof calls to p are not null or error avoiding program abortion. As we change the type of parametersfrom C to B , it is required that actual parameters associated to formal result parameters of type Care of type B or of supertype of B .

106 CHAPTER 5. CONTEXTUAL REFACTORINGS

Rule 5.4 〈Collapse Hierarchy - Superclass〉class B extends A

adsbmtsb

end

class C extends Bpri x : Tmeth p = (pdsp • cp)

end

cds1 cds2 • c

v

class B extends Aadsb ; pub x : Tmtsb ;meth p = (pdsp • cp)

end

cds ′1 cds2 • c′

where

cds ′1 = cds1[visib b : B , new B ,var v : B , par p : B ,new B , extends B//

visib c : C , new C , var v : C , par p : C ,new C , extends C ],

where visib ∈ {pri,prot,pub} and par ∈ {val, res}cds ′2 = cds2[]

c′ = c[val x : B ,new B/val x : C ,new C ]

provided

(1) super does not appear in p; (4) the attribute name x is not declared by anysubclass of B in cds2; (5) C is not used in type tests in cds, c or mtsb ; (6) p isnot declared in mtsb , and can only be declared in a class D , for any D ≤ B andD � C , if it has the same parameters as pdsp ; (7) b is not declared by any clientof C nor by any superclass or subclass these clients in cds1; (8) self .a does notappear in p, for any public or protected attribute a that is declared by B or byany of its superclasses; (9) self .t does not appear in p, for any method t inheritedby C ; (10) attributes of type C , which are target of calls to p, are not null orerror are part of an invariant of C ;

(11) every actual parameter associated with formal result parameters of type Cin cds and c are of type B or any supertype of it. (12) cds1 only contains clientsof C and subclasses of C , and cds2 contains no clients of C or subclasses of C ;

Derivation. For the derivation of 〈Collapse Hierarchy - Superclass〉, we follow the steps below.In order to make clear what happens to clients of class C , in the derivation we introduce class D ,a client of C .

5.1. REFACTORING RULES 107

1. For all clients of C , eliminate clientship with C ;

2. Eliminate every declaration of a local variable of type C , while introducing a variable oftype B ;

3. Introduce clientship with class B ;

4. Change types of attributes, and value and result parameters from C to B .

5. Eliminate casts with C . Change expressions ‘new C ’ to ‘new B ’;

6. Eliminate class C .

Step 1. We begin the derivation by eliminating the client dependence between clients of C andsuch class. This is done for all clients of C .

class B extends Aadsbmtsb

endclass C extends B

pri x : Tmeth p = (pdsp • cp [self .x ])

end

class D extends Epri c : C ; adsdmeth m = (pdsm • c′m [self .c.p(expp)])new = self .c := new C

end

= 〈Clientship Elimination〉 (l/r)

class B extends Aadsbmtsb

endclass C extends B

pri x : Tmeth p = (pdsp • cp [self .x ])

end

class D extends Epri x : T ; adsameth m = (pdsm • cm [self .p(ap)])meth p = (pdsp • cp [self .x ])mtsa

end

Step 2. As we remove class C in this refactoring, local variables of type C must not appear inthe program at the end of this derivation. We data refine every variable block that introducesvariables of type C . Consider a local variable block like the following. Notice that objects of classC can only call method p, as it is the unique method of this class, and x is a private attribute.

var c : C •c := new C ;c.p(e);. . .

end

108 CHAPTER 5. CONTEXTUAL REFACTORINGS

For the data refinement of this variable block, we have to eliminate the call to method p. Asthe attribute x in class C is private, we apply Law 85 〈change visibility: from private to public〉,from left to right, to change its visibility to public .

After the elimination of the call to p, by an application of Law 95 〈method call elimination〉,we obtain the following variable block.

var c : C •c := new C ;{c 6= null ∧ c 6= error}; (pdsp • cp [c.x ])(e);. . .

end

We apply Law 87 〈move attribute to superclass〉, from left to right, to move the attribute xfrom class C to class B . We can apply this law as it is required that subclasses of B , other than C ,do not declare x . Also, by using Law 91 〈move original method to superclass〉, from left to right,we move method p from C to B .

Now we prepare the variable block for data refinement by applying Law 78 〈simple specification〉,from left to right.

var c : C •c : [c = new C ];{c 6= null ∧ c 6= error}; (pdsp • cp [c.x ])(e);. . .

end

We use a data refinement law, Law 81 〈Data refinement—variable blocks with initialisation〉,with coupling invariant b = c, in which b is a concrete variable of type B . By the application ofthis law, we obtain a variable block as follows.

var b : B •b : [∃ c : C • b = c ∧ c = new C ];{b 6= null ∧ b 6= error}; (pdsp • cp [b.x ])(e);. . .

end

By the predicate calculus (one-point rule) and Law 78 〈simple specification〉, from right to left,we obtain the following variable block.

var b : B •b := new C ;{b 6= null ∧ b 6= error}; (pdsp • cp [b.x ])(e). . .

end

5.1. REFACTORING RULES 109

We can introduce a call to method p of class B from the sequential composition formed by theassumption and the parameterised command that is the same as the one that defines method p inclass B .

var b : B •b := new C ;b.p(e);. . .

end

We change the visibility of attribute x of class B back from public to private by applyingLaw 85 〈change visibility: from private to public〉, from right to left.

Step 3. Previous clients of C (like the class D that we are using in this derivation) can now bemade clients of class B . We apply rule 〈Clientship Elimination〉, from right to left.

= 〈Clientship Elimination〉 (r/l)

class B extends Aadsb ; pri x : Tmeth p = (pdsp • cp [self .x ])mtsb

endclass C extends Bend

class D extends Epri b : B ; adsdmeth m = (pdsm • cm [self .b.p(expp)])new = self .b := new B

end

Step 4. In the previous steps, we changed every client of C to be a client of B . Also, localvariables originally of type C are now of type B . Value and result parameters of type C must havetheir types changed from C to B . First, we apply Law 97 〈introduce trivial cast in expressions〉 forintroducing casts to C in every non-assignable occurrence of local variables, and value and resultparameters of type C . In order to change the type of local variables, value and result parametersof type C , we use Lemma 7 (Lemma Type changes in program, see Appendix C), from left to right.

Step 5. By Lemma 8 (Lemma Program cast elimination, see Appendix C), we remove casts to Cand assumptions with type tests that appear in a program. We have already moved the attribute xand methods from C to B . Thus, class C is empty and we can change occurrences of the expres-sion new C to new B without affecting the program. For this we apply Law 103 〈new superclass〉,from left to right. Notice that as a consequence of the application of this law, the variable block

110 CHAPTER 5. CONTEXTUAL REFACTORINGS

we presented in this derivation is now as follows.

var b : B •b := new B ;b.p(e). . .

end

Step 6. By applying law 〈change superclass: from an empty class to immediate superclass〉, fromleft to right, every subclass of C is changed to be a subclass of B . We can apply this law becausethere are no type casts or test involving C , and we have changed the type of attributes, variablesand parameters from C to B . Consequently, there are no use of C in the program, and we canremove it from the program by applying Law 82 〈class elimination〉, from left to right.

class B extends Aadsb ; pri x : Tmeth p = (pdsp • cp [self .x ])mtsb

end

class D extends Epri b : B ; adsdmeth m = (pdsm • c′m [self .b.p(expp)])new = self .b := new B

end

This finishes the derivation of rule 〈Collapse Hierarchy - Superclass〉.2

We considered the class being removed to have just one attribute and one method. This sim-plification allows us to use rule 〈Clientship Elimination〉 (Rule 4.7). Dealing with more attributesand methods requires a rule that allows changing a clientship involving more than one attributeand one method.

Collapse Hierarchy - Subclass

Rule 〈Collapse Hierarchy - Subclass〉 (Rule 5.5) is similar to rule 〈Collapse Hierarchy - Superclass〉,but it removes a class from a class hierarchy; its attribute and method are moved to its subclassin such hierarchy. Clients of the class being removed are made clients of its subclass; subclasses ofthe class being removed have their superclasses changed to be the subclass of class being removed.Types of attributes, variables, and parameters are changed from B to C .

To apply this rule, the method p must not be declared in mtsc as we move it from B to C . Themethod p must not be called by expressions of strict type B , as this method, after the application ofthis rule, is located in class C . Expressions that are of subtype of B , but are not of subtypes of C ,must not be target of method calls, as we move p from B to C . The application of this refactoringrule remove class B . So, this class cannot be used in type tests. All the other conditions for theapplication of this refactoring rule, except the last one, are related to changing types of attributes,local variables, value and result parameters.

5.1. REFACTORING RULES 111

Rule 5.5 〈Collapse Hierarchy - Subclass〉class B extends A

pri x : Tmeth p = (pdsp • cp)

endclass C extends B

adscmtsc

endcds1 cds2 • c

v

class C extends Apri x : T ; adscmeth p = (pdsp • cp)mtsc ;

endcds ′1 cds2 • c′

where

cds ′1 = cds1[visib x : C , new C ,var v : C , par p : C , extends C/

visib c : B , new B , var v : B , par p : B , extends B ],

where visib ∈ {pri,prot,pub} and par ∈ {val, res}c′ = c[new C/new B ]

provided

(1) p is not declared in mtsc ; (2) D .p, for any D ≤ B and D � C , does not appearin cds1, cds2, c, mtsb or mtsc (3) B is not used in type tests in cds, c or mtsb ;(4) every non-assignable occurrences of attributes, local variable, value and resultparameters of type B in expressions are cast with C or any subclass of C ; (5)every actual parameter associated to a formal value parameter of type B is of typeC or of any subtype of C ; (6) every expression assigned to a value parameter oftype B is of type C or of any subtype of C ; (7) every use of value argument oftype B as a result argument is for a corresponding formal parameter of type C orof any subclass of C (8) every expression assigned to a result parameter of type Bis of type C or any subclass of C ; (9) every use of a result parameter of type Bas a result argument is for a corresponding formal parameter of type C or of anysubclass of C ; (10) every expression assigned to a variable of type B is of type C orof any subclass of C ; (11) every use of a variable of type B is for a correspondingformal result parameter of type C or any subclass of C ; (12) cds1 only containsclients of C and subclasses of B , and cds2 contains no clients of C or subclasses ofB ;

112 CHAPTER 5. CONTEXTUAL REFACTORINGS

Derivation. We follow the steps below.

1. For all clients of B , change clientship from B to C ;

2. Change types of attributes, local variables, value and result parameter from B to A;

3. Eliminate casts with B ;

4. Change ‘new B ’ to ‘new C ’, and superclasses from B to A;

5. Eliminate class B .

Step 1. We begin the derivation by changing clients of B to be clients of C .

class A extends Fadsamtsa

endclass B extends A

pri x : Tmeth p = (pdsp • cp)

endclass C extends B

adscmtsc

end

class D extends Epri b : B ; adsdmeth m = (pdsm • cm [self .b.p(expp)])new = self .b := new B

end

We remove any occurrence of super in the method p by using the Law 94 〈eliminate super〉,from left to right, resulting in the command c′p . It may be necessary to apply Lemma 4 (Eliminatesuper in Hierarchy) to method p of class B . We eliminate the clientship relation with respect toclass B and introduce clientship with C , using rule 〈Change clientship: from subclass to superclass〉,from right to left.

= Law 94 〈eliminate super〉 (l/r), 〈Change clientship: from subclass to superclass〉 (r/l)

class A extends Fadsamtsa

endclass B extends Aendclass C extends B

pri x : T ; adscmeth p = (pdsp • c′p)mtsc

end

class D extends Epri c : C ; adsdmeth m = (pdsm • cm [self .c.p(expp)])meth new = self .c := new C

end

5.1. REFACTORING RULES 113

Step 2. We change type of attributes, local variables, and parameters from B to C , by usingLemma 7 (Lemma Type changes in program, see Appendix C), from right to left.

Step 3. For removing type casts involving class B , we use Lemma 8 (Lemma Program castelimination, see Appendix C).

Step 4. We change new B to new C , by applying law Law 104 〈new subclass〉, from left toright. Also, we change the superclass of classes from B to A. In this step, we also introduce callson super in the method p, by applying Law 94 〈eliminate super〉, from right to left, resulting inthe original command cp . It may be necessary to apply Lemma 5 (Eliminate super and TrivialMethods in Hierarchy) to method p of class C .

= 〈change superclass: from an empty class to immediate superclass〉 (l/r),Law 94 〈eliminate super〉 (r/l)

class A extends Fadsamtsa

endclass B extends Aendclass C extends A

pri x : T ; adscmeth p = (pdsp • cp)mtsc

end

class D extends Epri c : C ; adsdmeth m = (pdsm • cm [self .c.p(expp)])meth new = self .c := new C

end

Step 5. Finally, we eliminate class B as there are no references to it in the program.

= Law 82 〈class elimination〉 (l/r)

class A extends Fadsa ;mtsa

endclass C extends A

pri x : T ; adsb ;meth p = (pdsp • cp)mtsb

end

class D extends Epri c : C ; adsdmeth m = (pdsm • cm [self .c.p(expp)])new = self .c := new C

end

This finishes the derivation of 〈Collapse Hierarchy - Subclass〉.2

114 CHAPTER 5. CONTEXTUAL REFACTORINGS

In the derivation of 〈Collapse Hierarchy - Superclass〉 we applied data refinement in order tochange the type of local variables of type C , the class that is removed from the hierarchy, to variablesof type B , the superclass of C . However, in the derivation of 〈Collapse Hierarchy - Subclass〉, thetype of local variables were changed from B to C by the application of a lemma in which thesechanges are realised by programming laws. The reason for this is the impossibility of applyingdata refinement from an abstract variable of a superclass to a concrete variable of a subclass. Thisis evidenced by the fact that we cannot assign an object of a class to a variable whose type is asubclass of such a class, as would arise as a consequence of the data refinement of assignment.

The data refinement of local blocks in the derivation of 〈Collapse Hierarchy - Superclass〉 is notresponsible for changing occurrences of ‘new C ’ to ‘new B ’. In the derivation, the applicationof Law 103 〈new superclass〉 changes the expressions involving C to that involving B . Strictly,this change is not possible from a data refinement stand point, because it is not possible to obtain‘new B ’ from ‘new C ’. Also, the coupling invariant relating b, the concrete variable of type B ,and c, the abstract variable of type C , cannot include an expression like ‘new B ’, since this doesnot maintain the coupling invariant.

As expected from an informal approach, which is based on tests and compilation, Fowler [42]does not make clear the restrictions for the application of this refactoring, specially those relatedto type changes as one class of a hierarchy is removed. Also, he does not make clear what happensto clients of the removed class.

We have presented a rule that deals with removing a class that has just one attribute and onemethod. The main reason for this is that the rule that we use to change clientship from a subclassto a superclass also deals with just one attribute and one method. As discussed in that rule, wecould deal with more attributes and more methods. Certainly, this situation is more appropriatein a context in which a tool gives support to refactorings, as it could deal more easily with anarbitrary number of attributes and methods. The fact that it is possible to deal with one attributeand one method shows that we can deal with an arbitrary number of them.

5.1.5 Rename Method

Method names play an important role in object-oriented systems. They should be used to commu-nicate the intention behind the method code. If we have a method whose name does not expressits purpose, renaming a method is necessary in order to clarify the purpose of such method. Thisis the aim of the refactoring rule 〈Rename Method〉 (Rule 5.6).

On the left-hand side of this rule, there is a method named m. This method can be called atany point in the whole program. Applying this rule renames the method m to n.

Renaming a method inside a class affects not only the clients of such class, but also the classesin the same hierarchy in which the method is present. In the rule 〈Rename Method〉 (Rule 5.6), weuse cds1 to indicate the subclasses of the topmost class in the hierarchy of A that first introducesa method named m. In all these classes, method m must be renamed to n.

5.1. REFACTORING RULES 115

Rule 5.6 〈Rename Method〉class A extends C

adsa ;meth m = (pds • cmd)mtsa

endcds1 cds2 • c

=

class A extends Cadsa ;meth n = (pds • cmd)mtsa

endcds ′1 cds2 • c′

where

For all le : D , such that D ≤ A, we have:

cds ′1 = cds1[meth n = (pds • c1), le.n(an)/meth m = (pds • c1), le.m(an)]

c′ = c[le.n(an)/le.m(an)]

provided

(→) (1) cds1 contains all subclasses of the topmost class in the hierarchy of A thatintroduces a method named m, including that class, and classes in which thereare calls to m; cds2 contains all classes other than those in cds1; (2) n is notdeclared in any class in the whole hierarchy of the topmost superclass of Athat first introduces a definition of m;

(←) (1) cds ′1 contains all subclasses of the topmost class in the hierarchy of A thatfirst introduces a definition of n, and classes in which there are calls to n;cds2 contains all classes other than those in cds ′1; (2) m is not declared in anyclass in the whole hierarchy of the topmost class of A that first introduces adefinition of n;

In order to apply this law from left to right, a method named n must not be already declaredin the whole hierarchy of class A. Applying this rule from right to left requires similar conditionsto be satisfied.

Derivation. The derivation, from left to right, follows the strategy below. The derivation fromright to left is similar. In the following steps we use the class name Z to refer to the topmost classin the hierarchy of class A that first introduces a definition of m.

1. Moving of all definitions of method m to Z ;

2. Elimination of calls le.m, such that le : N for N ≤ Z ;

3. Introduction of a new method named n with the same body as the method m in Z ;

4. Elimination of method m from Z .

5. Introduction of calls to the new method n;

116 CHAPTER 5. CONTEXTUAL REFACTORINGS

6. Moving of the method n down from Z to its subclasses.

Example. Let us consider the following class declarations. We assume the conditions for theapplication of the refactoring rule 〈Rename Method〉 are satisfied. In this example, we consider amethod with a value parameter. The argument a denotes an expression of type T .

class Dadscmeth m = (val x : T • cd )mtsc [self .m(a)]

endclass B extends D

adsbmeth m = (val x : T • cb)mtsb [self .m(a)]

endcds2[le.m(a)] • c[le.m(a)]

class A extends Dadsameth m = (val x : T • ca)mtsa [self .m(a)]

endclass C extends A

adscmtsc [self .m(a)]

end

First, we move all definitions of m to class D using Lemma 2 (Pull Up Method in the WholeHierarchy), see Appendix C. This lemma moves all definitions of a method to the topmost class inthe hierarchy that first introduces a definition for it.

= Lemma 2

class Dadscmeth m = (val x : T •

if self is B → c′b[] ¬ (self is B) → if ¬ (self is A) → cd

[] self is A → if (A)self is C → c′c[] ¬ ((A)self is C ) → c′afi

fifi)

mtsd [self .m(a)]end

5.1. REFACTORING RULES 117

class B extends Dadsbmtsb [self .m(a)]

endclass A extends D

adsamtsa [self .m(a)]

end

class C extends Aadscmtsc [self .m(a)]

end

We eliminate every method call le.m(a) in cds2 and c. We also eliminate the parameterisedcommands that result from the method call elimination. Let us consider such command.

le.m(a)

= Law 95 〈method call elimination〉 (l/r)

{le 6= null ∧ le 6= error}(val x : T • if le is B → c′b[] ¬ (le is B) → if le is A → cd

[] ¬ (le is A) → if (A)le is C → c′c[] ¬ ((A)le is C ) → c′afi

fifi)(a)

Notice that, for every method call le.m(a) that was present in the original program, we havenow a sequential composition of an assumption about the method call target and an alternationsimilar to the one that defines the method m of class D . Similarly, we eliminate calls to themethod m that have self as target in the hierarchy of class D . This yields sequential compositionslike the one above, but with assumptions about self .

We introduce a method called n in class D with the same parameterised command that de-fines m. For that, we apply Law 90 〈method elimination〉, from right to left. We assume that n isnot declared by any superclass or subclass of D ; this is a condition for the application of the refac-toring rule. We eliminate the method m, because it is not called by any client of D nor within D ,

118 CHAPTER 5. CONTEXTUAL REFACTORINGS

by applying Law 90 〈method elimination〉, from left to right.

class Dadscmeth m = (val x : T •

if self is B → c′b[] ¬ (self is B) → if self is A → cd

[] ¬ (self is A) → if (A)self is C → c′c[] ¬ ((A)self is C ) → c′afi

fifi)

mtsd [{self 6= null ∧ self 6= error} (val x : T • if . . .fi)(a)]end

= Law 90 〈method elimination〉 (r/l), Law 90 〈method elimination〉 (l/r)

class Dadscmeth n = (val x : T •

if self is B → c′b[] ¬ (self is B) → if self is A → cd

[] ¬ (self is A) → if (A)self is C → c′c[] ¬ ((A)self is C ) → c′afi

fifi)

mtsd [{self 6= null ∧ self 6= error} (val x : T • if . . .fi)(a)]end

In class D , the method n is defined with the same parameterised command that resultedfrom the elimination of calls to the previously existing method m. Throughout the program, thisparameterised command, due to method call elimination, is preceded by an assumption about themethod call target. So, for each sequential composition like the one of Step 6, we can introduce acall to the method n of class D , by applying Law 95 〈method call elimination〉, from right to left,yielding the following method call.

le.n(a)

The introduction of calls to n with target self is also carried out, yielding calls self .n(a).

We can move n down to the subclasses of D , according to the alternation that is present inthis method, using Lemma 3 (Push Down Method in the Whole Hierarchy), see Appendix C. Thislemma moves all definitions of a method from the topmost class in the hierarchy that first introduces

5.1. REFACTORING RULES 119

a definition for it in the direction of classes at the bottom of the hierarchy.

= Lemma 3

class Dadsc ;meth n = (val x : T • cd )mtsc [self .n(a)]

endclass A extends D

adsa ;meth n = (val x : T • ca)mtsa [self .n(a)]

endcds1[le.n(a)]cds2[le.n(a)] • c

class B extends Dadsb ;meth n = (val x : T • cb)mtsb [self .n(a)]

endclass C extends A

adsc ;meth n = (val x : T • cc)mtsc [self .n(a)]

end

This finishes the derivation of the example for rule 〈Rename Method〉.2

In the example, the parameter list of the method being renamed is constituted just of one valueparameter. In the rule, however, any number of parameters of different passing mechanisms areaccepted. This refactoring is presented by both Opdyke [69, p.61] and Fowler [42, p. 273]. Opdykeconsiders the case of renaming a method to the same name of an already inherited method, buteither this method must not be called on instances of the class that declares the method beingrenamed and on instances of its subclasses, or both methods are semantically equivalent. In thissituation, methods must have compatible signatures. In our rule, we exclude the possibility ofrenaming a method to the name of an inherited method, as this case is a special case of the onepresented here; it is only necessary to impose more restrictions on method call targets. Requiringthat both methods are semantically equivalent is the same as requiring that they refine each other.

5.1.6 Parameterise Method

Methods declared in the same class, that perform the same tasks, but that are differentiatedby values that they use, can be simplified to a method that handles the variations by means ofparameters. The rule 〈Parameterise Method〉 (Rule 5.7) parameterise methods that have similarbodies, differentiated just by expressions that appear in these bodies.

On the left-hand side of this rule, in the command cmd in the methods m1 and m2 of the class A,there are occurrences of the expressions exp1 and exp2, respectively, or of type T . The sequence ofclass declarations cds1 contains only subclasses of A; the sequence cds2 contains all other classes.On the right-hand side, class A declares just one method named m defined by a parameterisedcommand that has a parameter of type T . Every method call le.m1, for any left-expression lewhose type is a subclass of A (or A itself), that appears on the left-hand side, is replaced with a

120 CHAPTER 5. CONTEXTUAL REFACTORINGS

Rule 5.7 〈Parameterise Method〉class A extends C

adsameth m1 = (• cmd [exp1])meth m2 = (• cmd [exp2])mtsa

end

cds1 cds2 • c

v

class A extends Cadsameth m = (val arg : T • cmd [arg ])mts ′a

end

cds ′1 cds ′2 • c′

where

mts ′a = mtsa [var x : T • x := exp1; le.m(x ) end/le.m1,

var x : T • x := exp2; le.m(x ) end/le.m2]

cds ′1 = cds1[var x : T • x := exp1; self .m1(x ) end/self .m1,

var x : T • x := exp2; self .m(x ) end/self .m2,

var x : T • x := exp1; le.m(x ) end/le.m1,

var x : T • x := exp2; le.m(x ) end/le.m2]

cds ′2 = cds2[var x : T • x := exp1; le.m(x ) end/le.m1,

var x : T • x := exp2; le.m(x ) end/le.m2]

c′ = c[var x : T • x := exp1; le.m(x ) end/le.m1,

var x : T • x := exp2; le.m(x ) end/le.m2]

provided

(1) cds1 contains only subclasses of A; (2) cds2 contains no subclasses of A; (3) exp1

and exp2 are expressions of type T ; (4) le : B , for a B such that B ≤ A; (5) m1

and m2 are not declared in any superclass of A; (6) m1 and m2 are not redefinedin any subclass of A; (7) m is not declared in any superclass or subclass of A; (8)x is a fresh variable; (9) the types of both exp1 and exp2 are basic.

call le.m(x ) that occurs inside a variable block that declares x . In such block, we assign to x theexpression exp. The changes to method calls le.m2 are similar.

In order to apply this rule, we require that the methods m1 and m2 are not defined in anysuperclass of A or in any of its subclasses. We also require that the method m is new: not declaredin mtsa nor in any superclass or subclass of A. Also the types of expressions exp1 and exp2 arebasic.

5.1. REFACTORING RULES 121

Derivation. The first step of the derivation is to change the visibility of the declaration of anyprivate attribute to public; we apply Law 85 〈change visibility: from private to public〉, from left toright. Then, we introduce the method m in A. We apply the Law 90 〈method elimination〉, fromright to left. The parameterised command that defines the method m has a value parameter (arg);the command cmd [arg ] is similar to cmd with occurrences of exp1 replaced with the parameter arg .

meth m = (val arg : T • cmd [arg ])

In what follows, we change method m1. Changes to method m2 are similar.

meth m1 = (• cmd [exp1])

The first step is to introduce a variable to hold exp1. We declare variable x and define its initialvalue to be expression exp1.

v Law 25 〈var elim〉 (r/l), Law 32 〈var− := initial value〉

var x : T • x := exp1; cmd [exp1] end

As the expression assigned to x occurs in the command cmd , we can replace such occurrenceswith x .

= Law 60 〈assignment seq comp exp substitution〉 (l/r)

var x : T • x := exp1; cmd [x ] end

From the command cmd [x ], we introduce a parameterised command with the value parame-ter arg . This parameterised command is applied to the argument x .

= Lemma 9 (l/r)

var x : T • x := exp1;(val arg : T • cmd)(x )

end

The parameterised command we just introduced is equal to the parameterised command thatdefines the method m. As the methods m and m1 are defined in the same class, we can introducea call to m from m1.

122 CHAPTER 5. CONTEXTUAL REFACTORINGS

= Lemma 1 (r/l)

var x : T • x := exp1;self .m(x )

end

Now we eliminate every call le.m1(), yielding the following sequential composition.

= Law 95 〈method call elimination〉 (l/r)

{le 6= null ∧ le 6= error}(• var x : T • x := exp1;

le.m(x )end)()

In rool, a parameterised command (• c)() can be written just as the command c. So wesimplify the parameterised command (• var x : T . . . end)() to var x : T • . . . end.

{le 6= null ∧ le 6= error}var x : T • x := exp1;

le.m(x )end

We refine the assumption {le 6= null ∧ le 6= error} to skip. As skip always terminates withoutchanging the state of any variable in a program, we can remove it.

v Law 77 〈remove assumption〉, Law 16 〈; −skip unit〉

var x : T • x := exp1;le.m(x )

end

The previous steps regarding the elimination of calls to method m1 can be applied to eliminatecalls to m2. Finally we remove the methods m1 and m2 from A.

class A extends Cadsameth m1 = (• cmd [exp1])meth m2 = (• cmd [exp2])meth m = (val arg : T • cmd ′)mtsa

end

5.1. REFACTORING RULES 123

= Law 90 〈method elimination〉 (l/r) (2x)

class A extends Cadsameth m = (val arg : T • cmd ′)

end

Finally we change the visibility of any public attribute that appears in m to private; we applyLaw 85 〈change visibility: from private to public〉, from right to left. This finishes the derivation ofthe rule 〈Parameterize Method〉.

2

We considered a refactoring similar to that of Fowler [42], in the sense that methods performthe same tasks, but different values are used for these tasks. In this way, these values are passedby means of arguments to the method being parameterised. This is the reason for the use of thevalue parameter passing mechanism. We also required the types of the expressions, whose valuesare passed as argument, to be basic.

5.1.7 Encapsulate Field

Public attributes reduce the modularity of object-oriented programs. They break data hidingbecause client classes can have direct access to them. The rule 〈Encapsulate Field〉 (Rule 5.8) hidesa public attribute and provides get and set methods for it.

The class A on the left-hand side of the rule 〈Encapsulate Field〉 includes a public attribute x .The context for this class is the sequence of classes cds and the command c, which can containexpressions for direct access to x . In class A on the right-hand side, the attribute x is private andget and set methods are declared. The context for class A is the sequence of classes cds ′ and thecommand c′. Direct accesses to x that are present in the cds and c are replaced with calls to getand set methods on the right-hand side.

To apply this rule, the type of x must be basic. To apply this rule from left to right, the methodsgetX and setX must not be already declared in A nor in any of its superclasses or subclasses. Toapply this rule in the reverse direction, the methods getX and setX must not be called in any pointof the whole program.

The refactoring rule 〈Encapsulate Field〉 (Rule 5.8) leads to changes in the context of the classto which the rule is applied since all direct accesses to a public attribute must now be indirect, byusing get and set methods.

Assignments of the form le.x := e, with le : N for N ≤ A, are replaced with calls to theset method setX , where e is an argument and the left-expression le the target of the call. Anassignment of the form le1 := le.x is replaced with calls le.getX (le1). As every access to x must becarried out by means of method calls, occurrences of le.x in an expression on the right-hand sideof an assignment must be replaced with a local variable used as result argument in a call to getX .

124 CHAPTER 5. CONTEXTUAL REFACTORINGS

Rule 5.8 〈Encapsulate Field〉

class A extends Cpub x : T ; adsa ;mtsa

endcds • c

=

class A extends Cpri x : T ; adsa ;meth getX =

(res arg : T • arg := self .x )meth setX =

(val arg : T • self .x := arg)mtsaendcds ′ • c′

where

For all le : N , such that N ≤ A, we have:

cds ′ = cds[le.setX (e), le.getX (le1),var y : T • le.getX (y); le1 := e[y ] end,var y : T • le.getX (y); pc(e[y ]) end/le.x := e, le1 := le.x , le1 := e[le.x ], pc(e[le.x ])]

c′ = c[...] (same substitutions above)

provided

(↔) The type of x is basic;

(→) getX is not declared in A nor in any superclass or subclass of A;setX is not declared in A nor in any superclass or subclass of A;

This call must precede the assignment in which le.x appears.

Derivation. Direct access to a public attribute can be performed in various ways. For instance,it can be done by declaring a variable whose type is the class that has a public attribute, assigningan object of such class to the variable, and then selecting the attribute. Another way of directlyaccessing an attribute of an object is declaring such object as an attribute, initialising it in thenew method, and selecting a public attribute of the object. For these reasons, in the derivation ofthis refactoring rule, we use the following derivation strategy.

1. Introduction of get and set methods for attributes that are going to be made private.

2. Replacement of direct accesses to attributes with calls to get and set methods.

3. Changing the visibility of attributes from public to private.

We begin the derivation by applying Law 90 〈method elimination〉, from right to left, to intro-duce get and set method in class A. Notice that, in the refactoring rule, we required that these

5.1. REFACTORING RULES 125

methods are not declared in the whole hierarchy of class A.

class A extends Cpub x : T ; adsa ;mtsa

end

= Law 90 〈method elimination〉 (r/l)(2x)

class A extends Cpub x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

Let us consider, in isolation, each possible way in which le.x may occur in mtsa , cds, and c.We begin with the assignment le.x := e. This program is equivalent to the one that introduces theassumption {le 6= null ∧ le 6= error} before the assignment to le.x . Notice that if le is null orerror we have that this assignment aborts, so the assumption is innocuous as it behaves as skip

when le is not null or error.

= Law 48 〈innocuous assumption-writing〉 (l/r)

{le 6= null ∧ le 6= error} le.x := e

To introduce a method call we need a parameterised command. This can be introduced usingLemma pcom value argument, passing the expression e as a value argument.

= Lemma 9

{le 6= null ∧ le 6= error} (val arg : T • le.x := arg)(e)

We have a program that is in the format required by the law for method call elimination. Also,the parameterised command we have is the same that defines the method setX of class A. Byapplying this law, from right to left, we obtain a call to the method setX of A.

= Law 95 〈method call elimination〉 (r/l)

le.setX (e)

126 CHAPTER 5. CONTEXTUAL REFACTORINGS

For assignments in the form le1 := le.x , we begin the derivation by introducing an innocuousassumption. The introduction of this assumption is justified by the fact that if le is null, theinspection of x gives error and the assignment aborts; if le is error, the inspection also giveserror, aborting the assignment.

le1 := le.x

= Law 47 〈innocuous assumption-reading〉 (r/l)

{le 6= null ∧ le 6= error} le1 := le.x

The next step introduces a parameterised command applied to le1, an argument that is passedby result.

= Lemma 10

{le 6= null ∧ le 6= error} (res arg : T • arg := le.x )(le1)

The parameterised command is the same as the one used in the definition of method getX .Also, it is preceded by an assumption on le that requires that it is not null or error. We introducea call to method getX of A.

= Law 95 〈method call elimination〉 (r/l)

le.getX (le1)

Now, let us consider the case le1 := e[le.x ]. The first is to introduce a local variable and assignto this variable the expression le.x at the end of the new local variable block.

le1 := e[le.x ]

= Law 25 〈var elim〉 (r/l), Law 30 〈var-:= final value〉 (r/l)

var y : T • le1 := e[le.x ]; y := le.x end

Then, we move the assignment to y before the le1 := e[le.x ], and replace the expression le.x ine with the variable y .

= Law 59 〈order independent assignment〉, Law 60 〈assignment seq comp exp substitution〉 (l/r)

var y : T • y := le.x ; le1 := e[y ] end

5.1. REFACTORING RULES 127

Notice that the assignment y := le.x is exactly the previous case we have dealt with. Followingthe same derivation steps, we end up with the following.

var y : T • le.getX (y); le1 := e[y ] end

The case in which le.x appears in an expression that is argument of an application of a param-eterised command is similar.

The attribute x is no longer accessed outside class A, so we can change its visibility to private.

class A extends Cpub x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

= Law 85 〈change visibility: from private to public〉 (r/l)

class A extends Cpri x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

With this step we finish the derivation of the rule 〈Encapulate Field〉.

2

In this rule we have dealt with just one attribute. The same approach is taken by Opdyke [69]and Fowler [42, p. 206]. As expected, self encapsulating an arbitrary number of attributes can bedone by the application of the rule presented here as many times as the number of attributes tobe encapsulated. Differently from Opdyke and Fowler, we require the type of the attribute beingencapsulated to be basic.

In this rule we have considered the encapsulation of an attribute that can be read and writtenin the whole program. Reading an attribute is equivalent to inspecting the value of this attribute.It corresponds to getting the result of the attribute inspection by using a method call with a resultargument. On the other hand, writing to an attribute can be done by passing the expression to beassigned to the attribute by means of value argument in a method call. Assigning an expressionto a public attribute, and then inspecting the value of the attribute is equivalent to the sequentialcomposition of calls to the set and get methods.

128 CHAPTER 5. CONTEXTUAL REFACTORINGS

5.2 Further Contextual Refactoring Rules

In this section we present refactoring rules related to commands, without their correspondingderivations. For their derivations, see Appendix B.

5.2.1 Add and Remove Parameter

Changing a method may require changing the parameters of a method in order to get informationthat was not necessary before. The refactoring rule 〈Add/Remove Parameter〉 (Rule 5.9) allows usto add to or remove a parameter from a method when we apply the rule from left to right or fromright to left, respectively.

On the left-hand side of this rule, the method m of class A is defined by a parameterisedcommand with parameters pds. On the right-hand side, the method m presents the parameter pdas well as the already existing parameters pds. Previous calls to m of the form le.m(a1), where a1 isan expression of type T1, are replaced with calls of the form le.m(a1, exp), where le1 is an expressionof a type compatible with the type of the parameter whose name is given by α(pds).

The type of the left-expression le is given by any subclass of the topmost superclass of A thatfirst introduces a definition of m. Previous definitions of m in the hierarchy of A are replaced witha new definition with the additional parameter pd .

To apply this rule in any direction, all attributes that appear in the definition of m mustbe public, and the type of le1 must be basic. This allows us to apply the law for method callelimination. In order to apply this rule from left to right, the name given by α(pd) must not be afree variable in the definitions of m in the hierarchy of A. In order to apply this rule from right toleft, arg2 must not be used in any definition of m.

5.2.2 Separate Query from Modifier

A method that returns values to its caller should not have any other effect other than just re-turning the required value. However, if a get method has observable side effects, that is, if itchanges the state of the object that receives the method call, then the code should be sepa-rated so that the query is separated from the modifier. This is the purpose of the refactoringrule 〈Separate Query from Modifier〉 (Rule 5.10).

On the left-hand side of this rule, the method getSetX of class A returns the value of theattribute x , but also assigns to such attribute the parameter arg2. In this way, any call to getSetXnot only gets the current value of the attribute x , but also assigns an expression to such attribute.On the right-hand side, the get and set methods for the attribute x are separated. Every callto getSetX that appeared on the left-hand side is replaced with a sequence of calls to getX and setX ,in this order.

5.2. FURTHER CONTEXTUAL REFACTORING RULES 129

Rule 5.9 〈Add/Remove Parameter〉class A extends Cadsameth m = (pds • c)mtsa

end

cds1 cds2 • c

=

class A extends Cadsameth m = (pds; pd • c)mts ′a

end

cds ′1 cds2 • c′

where

For all le : N , such that N ≤ Z , where Z is the topmost class of A that first introducesa definition of m, we have:

mts ′a = mtsa [self .m(a1, le1)/self .m(a1)]

cds ′1 = cds1[meth m = (pds; pd • c), le.m(a1, le1)/meth m = (pds • c), le.m(a1)]

c′ = c[le.m(a1, le1)/le.m(a1)]

provided

(↔) All attributes that appear in all definitions of m are public;

le1 is an expression of the same type as the parameter whose name is givenby α(pd);

the type of le1 is basic;

(→) α(pd) is not a free variable in the method m of the topmost superclass of A thatfirst introduces a definition of m nor in any redefinition of m in subclasses ofsuch topmost class;

cds1 only contains classes that define a method named m and classes that callmethod m; cds2 contains all other classes;

(←) α(pd) is not used in the method m of the topmost superclass of A that firstintroduces a definition of m nor in any redefinition of m in subclasses of suchtopmost class.

cds ′1 only contains classes that define a method named m and classes that callmethod m; cds2 contains all other classes;

130 CHAPTER 5. CONTEXTUAL REFACTORINGS

Rule 5.10 〈Separate Query from Modifier〉

class A extends Cpri x : T ; adsa ;meth getSetX = (val arg1 : T ;

res arg2 : T • arg2 := self .x ;self .x := arg1)

mtsaend

cds • c

=

class A extends Cpri x : T ; adsa ;meth getX = (res arg : T •

arg := self .x )meth setX = (val arg : T •

self .x := arg)mts ′a

end

cds ′ • c′

where

mts ′a = mtsa [le.getX (a2); le.setX (a1)/le.getSetX (a1, a2)]

cds ′ = cds[le.getX (a2); le.setX (a1)/le.getSetX (a1, a2)]

c′ = c[le.getX (a2); le.setX (a1)/le.getSetX (a1, a2)]

provided

(↔) le is any left expression of a type B such that B ≤ A;

a1 and a2 have basic types;

(→) getX and setX are not declared in mtsa nor in any superclass or subclass of A;

(←) getSetX is not declared in mtsa nor in any superclass or subclass of A

To apply this rule from left to right, the methods getX and setX must not be declared in mtsanor in any subclass or superclass of A. Also, the types of a1 and a2 must be basic. To apply this rulefrom right to left, the method getSetX must not be declared in mtsa nor in any subclass or superclassof A. For both directions, we require the target expressions in the calls to the method getSetX(getX and setX ) to be a subtype of A.

5.2.3 Encapsulate Downcast

In order to prevent clients from having to downcast the object that is obtained from a call to amethod, we can downcast the object within the method. In this way, clients are provided with themost specific type of the object. This is expressed by the rule 〈Encapsulate Downcast〉 (Rule 5.11).

On the left-hand side of this rule, a left expression le1 is assigned to the parameter arg of themethod m. The type of le1 is N , which is a subclass of M , the type of the parameter arg . Inthe program there may be occurrences of calls to the method m. As this method has a result

5.3. CONCLUSIONS 131

Rule 5.11 〈Encapsulate Downcast〉class A extends C

adsa ;meth m = (res arg : M •

arg := le1)mtsa

endcds • c

=

class A extends Cadsa ;meth m = (res arg : N •

arg := (N ) le1)mtsa

endcds ′ • c′

where

cds ′ = cds[var le2 : N • le.m(le2); y := le2 end/var le2 : M • le.m(le2); y := (N ) le2 end]

c′ = c[var le2 : N • le.m(le2); y := le2 end/var le2 : M • le.m(le2); y := (N ) le2 end]

le : B , such that B ≤ A;

provided

(↔) m is not defined in any superclass nor redefined in any subclass; of A.M ,N ∈ cds ′, N ≤ M , and cds,A B le1 : N .y : T , such that T ≤cds N ;

(→) M ,N ∈ cds, N ≤ M , and cds,A B le1 : N .

parameter, callers of such method must give a left-expression as argument. The argument le2 is oftype M . The method call is composed with an assignment to a variable y declared to be of type N .This assignment involves a downcast of the variable x to N .

On the right-hand side, the downcast is placed inside the method m. The type of the param-eter arg is changed to N . In the program, the assignment to y does not need a cast of le2 to N ,because it is now present inside method m. The type of the variable le2 is also changed to N .

To apply this rule in any direction, we require that the method m is not declared in anysuperclass or subclass of A. Altering the signature of m in A would require changing the signaturein all superclasses and subclasses of A. The variables x and y are declared to be of types M and N ,respectively.

5.3 Conclusions

In this chapter we presented a list of contextual refactoring rules, based on the work in [42], alongwith their derivation. Differently from the refactoring rules presented in Chapter 4, which arecompositional in the sense that they do not affect the classes that constitute the context of the

132 CHAPTER 5. CONTEXTUAL REFACTORINGS

class being refactored nor the main program, the refactoring rules we presented in this chapterchange other classes in the program and, possibly, the main command.

Similarly to what we have done in Chapter 4, we can classify some of the refactorings as basic,since they can be used in the derivation of other refactorings, and do not have a derivation thatrelies on other refactorings. We consider rules 〈Change clientship: from subclass to superclass〉,〈Pull Up/Push Down Field〉, 〈Rename Method〉, 〈Parameterise Method〉, and 〈Encapsulate Field〉to be basic refactorings. The refactoring rule 〈Extract Superclass〉 is not basic as its derivationrelies on the rule 〈Pull Up/Push Down Field〉; and the derivation of 〈Collapse Hierarchy - Subclass〉relies on the application of 〈changing clientship: from subclass to superclass〉.

Chapter 6

Refactoring towards Patterns

In this chapter we present design and architectural patterns. Design patterns present solutionsto recurrent problems in object-oriented systems development. They are descriptions of commu-nicating objects and classes that are customised to solve a general design problem in a particularcontext [43]. Architectural patterns define the overall shape and structure of software applica-tions [76]. Our intention is not to present a design (or architectural) pattern as a rule, but to showhow, by the application of refactoring rules, we can transform a system in order to obtain a designthat conforms to a pattern. The particular refactoring rules to be applied depends on the systembeing currently designed. We do not limit the structure of the systems of interest and, for thisreason, we have no rule for describing design patterns.

We present the pattern Facade [43] and a layered architecture, an architectural pattern, as goalsof the derivations of two different systems through the application of refactoring rules. The Facadepattern is a simple structural design pattern. The layered architecture we present has already beenused in practical software development [88].

6.1 The Facade Pattern

In this section we show how to obtain a design that is in accordance with a design pattern by theapplication of transformation rules. The Facade pattern [43] is used to introduce a class that isresponsible for providing a unified interface to a set of interfaces in a subsystem [43].

We can reduce the complexity of a system by structuring it into subsystems. The communicationbetween subsystems can be reduced if we use a facade that provides a single interface to the wholesubsystem. This facilitates the use of the subsystem; also, changes that do not affect the interfaceof the facade have no impacts on clients of the facade.

Here, we present an example that involves two clients of two different classes of a system:see Figure 6.1. The classes ClientA and ClientB are clients of the classes Subsys1 and Subsys2,respectively. The method p of class ClientA calls the method m with an object s1 of class Subsys1as target. The argument am represents expressions whose types are compatible with the formal

134 CHAPTER 6. REFACTORING TOWARDS PATTERNS

class ClientApri s1 : Subsys1;meth p = (pdsp • cp [self .s1.m(am)])

endclass Subsys1

pub x : T ; adsSubsys1;meth m = (pdsm • cm [x ])mtsSubsys1

endcds • c

class ClientBpri s2 : Subsys2;meth q = (pdsq • cq [self .s2.n(an)])

endclass Subsys2

pub y : T ; adsSubsys2;meth n = (pdsn • cn [y ])mtsSubsys2

end

Figure 6.1: The system before refactoring

parameters of the method m of the class Subsys1.

The class Subsys1 declares the attribute x of type T , among others. The method m of thisclass uses the attribute x . We assume that in method m there are no calls to the other methodsmtsSubsys1 of this class. Similarly, ClientB calls the method n of Subsys2 using s2 as a target. ClassSubsys2 declares the attribute y of type T that is used by the method n. We also assume that xand y are not declared by any subclass of ClientA and ClientB , respectively; and the methods mand n are not declared by any subclass of ClientA and ClientB , respectively. Also, we assume thatthere is no class named Facade in the sequence of class declarations cds.

After refactoring, the classes ClientA and ClientB and the subsystem classes must conform tothe Facade pattern. In other words, the classes ClientA and ClientB must be clients of a facadeclass. Calls to methods of the facade are forwarded to classes of the subsystem. All previous directmethod calls to objects of the classes Subsys1 and Subsys1 will have as target objects of the facade.These objects just forward the calls to objects of the classes Subsys1 and Subsys2. In this way, theclasses of the system will not be known by clients.

Derivation. We begin the derivation by eliminating the clientship relation that classes ClientAand ClientB have with classes Subsys1 and Subsys2, respectively. We apply, from left to right,rule 〈Clientship Elimination〉 (Rule 4.7). Class ClientA, after the application of this law, declaresthe attribute x that appears in the method m of class Subsys1 and the method m itself. Similarchanges are carried out in class ClientB .

6.1. THE FACADE PATTERN 135

class ClientApri s1 : Subsys1;meth p = (pdsp • cp [self .s1.m(am)])

endclass Subsys1

pub x : T ; adsSubsys1;meth m = (pdsm • cm [x ])mtsSubsys1

endcds • c

class ClientBpri s2 : Subsys2;meth q = (pdsq • cq [self .s2.n(an)])

endclass Subsys2

pub y : T ; adsSubsys2;meth n = (pdsn • cn [y ])mtsSubsys2

end

= 〈Clientship Elimination〉 (l/r) (2x)

class ClientApri x : T ;meth p = (pdsp • cp [self .m(am)])meth m = (pdsm • cm [x ])

end

class ClientBpri y : T ;meth p = (pdsp • cp [self .n(an)])meth n = (pdsn • cn [y ])

end

We now introduce a class named Facade with the attributes and methods of the subsystemclasses that are present in the client classes. So, the class Facade declares the attributes x and y ,and also m and n.

= Law 82 〈class elimination〉 (r/l)

class Facadepri x : T ; pri y : T ;meth m = (pdsm • cm [x ])meth n = (pdsn • cn [y ])

end

We change the classes ClientA and ClientB to be clients of the class Facade. This is done byapplying twice the rule 〈Clientship Elimination〉, from right to left. After this, the class ClientAdeclares an attribute f of type Facade that is initialised with an object of type Facade. Calls to themethod m of the class Facade have as target attribute f . Similar changes apply to class ClientB .

= 〈Clientship Elimination〉 (r/l) (2x)

class ClientApri f : Facade;meth p = (pdsp • cp [self .f .m(am)])new = self .f := new Facade

end

class ClientBpri f : Facade;meth q = (pdsq • cq [self .f .n(an)])new = self .f := new Facade

end

136 CHAPTER 6. REFACTORING TOWARDS PATTERNS

The class Facade provides the same methods of the subsystem classes that were used by theclient class in the beginning of the derivation. In fact, the attributes and methods of Facade arethe same as those of the subsystem classes, except for methods that were not used by clients andattributes that appear in these methods.

We now change the class Facade to be just a delegate class: calls to its methods are forwarded toadequate subsystem classes. We apply rule 〈Delegation Elimination〉 (Rule 4.8) twice, from rightto left. The method calls have as target the attributes s1 and s2 of type Subsys1 and Subsys2,respectively, declared in Facade. These attributes are initialised with objects of this type.

= 〈Delegation Elimination〉 (r/l) (2x)

class Facadepri s1 : Subsys1, s2 : Subsys2;meth m = (pdsm • self .s11.m(α(pds)))meth n = (pdsn • self .s2.n(α(pds)))new = self .s1 := new Subsys1; self .s2 := new Subsys2

endclass ClientA

pri f : Facade;meth p = (pdsp • cp [self .f .m(am)])new = self .f := new Facade

endclass ClientB

pri f : Facade;meth q = (pdsq • cq [self .f .n(an)])new = self .f := new Facade

endcds • c

class Subsys1pub x : T ; adsSubsys1;meth m = (pdsm • cm [y ])mtsSubsys1

endclass Subsys2

pub y : T ; adsSubsys2;meth n = (pdsn • cn [y ])mtsSubsys2

end

This finishes the derivation. Now the client classes call methods of the class Facade, whichforwards such calls to the subsystem classes. Consequently, client classes interact only with thefacade class, and not with subsystem classes.

6.2 A Layered Architecture

Programs structured according to a layered architecture support enhancements and reuse [76].Therefore, refactoring of object-oriented programs should be conducted, whenever necessary, toobtain a final program with a layered architecture [6]. Here we aim at a layered architectureoriginally designed for the integration of object-oriented programming languages with relationaldatabases [88].

The main purpose of the architecture is to avoid, as much as possible, data storage and retrievalto be mixed with code that implements the functional requirements of a system. To achieve this

6.2. A LAYERED ARCHITECTURE 137

Interface

Data

Business

Communication

Figure 6.2: The four-layer architecture

purpose, classes are separated into two groups: classes that describe the objects required by themodelling of the systems’ (functional) requirements; and classes for data storage and manipulation.The connection between classes of these groups is defined by interfaces. Classes of the first groupare independent of the effective implementation of the data storage and manipulation operations,because these classes do not rely on knowledge of the data structure used for storage, but only onthe methods defined by an interface. Classes of the first group contain what we call business code,which implements the functional requirements of a system. Classes of the second group, however,know how the persistence operations are implemented and depend on the data structure used forstorage. They contain data code for manipulating data structures.

More generally, this architecture is viewed as being composed by four independent layers (Fig-ure 6.2). Classes of the first group constitute the business layer, and classes of the second groupconstitute the data layer. The classes that contain code for communication among subsystems com-pose the communication layer ; and classes that implement the user interface compose the interfacelayer. Here we concentrate on structuring the application into the business and data layers. Theclasses of the business layer are divided into three groups: basic classes, representing basic entities;collection classes, representing groups of basic objects; and control classes, which define the controlflow of functional requirements. The collection classes include methods for adding, searching, andremoving items of a collection, and for invoking typical operations of business objects. If the facadepattern [43] is adopted, a single (control) class synthesises the functionality of the application.

From a poorly structured system we intend, by means of data refinement and application ofrefactoring rules, to reach a well-structured system that fits the layered architecture described here.In the next section we present a new refactoring rule we identified during the introduction of thearchitectural pattern described from a poorly structured system.

6.2.1 A New Refactoring Rule

Rule 〈Interface Clientship〉 (Rule 6.1) introduces clientship between a class B and a class D , whichmodels an interface. The class D is adequately extended in order to introduce a concept initiallydescribed in class B . By applying this rule, we can later provide different implementations of this

138 CHAPTER 6. REFACTORING TOWARDS PATTERNS

Rule 6.1 〈Interface Clientship〉

class B extends Apri x : T ; adsbmeth m = (pdsm • cm [c′m ])mtsb

end

=cds,c

class B extends Apri d : D ; adsbmeth m = (pdsm • cm [self .d .m])new = self .d := new Emtsb

endclass D

meth m = (pdsm • abort)endclass E extends D

pri x : T ;meth m = (pdsm • c′m)

end

provided

(→) (1) D and E are not declared in cds;(2) self .x does not appear in mtsb ;

(←) (1) Classes D and E are not referred to in cds or c.

concept.

On the left-hand side of this rule, class B declares an attribute x , and a method m (amongother methods in mtsb). On the right-hand side, we introduce class D whose method m is definedby a parameterised command with body abort. Such a class models a Java interface. A Javainterface contains a set of signatures of abstract methods; by defining the method bodies to beabort, we give them the most abstract definition.

On the right-hand side of this rule, class E extends D , declares an attribute x and redefines m.Class B is a client of D , and initialises its attribute d with an object of class E , avoiding in thisway program abortion. Command cm is defined in terms of the call self .d .m.

For the application of rule 〈Interface Clientship〉, from left to right, we require that classes Dand E are not declared in cds. Also, attribute x should not be accessed in methods of B otherthan m. In order to apply this rule from right to left, there must be no references to classes D andE , except in class B .

We can derive this refactoring rule in the following way. We introduce classes D and E usingLaw 82 〈class elimination〉 from right to left. However, attribute x of class E must be public, ini-tially. The next step is the data refinement of class B . Instead of using the attribute x of class B , weuse x of class E . This is realised by the application of Law 108 〈private attribute-coupling invariant〉.For this reason, we introduce class E with a public attribute x . Accesses to x are now realised bycalling method m of E .

6.2. A LAYERED ARCHITECTURE 139

This refactoring cannot be fully derived from other refactorings. It cannot be simply derivedby the application of rule 〈Extract Class〉 (Rule 4.6), as B is a client of class D whose methods aredefined with command abort, and this is not a class extraction.

6.2.2 The Architectural Pattern Derivation

Our refactoring strategy consists of three stages. Each stage involves the introduction of newclasses, and data and algorithmic refinement of an already existing class. Data refinement typicallyinvolves the introduction of new attributes to obtain information hiding or to restructure a class inorder to improve reuse. From the first stage (Stage 1) to the last one (Stage 3), the program changesfrom a poorly structured one to a well-structured program according to the layered architecturedescribed above. The developer should identify in which stage of development its program is, andapply refactoring from this stage to the last one. The main reason for dividing the development instages is the simplification of data refinement.

Stage 1

In the first stage, we deal with a class that is monolithic. Data and business code are mixed. Thepurpose of this stage is to identify basic entities in such a monolithic description, and model eachentity as a separate class, with its relevant attributes and methods.

The general form of a monolithic class is given below. The attribute aTable is used to modela database. The type of aTable is given by a partial injective function (symbol ‘ 7→’) from a typeT1 to a type T2. The method update is used to update a record of the table. It takes the recordidentifier n and its new value m as arguments; it also has a result parameter rp: a string thatreports whether the update was successful or not. First, the method update checks if n belongs tothe domain of aTable, which is a business rule. If it does, then aTable is updated at position nwith the expression exp in which there may be occurrences of the expression m, a data operation.The symbol ‘⊕’ in the body of method update stands for function overriding. The class Applicationalso presents methods for inserting new elements in aTable, deleting already existing elements, anda method for inspecting the value associated with a given element in the domain of the table.

class Applicationpri aTable : T1 7→ T2; . . .meth update = (val n,m : T1,T2; res rp : string •

if (n ∈ dom aTable) → self .aTable := self .aTable ⊕ {n 7→ exp[m]};rp := “Updated”

[] (n 6∈ dom aTable) → rp := “Not Updated”fi)

. . .end

140 CHAPTER 6. REFACTORING TOWARDS PATTERNS

At the end of this stage, we want to have the concept (class) which characterises the elements ofaTable separated. The class Application is transformed as shown in Figure 6.3.

By using Law 82 〈class elimination〉, from right to left, we introduce the class BasicEntitythat captures the concept introduced by the domain and range of the attribute aTable. This classprovides get and set methods for the attribute at2, because it is changed along the lifetime of objectsof the class BasicEntity . The value of attribute at1 is usually established at object creation andnot modified along the lifetime of an object of BasicEntity . This reflects the fact that attribute at1is used to identify which attribute at2 is associated with it, in the class Application. The classBasicEntity represents basic objects necessary to implement the functional requirements of thesystem, it separates the concept of pair initially present in the class Application.

class BasicEntitypri at1, at2 : T1,T2;meth setAt2 = (val m : T2 • self .at2 := m)meth getAt2 = (res m : T2 • m := self .at2)new = (val n,m : T1,T2 • self .at1 := n; self .at2 := m)

end

The next step is to prepare the class Application for data refinement. This preparation con-sists of applications of Law 78 〈simple specification〉 to assignments to the attribute aTable. Theapplication of this law changes assignments into corresponding specification statements.

class Applicationpri aTable : T1 7→ T2; . . .meth update = (val n,m : T1,T2; res rp : string •

if (n ∈ dom aTable) → self .aTable : [self .aTable = self .aTable ⊕ {n 7→ exp[m]}];rp := “Updated”

[] (n 6∈ dom aTable) → rp := “Not Updated”fi)

. . .end

Afterwards, a new (private) attribute is introduced in the original class Application. A couplinginvariant relates the new attribute with the old one. From the point of view of data refinement, thenew variables are concrete variables. We use Law 108 〈private attribute-coupling invariant〉 to addan attribute data of type seq BasicEntity (sequence of BasicEntity) to Application. The couplinginvariant CIStage1 is used to relate the attribute aTable and data, which is a sequence of objects ofclass BasicEntity .

CIStage1 = aTable = {i : 0 . . #data − 1 • data(i).at1 7→ data(i).at2} ∧(∀ i , j : 0 . . #data − 1 • i 6= j ⇒ data(i).at1 6= data(j ).at1)

6.2. A LAYERED ARCHITECTURE 141

class Applicationpri data : seqBasicEntity ;meth update = (val n,m : T1,T2; res rp : string •var p, i : BasicEntity , int • self .search(n, p, i);if (p is BasicEntity) → p.setAt2(exp[m]); self .data(i) := p; rp := ‘‘Updated’’[] (p = null) → rp := ‘‘Not Updated’’fi

end)meth search = (val j : int; res obj , pos : Pair , int • . . . )

. . .end

Figure 6.3: The class Application in the end of Stage 1

This coupling invariant guarantees that aTable is formed by mappings relating the values in eachobject present in data. Moreover, the values for the attribute at1 of the objects in data must bedistinct.

The application of Law 108 〈private attribute-coupling invariant〉 to the class Application changesthe methods of this class according to the laws of data refinement [64]. Specification statementsand guards, as expected, must assume the coupling invariant. The class Application now is asfollows.

class Applicationpri data : seq BasicEntity ;pri aTable : T1 7→ T2; . . .meth update = (val n,m : T1,T2; res rp : string •

if (n ∈ dom aTable ∧ CI ) →self .aTable : [CI , self .aTable = self .aTable ⊕ {n 7→ exp[m]} ∧ CI ];rp := “Updated”

[] (n 6∈ dom aTable ∧ CI ) → rp := “Not Updated”fi)

. . .end

Now we refine the class Application in order to remove references to the abstract variable aTable.First, by applying Law 90 〈method elimination〉, from right to left, we introduce method search inclass Application. This method returns an object of type BasicEntity whose attribute at1 has thesame value as n. We proceed with algorithmic refinement of specification statements and guards.Such refinement is carried out for all methods of Aplication. The method update, after refinement,is as follows.

142 CHAPTER 6. REFACTORING TOWARDS PATTERNS

class Applicationpri collct : BusinessCollection;meth update = (val n,m : T1,T2; res rp : string •

collct .update(n,m, rp)) endnew = collct := new BusinessCollection()

. . .end

Figure 6.4: The class Application in the end of Stage 2

meth update = (val n,m : T1,T2; res rp : string •var p, i : BasicEntity , int • self .search(n, p, i);

if (p is BasicEntity) → p.setAt2(exp[m]); self .data(i) := p; rp := “Updated”[] (p = null) → rp := “Not Updated”fi

end)

The method update uses two local variables: p and i (see Figure 6.3). First it calls the new methodsearch to get, in p, the object identified by n, and in i , its index in data. If p is null, then thereis no element identified by n, and this is reported through rp. If p is not null, then a call to amethod of BasicEntity is used to set its value to that of an expression involving the parameter mof update, the sequence data is updated, and success is reported.

In the development, the variables p and i are introduced along with a specification statementthat is refined to introduce a call to the method search, which is also called by the other methodsof class Application, those used for insertion and deletion of objects in data.

Calls to methods of BasicEntity have to replace the direct access to the (abstract) attributeaTable which, after that, can be removed from the class Application. This is done by refin-ing the methods of Application using laws similar to those presented by Morgan [64]. By us-ing Law 83 〈attribute elimination〉, we remove the attribute aTable from Application.

Stage 2

In this stage, we have a program in which different concepts are described in different classes. Inthe end, our purpose is to have the class Application as a facade to the system, where the bodiesof its methods basically delegate responsibilities to the business collections through method calls.

We obtain the classes Application (Figure 6.4) and BusinessCollection (Figure 6.5) in two steps.The first step is the introduction of class BusinessCollection. Then, we make class Application justa delegating class by using 〈Delegation Elimination〉 (Rule 4.8), from right to left.

6.2. A LAYERED ARCHITECTURE 143

class BusinessCollectionpri data : seqBasicEntity ;meth update = (val n,m : T1,T2; res rp : string •

var p, i : BasicEntity , int • self .search(n, p, i);if (p is BasicEntity) → p.setAt2(m); self .data(i) := p; rp := “Updated”[] (p = null) → rp := “Not Updated”fi

end )meth search = (val j : T1; res obj , pos : BasicEntity ,T1 • . . . ). . .

end

Figure 6.5: The class BusinessCollection in the end of Stage 2

Stage 3

At this point, the collection class and the persistence mechanism are still interwoven. This hindersreuse and extensibility, because if the persistence mechanism is changed, part of the system mustbe redesigned. The business code that can be reused, when adapting the persistence mechanism,should be separated from data code. This is the purpose of this stage.

We proceed with the application of refactoring rule 〈Interface Clientship〉 (Rule 6.1). Thisresults in classes BusinessCollection (Figure 6.6), and RepositoryClass and RepositoryClassRef ,which are presented in Figure 6.7. Class BusinessCollection now is client of RepositoryClass andinitialises attribute rep with an object of class RepositoryClassRef . This attribute is also targetof call to methods of RepositoryClassRef . Class RepositoryClass defines an interface betweenthe BusinessCollection and the class that deals with the persistence mechanism. A class likeRepositoryClass is similar to a Java interface. Class RepositoryClassRef implements the access tothe data structure originally defined in class BusinessCollection.

The use of an interface provides independence between the collection and the repository classes.We can change the repository class, for instance, from a class that uses a list to one that uses a tree,with minimal impact on the collection class. Only the initialiser of this class needs to change tocreate an object of the new implementation of the repository. We now have a program structuredaccording to the architecture described in Section 6.2.

The strategy described here can also be used to obtain systems structured according to a three-layer architecture [19]. The main difference between our architecture and the three-layer one is thepresence of the communication layer. We have developed an example of a bank application [31],which was informally presented by Viana and Borba [88], following the strategy we have justpresented. However, the derivation presented in [31] is based on the use of small transformationsteps.

144 CHAPTER 6. REFACTORING TOWARDS PATTERNS

class BusinessCollectionpri rep : RepositoryClass;meth update = (val n,m : T1,T2; res rp : string •

var p, i : BasicEntity , int • rep.search(n, p, i);if (p is BasicEntity) → p.setAt2(m); rep.update(p, i); rp := “Updated”[] (p = null) → rp := “Not Updated”fi

end )new = self .rep := new RepositoryClassRef. . .

end

Figure 6.6: Class BusinessCollection in the end of Stage 3

class RepositoryClassmeth update = (val obj , ind : BasicEntity ,T1 • abort)meth search = (val j : T1; res obj , pos : BasicEntity ,T1 • abort)

. . .endclass RepositoryClassRef extends RepositoryClass

pri data : seq BasicEntity ;meth update = (val obj , ind : BasicEntity ,T1 • self .data(ind) := obj )meth search = (val j : T1; res obj , pos : BasicEntity ,T1 • . . . )

. . .end

Figure 6.7: Classes RepositoryClass and RepositoryClassRef

6.3 Conclusions

In this chapter we exemplified how, from a specific sequence of class declarations, we can achievea design in accordance with a design pattern. We also presented how to achieve a well-structuredprogram from a poorly-structured one. The final program is structured according to a layeredarchitecture, which provides independence between business and data layers.

In this chapter we also presented a new refactoring rule that was needed in the transformationof a poorly structured system into a system designed according to a layered architecture. Thisrefactoring was identified from a revision of the development presented in [31]. Indeed, this is anindication that, in practice, new refactorings will always arise.

Surprisingly, it was not possible to obtain such derivation just from refactoring rules presentedin Chapters 4 and 5. In particular, refactoring 〈Interface Clientship〉 could not be derived fromrefactoring 〈Extract Class〉, which would seem to be compulsory in such derivation. This is be-cause we cannot change a class to be a client of another whose methods are defined with abort

(representing methods of an interface).

6.3. CONCLUSIONS 145

In his refactoring catalog, Fowler [42] suggests refactorings that allow, for instance, separatingbusiness logic from the user interface code. Such refactorings are called “big refactorings”. Therefactoring Separate Domain from Presentation [42, p. 370] could be applied to obtain the set ofclasses in the end of Stage 2, when considering the case in which data in the user interface shouldbe part just of the business logic. This is expressed by the attribute data of class Application inthe end of Stage 1. Fowler also considers situations in which data is used only for user interfacepurposes, and data is used both by the user interface and the business logic. On the other hand, toachieve classes of Stage 3, it would be necessary to use “small refactorings” such as Extract Class,Move Method, Push Down Method, and Extract Interface.

Design patterns are not presented as rules. The reason for this is that only the right-hand sidecould effectively be characterised; the left-hand side should correspond to any system that needs tobe refactored to achieve a structure according to a design pattern. In fact, one goal of refactoringa system is to have such a system in accordance with a design pattern [43]. Describing a designpattern as a rule would restrict its application just to systems that match the left-hand side of therule. It would be necessary to write rules for all situations that result in a design pattern that canbe achieved from an existing design.

A formal description of design patterns has already been provided by Flores et al. [41] andEden [38]. They use different notations for the description of object-oriented design patterns. Inparticular, Flores et. al. present elements that constitute a general object-oriented design and theirformal model, and explain how to formally link a design to a pattern, which has a formal modeland properties that must be satisfied. However, as already said, we transform a particular designwith the aim of obtaining a new design according to a design or architectural pattern.

Lano et al. [53] formally justify design patterns by relating two sets of classes, the “before”and “after” systems. The “after” system consists of a collection of classes organised according toa pattern. The proof that the “after” system is an extension of the “before” one is given via asuitable interpretation that is proved for selected axioms. Differently, we adopt a transformationalapproach that is based on rules, and not on the verification that a system extends the originalsystem.

146 CHAPTER 6. REFACTORING TOWARDS PATTERNS

Chapter 7

Conclusions

In order to preserve behaviour, changes to a software must be carried out in a disciplined way.One way of imposing a discipline to software transformation is by using formal methods either in aguess-and-verify approach, which requires a transformation to be proved to preserve the semanticsof the original system, or in a constructive approach, in which case a system is transformed intoanother one by the application of laws. In this thesis, we adopted a constructive approach tosoftware transformation based on algebraic rules. These rules correspond mainly to some of therefactoring practices documented by Fowler [42] and Opdyke [69].

We presented a set of refactoring rules along with their derivation in terms of basic laws ofobject-oriented programming [14, 17], and laws of data refinement. These laws were expressedin the language rool, which includes recursive classes, visibility control, dynamic binding, andrecursive methods. Also, it includes specification constructs from the refinement calculi. It has acopy semantics rather than a reference semantics. The semantics of rool is given by means ofpredicate transformers. The laws were proved correct against this semantics and simulation laws.The refactoring rules presented deal, mainly, with the structure of classes and their relationships.

The laws of classes (see Appendix E) are essential for the derivation of refactoring rules. Indeed,these laws play the role of the basic refactorings that Opdyke presents in his thesis [69]. In fact, theselaws can be viewed as the most basic refactorings that can be used to define other refactorings [50].Moreover, these laws comprise a comprehensive set, which is useful for reducing programs to anormal form described in terms of a restricted subset of rool [17, 16]. On the other hand, we havenot used all the laws of commands (see Appendix D); we have used mainly laws that deal withintroduction of class invariants as assumptions, and introduction of parameterised commands.

Besides the formalisation of existing refactoring practice, we have also presented some newrefactoring rules that are used for the derivation of other refactoring rules and patterns. Wehave presented the formalisation of one design pattern and of one architectural pattern. However,differently from the presentation of the refactoring rules, both kinds of patterns are not presentedas rules. The reason is that we can characterise only the final result (what would be the right-hand side of a rule), whereas the left-hand side would correspond to any system that needs to be

148 CHAPTER 7. CONCLUSIONS

refactored to achieve a system that is in accordance with a pattern. Writing a rule would restrictits application to systems that match the left-hand side. Instead of a single rule application, weachieve a system that conforms to a pattern by means of refactoring rule applications. Surprisingly,we identified another refactoring rule.

The derivation of refactoring rules may also be based on other refactoring rules. For instance,one of the steps of the derivation of 〈Extract Superclass〉 is the application of the refactoring〈Pull Up/Push Down Field〉. Consequently, we consider the 〈Pull Up/Push Down Field〉 to be abasic refactoring, while the refactoring 〈Extract Superclass〉 is a derived one, in the sense that itsderivation uses not only laws of classes, but also refactoring rules.

The proofs of the refactoring rules by the application of laws of object-oriented programmingconfirm the effectiveness of object-oriented refinement calculi for the development of programs.To our knowledge, this is the first time an object-oriented refinement calculus is applied to proveprogram transformations like refactorings. Moreover, the laws of rool provide guidance on theconstruction of programs.

The formalisation of refactorings revealed new laws of rool. Some of these laws were previouslyknown for imperative programming, but were not initially proposed for rool. Examples of theselaws are those that deal with introduction of parameterised commands from a non-parameterisedcommand. Other laws make sense only in the context of object-oriented programming like, forinstance, the one for introducing innocuous assumptions about objects whose attributes are alreadyinspected in a program (law Law 47 〈innocuous assumption-reading〉). We have also presented newlaws for dealing with the expression new and the extends clause. These laws allowed us to deriverefactorings that change an inheritance hierarchy by removing a class from it, and also extractinga superclass from two classes. We have also presented a (new) simulation law that is applicable toa class hierarchy instead of a single class (law Law 109 〈superclass attribute-coupling invariant〉).This law is a result of a joint work [17, 16].

The presentation of the refactoring rules in rool, a subset of sequential Java, does not implylack of expressiveness of these rules. We dealt with rules that change the structure of classes inthe sense that we can, for instance, extract methods, move methods between classes, parameterisemethods, change the name of methods, and move attributes between classes in a hierarchy. Forthese, rool is sufficiently expressive to make our results meaningful in practice.

A limitation of our work is that we restricted the set of refactoring rules to those that dealmainly with the structure of classes, and with attributes and methods. We have not presentedrules that deal with data sharing because rool has a copy semantics. For this reason, it is notpossible to describe refactorings like Duplicated Observed Data [42, p. 189]. Refactoring rules whosederivations involve data refinement may also be invalid in the presence of pointers, as they involvespecification statements in which only the values of the variables in the frame can be changed. Infact, all refactoring rules must be reviewed when using a language with pointers.

Another limitation is that, from an arbitrary command, we cannot introduce a parameterised

7.1. RELATED WORK 149

command with an object as argument, if such object is a method call target. The reason isthe application of laws Law 62 〈var block-val〉 and Law 63 〈var block-res〉, depending on the kindof parameter passing mechanism to be used. These laws are the first step for the introductionof parameterised command. Both laws requires the variables to be passed as arguments not tobe method call targets. This has limited the types of parameters of parameterised commandswe introduce in derivations to be basic because there is no sense in passing an objects as anargument on which no method can be called. Consequently, refactoring rules like, for instance,〈Extract/Inline Method〉 involves only arguments of basic type. For instance, for introducing aparameterised command with a value argument, we apply law 〈var block-val〉var block-val leadingto the declaration of a local variable and an assignment of the variable to be passed as argumentto the local variable. Also, variable to be passed as argument is substituted with the (new) localvariable. In a parameterised command, if the variable we pass as a value argument is a methodcall target, any change to this argument, due to the method call, is not reflected in the variable ispass as argument. This is a consequence of the copy semantics of rool. In a reference semantics,the restriction on the basic types of arguments should be discarded.

Also, we have not formalised refactorings that involve class methods and class variables. Thesefeatures are not available in rool, but they are in Java. As a consequence, it is not possible todescribe, for instance, refactorings that deal with the replacement of type codes with subclasses,since type codes are described using class variables.

We presented refactoring rules in which we deal with just one attribute (rule 〈Move Attribute〉,Rule 4.3, for instance) and one method (for instance, rule 〈Move Method〉, Rule 4.2). O Thissimplified derivation of refactoring rules because we do not have tool support yet. Certainly, dealingwith more than one attribute and one method is is more appropriate in a context in which a toolgives support to refactorings, as it could deal more easily with an arbitrary number of attributesand methods.

The proof of the simulation laws presented in Section 3.5.1 is beyond the scope of this work.Simulation has already been addressed in [23], with respect to its soundness. This is still an ongoingresearch subject.

7.1 Related Work

Most of the refactoring rules that we considered are based on those presented by Fowler [42].However, the approach adopted by Fowler is informal, based on program compilation and tests. Inour approach, refactoring rules are presented with a meta-program on the left-hand side and anotherone on the right-hand side, along with side-conditions for the application of the rule. Besides that,we present the proof of correctness of the refactorings by the program derivation. The rules wederived slightly differ from those of Fowler. The differences involve, for instance, the number ofattributes and classes involved in a refactoring.

150 CHAPTER 7. CONCLUSIONS

Fowler’s work is highly dependent on compilation. This is evidenced, for instance, in therefactoring Rename Method, in which interfaces are not mentioned. Even though rool does notprovide interfaces as in Java, the description of the refactoring rule for method renaming (Rule 5.6)allowed perceiving the need for mentioning interfaces in the Fowler’s refactoring. In refactoringExtract Superclass [42, p. 336], Fowler only addresses changes of clients of subclasses that couldbe changed to use the superclass. However, there is no condition concerning type tests involvingvariables whose types are changed to the superclass. Again, the verification of this situation is leftto compilers.

Some refactorings proposed by Opdyke are “low-level refactorings” [69, Chapter 5] and are, infact, programming laws of rool. This is the case of the refactoring that deal with the introductionof attributes, for instance. Other refactorings by Opdyke are described here as refactoring rules.For instance, the refactoring abstract access to member variable corresponds to the refactoringrule 〈Encapsulate Field〉 (Rule 5.8). Opdyke uses “low-level refactorings” refactorings to createan abstract superclass, for instance. We take a similar approach: the programming laws of rool

serve as the basis for the derivation of the refactoring rules we presented. We have not derived anyrefactoring rule using the semantics of rool directly.

Opdyke proposes a set of preconditions that need to be satisfied in order for the program trans-formation to be behaviour preserving. In our approach, each refactoring rule has side-conditions forthe application of a refactoring. If the conditions are not satisfied, the refactoring rule cannot beapplied. However, Opdyke does not describe formally the effect of the application of a refactoring.This is done by Roberts [74] who extended the work of Opdyke with postconditions. In both works,preconditions and postconditions are written as predicates. None of the works present refactoringsas algebraic rules. We describe refactorings between program fragments along with the conditionsthat must be satisfied for the application of a refactoring rule to be valid.

One of the properties that Opdyke identified as being easily violated in if explicit checks werenot made before a program was refactored is Semantically Equivalence and Operations, which isdefined as follows: ”(...) let the external interface to the program be via de function main. Ifthe function main is calle twice (once before and once after a refactoring) with the same set ofinputs, the resulting set of output values must be the same” [69]. Refactoring must satisfy thiscondition. For instance, refactoring change member function name [69, p. 61] requires that if werename a method to the same name of a method that already exists in a superclass of the classthat declares the method we want to rename, then these methods must be semantically equivalent.Of course, they must have the same signatures. To show that methods are semantically equivalent,it is necessary to show that they pass the same tests. However, there is no formal basis to ensuresemantic equivalence between methods, there is no way to derive one method from the other, forinstance, with a basis on laws of programming.

We impose explicit conditions on type tests and casts in some refactoring rules (for instance,Rule 5.3). However, conditions on type tests and casts are not explicit in Opdyke’s work. These

7.1. RELATED WORK 151

conditions are implicit in the property Semantically Equivalent References and Operations, guar-anteeing that the “type of a variable can be changed by a refactoring, as long as each operationreferenced on the variable is defined equivalently for its new type” [69, p.41].

Roberts [74] argues that a suite of tests can be used as a specification and the correctness ofa refactoring can be proved against this specification. However, as is well-known, a suite of testsis able only to uncover errors, not to prove their absence. In order to deal with the correctness ofrefactorings, in our approach the derivation of a refactoring rule is carried out by the use of lawsthat are proved against the semantics of rool.

Mens, Demeyer, and Janssens [61] present a technique for the formalisation of refactorings:graph rewriting. As they use a lightweight approach, they look at notions of behaviour preservationthat can be detected statically. This technique is language independent, but they recognise thatsome refactorings require techniques to deal with complex graphs. Refactorings such as movemethod and push down method are difficult to manipulate by means of graph rewriting. Althoughwe use a specific language for describing and proving refactorings, the features of rool are thosecommonly encountered in object-oriented programming languages used in practice. Also, we dobelieve that presenting the rules as equality and refinement of meta-programs is a more appealingapproach for practical use and automation.

Snelting and Tip [77] presented a method for finding design problems in a class hierarchy bythe analysis of the usage of the hierarchy by a set of applications. The method is based on conceptanalysis. For instance, it is possible to find attributes that are redundant or that can be moved toa subclass, or it is possible to detect situations in which it is appropriate to split a class. Theirwork can be viewed as complementary to ours with respect to the detection and suggestion ofrefactorings.

The Eclipse IDE [37] does not take casts into account in its refactorings. This is a designdecision for the refactoring capabilities of Eclipse [84]. In refactorings in which there are accessesto attributes via cast expressions, a warning is given to the user about these accesses being notpossible after refactoring. This occurs, for instance, in the refactoring for moving a method froma class to its superclass when the method of the subclass accesses an attribute declared in thisclass via an expression with a cast. However, if the method is manually moved, no error is givenduring compilation and the program behaves as before moving the method up to the superclass.The design decision restrictions the program that can be refactored using Eclipse not to use casts.

The Eclipse IDE [37] allowed us to move to a superclass methods with the same name butwith different bodies. This has not preserved the program behaviour because just one of thebodies is moved to the superclasses. In our approach, moving methods that have the samename (and parameters) from classes to the common superclass of the classes in which thesemethods are declared involves the application of laws Law 91 〈move original method to superclass〉and Law 89 〈move redefined method to superclass〉. The last one introduces a conditional in themethod of the superclass. The dynamic type of the object that is target of the method call deter-

152 CHAPTER 7. CONCLUSIONS

mines the code which code must be executed. But, this is not the case of the refactoring in Eclipse,leading to a program behavior different from the one before refactoring. In the case of moving amethod from a superclass to subclasses, excluding one of the subclasses whose instances are targetof calls to such method, no warning is given to the user about the introduction of errors in theprogram with this change. Only at compilation time, an error is reported.

7.2 Future Work

In this work, we used a simulation law that is applicable to a class hierarchy instead of a sin-gle class (law Law 109 〈superclass attribute-coupling invariant〉). However, the proof of this lawis not available yet and is beyond the scope of the present work. Changing data representationin a single class can be viewed as the traditional module data refinement. Differently from thelaw Law 108 〈private attribute-coupling invariant〉, whose soundness has already been proved [25],dealing with data refinement in a class hierarchy is a new issue whose soundness must be investi-gated, assuring that simulation of a class hierarchy entails refinement of such a hierarchy. This isone future direction of work.

Data refinement between attributes of different classes usually involved attributes declaredby classes, not inherited ones. For instance, for the elimination of a client relationship betweena class A and a class B , we eliminate every call to methods of B that appears inside A. Werestricted methods of B just to access attributes declared in B itself. We have not dealt withpossibly inherited attributes that could be accessed inside methods of B that are called by A. Itis necessary to investigate data refinement laws that deal with inherited attributes in situations asthe one just described.

The formalisation of refactorings involves the application of several laws for commands, classes,and simulation. The activities of elaboration and presentation of these laws, the presentation oftheir proofs and their application are very tedious and error-prone. This highlights the need ofusing a theorem prover to check proofs both of laws and of refactorings. In this way, we canimprove the reliability of the refactorings. Previous experience in the automation of a normal formstrategy for rool, presented in [57], may serve as guide for the right direction to be followed forautomatic proofs of refactorings.

Dealing with pointers in rool is also a topic of future research. This new feature will allow us todevelop new refactoring rules like Duplicated Observed Data [42, p. 189]. It will be possible to derivepatterns like Observer [43, p. 293]. Laws of commands of rool should be reviewed to guaranteetheir validity in a reference semantics. Also, laws that involve specification statements, like thoseof data refinement, should be reviewed, since frames in specifications restrict the variables that canbe modified. It is necessary to investigate how to deal with frames of specification statement in areference semantics. On the other hand, the laws for object-oriented features do not rely on copysemantics, except one for change of data representation.

7.2. FUTURE WORK 153

The development of a tool to support program transformation based on the refactoring rules wepresented here is another direction for future research. It is necessary, for instance, to investigatetechniques that can be used to determine if the conditions of a refactoring rule are satisfied, allowingits application.

154 CHAPTER 7. CONCLUSIONS

Appendix A

Derivation of Compositional

Refactoring Rules

In this appendix, we present derivations of refactorings rules presented in Chapter 4.

A.1 Delegation Elimination

Derivation. From 〈inline delegate〉 (Figure A.1) and 〈(undo)inline delegate〉 (Figure A.2).

A.1.1 inline delegate

Derivation

class A extends Cpri b : B ; adsameth m = (pds • self .b.n(α(pds)))mtsanew = self .b := new B

end

class Bpri x : Tmeth n = (pds • c)mtsb

end

= Law 85 〈change visibility: from private to public〉 (l/r), Law 95 〈method call elimination〉 (l/r)

class A extends Cpri b : B ; adsameth m = (pds • {self .b 6= null ∧ self .b 6= error} (pds • c)[self .b/self ](α(pds)))mtsanew = self .b := new B

end

156 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

class A extends Cpri b : B ; adsameth m = (pds • b.n(α(pds)))mtsa

endclass B

pri x : Tmeth n = (pds • c)mtsb

end

vcds,c

class A extends Cpri x : T ; adsameth m = (pds • c)mtsanew = self .b := new B

endclass B

pri x : Tmeth n = (pds • c)mtsb

end

provided

super does not appear in n;b 6= null ∧ b 6= error is an invariant of A;self .a does not appear in n, for any public or protected attribute a that is declared

by D or by any of its superclasses;self .p does not appear in n, for any method p declared in mtsb or in any super-

classes of B ;self .b does not appear in mtsa ;x is not declared in adsa nor in any superclass or subclass of A;

Figure A.1: Law 〈inline delegate〉

class A extends Cpri b : B ; adsameth m = (pds • {self .b 6= null ∧ self .b 6= error} c[self .b/self ])mtsanew = self .b := new B

end

¹ Law 108 〈private attribute-coupling invariant〉

CI = self .x = self .b.x

class A extends Cpri x : T ;pri b : B ; adsameth m = (pds • {self .b 6= null ∧ self .b 6= error} CI (c[b/self ]))CI (mtsa)new = self .b := new B

end

A.1. DELEGATION ELIMINATION 157

v Law 77 〈remove assumption〉, Law 16 〈; −skip unit〉

class A extends Cpri x : T ;pri b : B ; adsameth m = (pds • c[self .b/self ])mtsanew = self .b := new B

end

= Law 83 〈attribute elimination〉 (r/l)

class A extends Cpri x : T ; adsameth m = (pds • CI (c[self .b/self ]))CI (mtsa)

end

Finally, we apply Law 85 〈change visibility: from private to public〉, from right to left, to changethe visibility of attribute x of class B to private.

A.1.2 (undo) inline delegate

class A extends Cpri x : T ; adsameth m = (pds • c)mtsa

end

class Bpri x : Tmeth n = (pds • c)mtsb

end

= [Definition: (pds • c) = (pds • (pds • c)(α(pds)))]

class A extends Cpri x : T ; adsameth m = (pds • (pds • c)(α(pds)))mtsa

end

= Law 85 〈change visibility: from private to public〉 (l/r),Law 108 〈change visibility: from private to public〉

158 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

class A extends Cpri x : T ; adsameth m = (pds • c)mtsa

endclass B

pri x : Tmeth n = (pds • c)mtsb

end

vcds,c

class A extends Cpri b : B ; adsameth m = (pds • self .b.n(α(pds)))mtsanew = self .b := new B

endclass B

pri x : Tmeth n = (pds • c)mtsb

end

provided

super does not appear in n;

b 6= null ∧ b 6= error is an invariant of A;

b is not declared in adsa nor in any superclass or subclass of A;

self .x does not appear in mtsa ;

Figure A.2: Law 〈(undo)inline delegate〉

CI = self .x = self .b.x ∧ self .b 6= null ∧ self .b 6= error

class A extends Cpri b : B ;pri x : T ; adsameth m = (pds • (pds • CI (c))(α(pds)))new = self .b := new Bmtsa

end

class Bpub x : Tmeth n = (pds • c)mtsb

end

v [Assignment, specifications, and guards diminution]

class A extends Cpri b : B ;pri x : T ; adsameth m = (pds • (pds • c)[self .b/self ](α(pds)))new = self .b := new Bmtsa

end

A.2. INLINE CLASS 159

= Law 107 〈introduce class invariant〉 (l/r), Law 53 〈assumption before or after command〉 (r/l)

class A extends Cpri b : B ;pri x : T ; adsameth m = (pds • {self .b 6= null ∧ self .bneqerror} (pds • c)[self .b/self ](α(pds)))new = self .b := new Bmtsa

end

= Law 95 〈method call elimination〉 (r/l)

class A extends Cpri b : B ;pri x : T ; adsameth m = (pds • self .b.n(α(pds)))new = self .b := new Bmtsa

end

Finally, we apply Law 85 〈change visibility: from private to public〉, from right to left, to changethe visibility of attribute x of class B to private.

A.2 Inline Class

For the derivation of the refactoring rule 〈Inline Class〉 we copy attributes of B to A all clients ofthat class and eliminate calls to methods of B that appear in A.

160 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

We begin the derivation with the left-hand side of the rule.

class A extends Cpri b : B ; adsa ;meth getX = (res arg : T • self .b.getX (arg))meth setX = (val arg : T • self .b.setX (arg))meth m = (pds • cm [self .b.m(α(pds))])new = b := new B();mtsa

endclass B

pri x : T ;meth getX = (res arg ′ : T • arg ′ := self .x )meth setX = (val arg ′ : T • self .x := arg ′)meth m = (pds •

cm [var aux : T • self .getX (aux );le := exp1[aux ]end,self .setX (exp2), α(pds)])

end

We eliminate the clientship relation between A and B The attribute x of B is copied to A andall methods of B that are called from A are also copied to A. Calls to methods of B are replacedwith calls to the methods we copied from B to A. The attribute b initially present in A is removedfrom this class.

= 〈Clientship Elimination〉 (l/r)

class A extends Cpri x : T ; adsa ;meth getX = (res arg : T • self .bgetX (arg))meth setX = (val arg : T • self .bsetX (arg))meth bgetX = (res arg ′ : T • arg ′ := self .x )meth bsetX = (val arg ′ : T • self .x := arg ′)meth m = (pds • cm [self .p(α(pds))])meth p = (pds •

cp [var aux : T • self .bgetX (aux );le := exp1[aux ]end,self .bsetX (exp2), α(pds)])

mtsaend

We eliminate calls inside A that have self as target. We do this by applying the laws methodcall and parameterised command elimination.

A.2. INLINE CLASS 161

= Lemma 1(l/r)(4x),Law 64 〈pcom elimination-val〉(l/r)(2x), Law 62 〈var block-val〉(r/l)(2x),Law 65 〈pcom elimination-res〉(l/r)(2x),Law 63 〈var block-res〉(r/l)(2x),

class A extends Cpri x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)meth bgetX = (res arg ′ : T • arg ′ := self .x )meth bsetX = (val arg ′ : T • self .x := arg ′)meth m = (pds • cm [self .p(α(pds))])meth p = (pds •

cp [var aux : T • aux := self .x ; le := exp1[aux ]end,self .x := exp2, α(pds)])

mtsaend

In the command cp we can eliminate the variable aux . We replace the occurrence of aux inthe expression exp1 with the expression self .x that is assigned to aux . After this, we advance theassignment to aux with respect to the assignment to le. We can do it because aux does not appearin the assignment to le.

= Law 60 〈assignment seq comp exp substitution〉 (r/l), Law 59 〈order independent assignment〉

cp [var aux : T • le := exp1[self .x ]; aux := self .x end, self .x := exp2, arg ′])

At this point, we can eliminate the assignment to aux because it is at the end of the localvariable block. We do this by applying law Law 30 〈var− := final value〉. The only commandpresent in the block that declares aux is the assignment to le, in which there are no occurrencesof aux . We can remove this variable by applying law Law 25 〈var elim〉.

= Law 30 〈var− := final value〉 (l/r), Law 25 〈var elim〉 (l/r)

cp [le := exp1[self .x ], self .x := exp2, arg ′])

As the methods bgetX and bsetX were introduced in a previous step, they are not called insideA, we can remove them.

162 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

= Law 90 〈method elimination〉 (l/r)(2x)

class A extends Cpri x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)meth m = (pds • cm [self .p(α(pds))])meth p = (pds • cp [le := exp1[self .x ], self .x := exp2, α(pds)])mtsa

end

This finishes the derivation of 〈Inline Class〉.2

A.3 Self Encapsulate Field

We begin the derivation with the class A that appears on the left-hand side of Rule 4.10.

class Apri x : T ; adsameth m1 = (pds1 • c1[le1 := exp1[x ], self .x := exp2])new = (val arg : T • self .x := arg)mtsa

end

First, we introduce setting and getting methods for the variable x that we want to be selfencapsulated.

= Law 90 〈method elimination〉 (r/l) (2x)

class Apri x : T ; adsameth m1 = (pds1 • c1[le1 := exp1[x ], self .x := exp2])meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)new = (val arg : T • self .x := arg)mtsa

end

We concentrate on commands of the form le := exp1[x ] in which the variable x occurs in theexpression exp1 and is directly read. The first step to eliminate such direct access is to declare avariable to capture the value to of the attribute x . According to a condition to the application ofthis rule, the variable aux is new.

A.3. SELF ENCAPSULATE FIELD 163

= Law 25 〈var- elim〉 (r/l)

var aux : T • {self 6= null ∧ self 6= error} le1 := exp[x ]end

We assign the variable x to aux at the end of the scope of the last variable.

= Law 30 〈var- := final value〉

var aux : T • {self 6= null ∧ self 6= error} le1 := exp1[x ]; aux := x end

The variable aux is new, allowing us to move the assignment aux := x to be placed before theassignment to le.

= Law 59 〈order independent assignment〉

var aux : T • {self 6= null ∧ self 6= error} aux := x ; le1 := exp1[x ] end

The variable x that is assigned to aux also occurs in the expression exp1. We substitute thisoccurrence of x with the variable aux .

= Law 60 〈assignment seq comp exp substitution〉

var aux : T • aux := x ; le1 := exp[aux ]end

As we want to indirectly access the variable x , we need to introduce a call to getX . Wedeclare a variable p aux to which is assigned the variable x and replace the aux with p aux in thecommand aux := x .

= Lemma 10 (l/r)

var aux : T •{self 6= null ∧ self 6= error} (res arg : T • arg := b.x )(aux ) ¢

le1 := exp[aux ]end

The parameterised command obtained in the previous step is equal to the one that defines themethod getX . So, we introduce a call to such method, obtaining the following program.

164 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

= Lemma 1 (r/l)

var aux : T •self .getX (aux )le1 := exp[aux ]

end

For commands of the form self .x := exp2 we proceed as follows. We declare the variablep arg to which we assign the expression exp2. That variable substitutes the expression exp2 in theassignment to self .x .

{self 6= null ∧ self 6= error} self .x := exp2

= Lemma 9 (l/r)

{self 6= null ∧ self 6= error} (val arg : T • self .x := arg)(exp2)

This parameterised command, not taking into account the application to the argument exp2, isthe same as that of method setX . So, we introduce a call to this method.

= Lemma 1(r/l)

self .setX (exp2)

The same steps for introducing a call to the method setX above are followed for changing theinitialiser of class A and introducing the same method call. The final class A is as follows.

class Apri x : T ; adsameth m1 = (pds1 • c[var aux : T • self .getX (aux );

le1 := exp1[aux ]end, self .setX (exp2)])meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)new = (val arg : T • self .setX (arg)) mtsa

end

A.4 Decompose Conditionals

For the derivation of this refactoring, it is necessary to parameters with a specific passing mecha-nism, not the abstract list of parameters pds. Also, we consider variable a and b, c and d to appearin commands cm1 and c′m1

. We suppose that variables a and c hold information for the branches of

A.4. DECOMPOSE CONDITIONALS 165

the alternation; variables b and c are used to get values that results from the branches. We couldthink about these variables as parameters value parameters (a and c) and result parameters (b andd) of method m1. For simplicity, we assume these variables have type T . We begin the derivationwith the class A of the left-hand side of the rule.

class Aadsameth m1 = (pds1 •

if exp → cm1 [a, b][] ¬ exp → c′m1

[c, d ]fi)

mtsaend

First, we introduce the methods m2, m3, and m4. The body of method m2 is a parameterisedcommand that has a result argument that returns to the caller the boolean value of the expressionexp. We define the methods m3 and m4 with parameterised commands that have parameterspassed by value-result. The commands that appear in these methods are those in the branches ofthe alternation.

= Law 90 〈method elimination〉 (r/l)(3x)

class Aadsameth m1 = (pds1 •

if exp → cm1 [a, b][] ¬ exp → c′m1

[c, d ]fi)

meth m2 = (res arg : bool • arg := exp)meth m3 = (val arg1 : T ; res arg2 : T • cm1 [arg1, arg2])meth m4 = (val arg3 : T ; res arg4 : T • c′m1

[arg3, arg4])mtsa

end

We declare a the boolean variable b in method m1.

166 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

= Law 25 〈var elim〉 (r/l)

meth m1 = (pds1 •var b : bool •

if exp → cm1 [a, b][] ¬ exp → c′m1

[c, d ]fi

end)

At the end of the scope of the variable b, we assign the expression exp to b.

= 〈var- := final value〉var- := final value (r/l)

meth m1 = (pds1 •var b : bool •

if exp → cm1 [a, b][] ¬ exp → c′m1

[c, d ]fi;b := exp

end)

Since b is new—it does not occur in the alternation—, we can move the assignment to it to beplaced in the beginning of the variable block.

= Law 59 〈order independent assignment〉

meth m1 = (pds1 •var b : bool • b := exp;

if exp → cm1 [a, b][] ¬ exp → c′m1

[c, d ]fi

end)

The expression exp occurs in the guards of the alternation. We replace it with the variable bto which is assigned the boolean value of exp.

= Law 60 〈assignment seq comp exp substitution〉

meth m1 = (pds1 •var b : bool • b := exp; ¢

if b → c[] ¬ b → c′

fiend)

A.4. DECOMPOSE CONDITIONALS 167

The command b := exp is similar to that present in the method m2. We introduce a call to suchmethod by introducing a variable block in which we replace the variable b with the new variablep arg . At the end of the block of variable p arg , we assign it to b.

= Law 63 〈var block-res〉 (l/r)

var p arg : bool •p arg := exp;b := p arg

end

We introduce a parameterised command that corresponds to the variable block we declared inthe previous step.

= Law 65 〈pcom elimination-res〉 (l/r)

(res arg : bool • arg := exp)(b)

We obtained exactly the parameterised command in the body of method m2, applied to theargument b.

= Lemma 1 (r/l)

self .m2(b)

The class A now is as follows.

class Aadsameth m1 = (pds1 •

var b : bool • self .m2(b);if b → cm1 [a, b] ¢

[] ¬ b → c′m1[c, d ]

fiend)

meth m2 = (res arg : bool • arg := exp)meth m3 = (vres arg3 : T3 • c[arg3])meth m4 = (vres arg4 : T4 • c′[arg4])mtsa

end

We proceed by introducing calls to the methods m3 and m4 from the guarded commands cm1

168 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

and c′m1. The steps we follow are similar to those we have used to introduce the call to the

method m2. First we introduce variable blocks with assignments according to the parameter pass-ing mechanism we intend to use; here the mechanisms are value and result. Then we introduceparameterised commands that correspond to the variable blocks just introduced.

The same steps are followed for introducing a call to the method m4 from the command c′m1.

The final class A is the following.

class Aadsameth m1 = (pds1 •

var b : bool • self .m2(b);if b → self .m3(ai)[] ¬ b → self .m4(aj )fi

end)meth m2 = (res arg : bool • arg := exp)meth m3 = (vres arg3 : T3 • c[arg3])meth m4 = (vres arg4 : T4 • c′[arg4])mtsa

end

This finishes the derivation of the refactoring rule 〈Decompose Conditional〉, which is presentedonly by Fowler [42].

2

This refactoring improves legibility, making a method clearer by clarifying reasons for branchesof the alternation. Names of methods being extracted have a crucial role in improving legibility.We can see this refactoring as the application of 〈Extrac/Inline Method〉, from left to right, forguards and for each branch of the alternation.

A.5 Introduce Explaining Variable

We begin the derivation of Rule 4.12 with the command c in which there is an occurrence of theexpression e.

c[e]

First we introduce a variable that is used to hold the values of the expression we want to makeclear its purpose.

= Law 25 〈var elim〉 (r/l)

var x : T • c[e] end

A.6. CONSOLIDATE CONDITIONAL EXPRESSION 169

At the end of the variable block, we assign to x the expression e.

= Law 30 〈var- := final value〉

var x : T • c[e]; x := e end

As the variable x is new, we can move the assignment of e to x just before the command c[e].

= Law 59 〈order independent assignment〉

var x : T • x := e; c[e] end

We replace the occurrences of e with x in the command c[e] based on the fact that x is new,thus not free in c.

= Law 60 〈assignment seq comp exp substitution〉

var x : T • x := e; c[x ] end

A.6 Consolidate Conditional Expression

The cases covered in refactoring 〈Consolidate Conditional Expression〉 are those of two basic lawsof rool that deal with alternations.

Cases

• Or: Law 8 〈if - ∨ distrib1 〉

• And:Law 11 〈if - ∧ distrib〉

A.7 Consolidate Duplicate Conditional Fragments

This refactoring is, in fact, the basic law of rool that deal with the distribution of a commandover an alternation.

• Law 20 〈;-if left dist〉

A.8 Substitute Algorithm

This rule is a direct consequence of law Law 67 〈command refinement-class refinement〉.

170 APPENDIX A. DERIVATION OF COMPOSITIONAL REFACTORING RULES

Appendix B

Derivation of Contextual Refactoring

Rules

In this appendix, we present derivations of refactoring rules presented in Chapter 5.

B.1 Add/Remove Parameter

The derivation of rule 〈Add/Remove Parameter〉 follows the strategy below.

1. Moving of all definitions of the method m to the topmost class that first introduces a definitionfor it;

2. Elimination of calls to the method m;

3. Addition of the new parameter pd to the parameterised command that resulted from step 2;

4. Elimination of the method with the original number of parameters;

5. Introduction of method m with the desired number of parameter.

6. Introduction of calls to the new method;

7. Moving down of the definition of method m to the subclasses of the topmost class that firstintroduces a definition of such method.

Writing the new parameter as pd gives a programmer the opportunity to add a parameter witha value or a result parameter passing mechanism. The refactoring Add Parameter presented byFowler [42] is a particular case of the one presented here because he considers just information thata method needs from its callers. In our refactoring, the programmer may also define informationthat a method may return to its callers.

172 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

An example for 〈Add/Remove Parameter〉

We consider the following sequence of class declarations. The method m is defined by a parame-terised command with the value parameter x . Our aim is to add the value parameter y .

class Dadscmeth m = (val x : T • cd [exp])mtsc [self .m(a)]

endclass B extends D

adsbmeth m = (val x : T • cb [exp])mtsb [self .m(a)]

endcds[le.m(a)] • c[le.m(a)]

class A extends Dadsameth m = (val x : T • ca [exp])mtsa [self .m(a)]

endclass C extends A

adscmtsc [self .m(a)]

end

The first step is to move all definitions of m to the topmost class of A that first introduces adefinition of m. In our example, we have to move all definitions to D .

= Lemma 2

class Dadscmeth m = (val x : T •

if self is B → c′b [exp][] ¬ (self is B) → if self is A → cd [exp]

[] ¬ (self is A) → if (A)self is C → c′c [exp][] ¬ ((A)self is C ) → c′a [exp]fi

fifi)

mtsd [{self 6= null ∧ self 6= error} (val x : T • cd [exp])(a)]end

B.1. ADD/REMOVE PARAMETER 173

class B extends Dadsbmtsb [{self 6= null ∧ self 6= error}

(val x : T • cb)(a)]endclass A extends D

adsamtsa [{self 6= null ∧ self 6= error}

(val x : T • ca [exp])(a)]end

class C extends Aadscmtsc [{self 6= null ∧ self 6= error}

(val x : T • cc [exp])(a)]end

We eliminate every method call le.m(a) in cds, and c. Let us consider the following methodcall where the type of the left-expression le is given by any class in the hierarchy of D .

le.m(a)

= Law 95 〈method call elimination〉 (l/r)

{le 6= null ∧ le 6= error}(val x : T • if le is B → c′b [exp][] ¬ (le is B) → if le is A → cd [exp]

[] ¬ (le is A) → if (A)le is C → c′c [exp][] ¬ ((A)le is C ) → c′a [exp]fi

fifi)(a)

The Lemma 9 introduces a parameterised command with a value argument from a non-parameterisedcommand. It can be found in Appendix C.

= Lemma 9

{le 6= null ∧ le 6= error}(val x : T •

(val y : T •if le is B → c′b [y ][] ¬ (le is B) → if le is A → cd [y ]

[] ¬ (le is A) → if (A)le is C → c′c [y ][] ¬ ((A)le is C ) → c′a [y ]fi

fifi)(exp))(a)

174 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

= Law 66 〈pcom merge〉

{le 6= null ∧ le 6= error}(val x : T ; val y : T •if le is B → c′b [y ][] ¬ (le is B) → if le is A → cd [y ]

[] ¬ (le is A) → if (A)le is C → c′c [y ][] ¬ ((A)le is C ) → c′a [y ]fi

fifi)(a, exp)

In the class D we eliminate the old method m and introduce a new method m defined by thesame parameterised command we obtained in the previous step.

= Law 90 〈method elimination〉 (l/r), Law 90 〈method elimination〉 (r/l)

class Dadsc

(val x : T ; val y : T •if le is B → c′b [y ][] ¬ (le is B) → if le is A → cd [y ]

[] ¬ (le is A) → if (A)le is C → c′c [y ][] ¬ ((A)le is C ) → c′a [y ]fi

fifi)(a, exp)

mtsd [{self 6= null ∧ self 6= error} (val x : T ; val y : T • cd [y ])(a, exp)]end

Now we introduce calls to the new method m. This step is carried out in every point of theprogram in which there was an original call to m. In other words, we introduce method calls toeach composition of an assumption about an object of type D , or any of its subclasses, and theparameterised command the defines the method m in D .

{le 6= null ∧ le 6= error}(val x : T ; val y : T •if le is B → c′b [y ][] ¬ (le is B) → if le is A → cd [y ]

[] ¬ (le is A) → if (A)le is C → c′c [y ][] ¬ ((A)le is C ) → c′a [y ]fi

fifi)(a, exp)

B.2. SEPARATE QUERY FROM MODIFIER 175

= Law 95 〈method call elimination〉 (r/l)

le.m(a, exp)

The last step is to move down the definition of m from D to its subclasses. We use Lemma 3which moves a definition of a method down in the hierarchy of the class that first introduces adefinition for it.

= Lemma 3

class Dadscmeth m = (val x : T ; val y : T • cd [y ])mtsc [self .m(a, exp)]

endclass B extends D

adsbmeth m = (val x : T ; val y : T • cb [y ])mtsb [self .m(a, exp)]

endcds[le.m(a, exp)] • c[le.m(a, exp)]

class A extends Dadsameth m = (val x : T ; val y : T • ca [y ])mtsa [self .m(a, exp)]

endclass C extends A

adscmtsc [self .m(a, exp)]

end

This finishes the example for rule 〈Add/Remove Parameter〉.2

B.2 Separate Query From Modifier

We begin the derivation by changing the visibility of the private attribute x .

class Apri x : T ; adsa ;meth getSetX = (val arg1 : T ; res arg2 : T • arg2 := self .x ; self .x : arg1)mtsa

end

= Law 85 〈change visibility: from private to public〉

class Apub x : T ; adsa ;meth getSetX = (val arg1 : T ; res arg2 : T • arg2 := self .x ; self .x : arg1)mtsa

end

For all commands le.getSetX (a1, a2) that appear in cds and c, we proceed as follows. First, we

176 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

eliminate the call to the method getSetX of class A, and separate the parameters, resulting in thefollowing sequential composition of commands.

le.getSetX (a1, a2)

= Law 95 〈method call elimination〉(l/r)

{le 6= null ∧ le 6= error} (val arg1 : T ; res arg2 : T • arg2 := le.x ; le.x := arg1)(a1, a2)

= Law 66 〈pcom merge〉(l/r)

{le 6= null ∧ le 6= error} (val arg1 : T • (res arg2 : T • arg2 := le.x ; le.x := arg1)(a2))(a1)

We eliminate the parameterised commands we obtained in the last step of the derivation,resulting in the following program.

= Law 65 〈pcom elimination-res〉(l/r), Law 64 〈pcom elimination-val〉(l/r)

{le 6= null ∧ le 6= error}var p arg1 : T •

p arg1 := a1;var p arg2 : T •

p arg2 := le.x ;le.x := p arg1;a2 := p arg2

endend

We move the assignment p arg1 := a1 inside the block that declares the variable p arg2, as thisvariable does not occur in the assignment. Our intention is to obtain two separated variable blocks,the first assigning a value to le.x , and the second just reading le.x and assigning the value read tothe local variable p arg2.

B.2. SEPARATE QUERY FROM MODIFIER 177

= Law 29 〈var-; right dist〉(l/r)

{le 6= null ∧ le 6= error}var p arg1 : T •

var p arg2 : T •p arg1 := a1; ¢

p arg2 := le.x ;le.x := p arg1;a2 := p arg2

endend

The order in which the assignments to the variables p arg1 and p arg2 occur is irrelevant, asp arg1 and p arg2 are not free in the assigning expressions.

= Law 59 〈order independent assignment〉 (l/r)

{le 6= null ∧ le 6= error}var p arg1 : T •

var p arg2 : T •p arg2 := le.x ;p arg1 := a1;le.x := p arg1;a2 := p arg2 ¢

endend

We also move the assignment to the variable a2 to just after the assignment p arg2 := le.x .

= Law 59 〈order independent assignment〉 (r/l)(2x)

{le 6= null ∧ le 6= error}var p arg1 : T •

var p arg2 : T •p arg2 := le.x ;a2 := p arg2;p arg1 := a1;le.x := p arg1

endend

We move the last two assignments outside the block that declares p arg2, obtaining a sequentialcomposition in which the first component is the variable block, and the second component is thesequence of assignments we are moving. We can do this because the variable p arg2 does not occur

178 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

in the assignments.

= Law 28 〈var−; left dist〉(r/l) (2x)

{le 6= null ∧ le 6= error}var p arg1 : T •

var p arg2 : T •p arg2 := le.x ;a2 := p arg2;

end;p arg1 := a1;le.x := p arg1

end

We move the block that declares variable p arg2 outside the block of p arg1, so that now thevariable blocks constitute a sequential composition in which the first component is the block thatdeclares the variable p arg2.

= Law 29 〈var-; right dist〉(r/l)

{le 6= null ∧ le 6= error}var p arg2 : T •

p arg2 := le.x ;a2 := p arg2;

end;var p arg1 : T •

p arg1 := a1;le.x := p arg1

end

We need the assumption {le 6= null ∧ le 6= error} before both variable blocks, as we need themfor introducing method calls later.

B.2. SEPARATE QUERY FROM MODIFIER 179

= Law 54 〈assumption advance command〉 (l/r)

{le 6= null ∧ le 6= error}var p arg2 : T •

p arg2 := le.x ;a2 := p arg2;

end;{le 6= null ∧ le 6= error}var p arg1 : T •

p arg1 := a1;le.x := p arg1

end

As there are no calls to the method getSetX of class A, we can remove this method from suchclass.

class Apub x : T ; adsa ;meth getSetX = (val arg1 : T ; res arg2 : T •

arg2 := self .x ; self .x : arg1)mtsa

end

= Law 90 〈method elimination〉(l/r)

class Apub x : T ; adsa ;mtsa

end

We introduce get and set methods for the attribute x of class A.

= Law 90 〈method elimination〉(r/l) (2x)

class Apub x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

Now we continue by introducing calls to these new methods. Our starting point is the variable

180 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

blocks we have obtained from the original call to method getSetX .

{le 6= null ∧ le 6= error}var p arg2 : T •

p arg2 := le.x ;a2 := p arg2;

end;{le 6= null ∧ le 6= error}var p arg1 : T •

p arg1 := a1;le.x := p arg1

end

First we rename the variables p arg1 and p arg2 to p arg .

= Law 26 〈var rename〉 (2x)

{le 6= null ∧ le 6= error}var p arg : T •

p arg := le.x ;a2 := p arg ;

end;{le 6= null ∧ le 6= error}var p arg : T •

p arg := a1;le.x := p arg

end

We introduce the parameterised commands that correspond to the variable blocks, applied toproper arguments.

= Law 65 〈pcom elimination-res〉 (r/l), Law 64 〈pcom elimination-val〉 (r/l)

{le 6= null ∧ le 6= error} (res arg : T • arg := le.x )(a2);{le 6= null ∧ le 6= error} (val arg : T • le.x := arg)(a1)

The parameterised commands are the same that define the methods setX and getX , respectively.Both are preceded by assumptions about the object denoted by le. Therefore, we can introducecalls to the methods setX and getX of class A.

= Law 95 〈method call elimination〉 (r/l) (2x)

le.setX (a2); le.getX (a1)

B.3. ENCAPSULATE DOWNCAST 181

Finally, we change the visibility of attribute x to private as it is not directly accessed fromoutside A.

class Apub x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

= Law 85 〈change visibility: from private to public〉 (r/l)

class Apri x : T ; adsa ;meth getX = (res arg : T • arg := self .x )meth setX = (val arg : T • self .x := arg)mtsa

end

This finishes the derivation of the rule 〈Separate Query from Modifier〉.2

B.3 Encapsulate Downcast

Derivation. For deriving this refactoring rule, we follow the steps below.

1. Elimination of calls to the method m in cds and c;

2. Elimination of downcasts in the clients;

3. Elimination of the original method m from class A;

4. Introduction of a new method m in A defined by a parameterised command that includes adowncast;

5. Introduction of calls to the newly introduced method m.

For all commands of the form var le2 : M • le.m(le2); y := (N ) le2 end, we proceed as follows.First we eliminate calls to m.

var le2 : M • le.m(le2); y := (N )le2 end

182 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

= Law 95 〈method call elimination〉(l/r)

var le2 : M •{le 6= null ∧ le 6= error} (res arg : M • arg := le1)[le/self ](le2); y := (N ) le2

end

The parameterised command obtained from method elimination is replaced with the commandthat appears within it, with appropriate substitutions of parameters for arguments.

= Lemma 10 (r/l)

var le2 : M • {le 6= null ∧ le 6= error} (le2 := le1)[le/self ]; y := (N ) le2 end

We can introduce a trivial cast with respect to the expression le1. The cast has the same typeas the declared type of le1.

= Law 97 〈introduce trivial cast in expressions〉

var le2 : M • {le 6= null ∧ le 6= error} (le2 := (N ) le1)[le/self ]; y := (N ) le2 end

As there are no occurrences of self in le2, we can simplify the expression (le2 := (N ) le1)[le/self ]to le2 := (N ) le1[le/self ].

= Property of substitution

var le2 : M • {le 6= null ∧ le 6= error} le2 := (N ) le1[le/self ]; y := (N ) le2 end

We change the type of le2 from M to N by applying the law Law 99 〈change variable type〉. Wecan do this because the type of the expression that is assigned to le2 is a subtype of the declaredtype of le2.

= Law 99 〈change variable type〉

var le2 : N • {le 6= null ∧ le 6= error} le2 := (N ) le1[le/self ]; y := (N ) le2 end

We write the specification statement that corresponds to the assignment to le2.

= Law 78 〈simple specification〉 (l/r)

var le2 : N • {le 6= null ∧ le 6= error} le2 : [le2 = (N ) le1[le/self ]]; y := (N ) le2 end

B.3. ENCAPSULATE DOWNCAST 183

As the type of the expression that is assigned to le2 is N , we can strengthen the postconditionof the specification statement to take into account the fact the type of the object currently assignedto le2 is N .

v Law 79 〈strengthen postcondition〉

var le2 : N •{le 6= null ∧ le 6= error} le2 : [le2 = (N ) le1[le/self ] ∧ le2 is N ]; y := (N ) le2

end

From the postcondition of the specification statement, we can introduce an assumption aboutthe type of le2.

= Law 76 〈merge coercions〉(r/l)

var le2 : N •{le 6= null ∧ le 6= error} le2 : [le2 = (N ) le1[le/self ]] [le2 is N ]; y := (N ) le2

end

v Law 57 〈assumption intro〉

var le2 : M •{le 6= null ∧ le 6= error} le2 : [le2 = (N ) le2] [le2 is N ]; {le2 is N } y := (N ) le2

end

= Law 76 〈merge coercions〉 (l/r)

var le2 : N •{le 6= null ∧ le 6= error} le2 : [le2 = (N ) le1[le/self ] ∧ le2 is N ]; {le2 is N } y := (N ) le2

end

The specification statement le2 : [le2 = (N ) le1[le/self ] ∧ le2 is N ] is refined by the assign-ment le2 := (N ) le1[le/self ].

v Law 69 〈assignment〉

var le2 : N •{le 6= null ∧ le 6= error} le2 := (N ) le1[le/self ]; {le2 is N } y := (N ) le2

end

As the type of le2 is the same as that of y , we can eliminate the cast to N that is applied to le2

in the assignment to y .

184 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

= 〈eliminate cast of expressions〉eliminate cast of expressions

var le2 : N •{le 6= null ∧ le 6= error} le2 := (N )le1[le/self ]; {le2 is N } {le2 is N } y := le2

end

We merge the assumptions about the type of le2 and then we remove the resulting assumption.

= Law 75 〈merge assumptions〉, Predicate calculus

var le2 : N •{le 6= null ∧ le 6= error} le2 := (N )le1[le/self ]; {le2 is N } y := le2

end

v Law 77 〈remove assumption〉, Law 16 〈; −skip unit〉

var le2 : N • {le 6= null ∧ le 6= error} le2 := (N )le1[le/self ]; y := le2end

= Property of substitution

var le2 : N • {le 6= null ∧ le 6= error} (le2 := (N )le1)[le/self ]; y := le2end

As there are no calls to the method m of class A, we can remove it from such class.

class Aadsa ;meth m = (res arg : M • arg := exp)mtsa

end

= Law 90 〈method elimination〉 (l/r)

class Aadsa ;mtsa

end

We introduce a method m in class A defined by a parameterised command whose main commandpresents a cast to N .

B.3. ENCAPSULATE DOWNCAST 185

= Law 90 〈method elimination〉 (r/l)

class Aadsa ;meth m = (res arg : N • arg := (N )le1)mtsa

end

We can introduce a call to the method m of class A in place of all commands like those below, asthey are similar to the main command of the parameterised command that defines the method m.First, we introduce the necessary parameterised command.

{le 6= null ∧ le 6= error} le2 := (N )le1; y := le2

= Lemma 10 (l/r)

{le 6= null ∧ le 6= error} (res arg : N • arg := (N )le1)[le/self ](le2); y := le2

Then, we introduce a call to the method m.

= Law 95 〈method call elimination〉(r/l)

le.m(le2); y := le2

This finishes the derivation of the rule 〈Encapsulate Downcast〉.2

186 APPENDIX B. DERIVATION OF CONTEXTUAL REFACTORING RULES

Appendix C

Lemmas for Program Derivation

Lemma 1 (method call elimination-self).

Consider that the following class declaration

class C extends Dadsmeth m = pcmts

end

is included in cds. Then

cds,C B pc(e) = self .m(e)

Proof

1. Change private attributes that appear in pc into public.

Application of Law 85 〈change visibility: from private to public〉, from left to right.

2. Let us call p the method called on super in pc. Change private attributes that appear in pinto public.

Application of Law 85 〈change visibility: from private to public〉, from left to right.

3. Eliminate any occurrence of super in pc. This implies in the elimination of super in thewhole hierarchy. First, in classes that do not have the definition of the method called onsuper in pc, introduce a redefinition of such method, which is p in item 2.

188 APPENDIX C. LEMMAS FOR PROGRAM DERIVATION

Application of Law 88 〈introduce method redefinition〉, from left to right, from the first sub-class of the class closest to C that introduces a definition or a redefinition of p, in thedirection of C , which introduces the call to m on self .

4. Eliminate super in the whole hierarchy.

Application of Law 94 〈eliminate super〉, from left to right, from the first subclass of theclass closest to C that introduces a definition or a redefinition of p, in the direction ofC , which introduces the call to m on self

5. Introduction of assumption on self before the parameterised command application pc(e)

Application of Lemma 6

6. Introduce call to method m, having self as target, in class C .

Application of Law 95 〈method call elimination〉, from right to left.

7. Introduce super in the whole hierarchy.

Application of Law 94 〈eliminate super〉, from right to left, from C to the first subclass ofthe class closest to C that introduces a definition or a redefinition of p.

8. Eliminate occurrences of super in m. This implies in the elimination of super in the wholehierarchy.

Application of Law 88 〈introduce method redefinition〉, from right to left, from the class thatintroduces the call to m on self in the direction of the first subclass of the class closestto C that introduces a definition or a redefinition of p.

9. Change public attributes that appear in p into private.

Application of Law 85 〈change visibility: from private to public〉, from right to left.

10. Change public attributes that appear in m into private.

Application of Law 85 〈change visibility: from private to public〉, from right to left.

2

189

Lemma 2 (Pull Up Method in the Whole Hierarchy) In class inheritance hierarchy, the definitionsof a method in the whole hierarchy are moved to the topmost class that first introduces such method,provided private attributes do not appear in the definition of the method being moved up in suchtopmost class in the inheritance hierarchy nor in any redefinition of the method being moved uppresent in the subclasses of such topmost class.

Proof

We call Z the topmost class in the inheritance hierarchy of the class whose method m we want tomove up, and that first introduces a definition for it. The steps of this proof are as follows.

1. Change the visibility of private attributes that appear in every definition of m to public;

Application of Law 85 〈change visibility: from private to public〉, from left to right.

2. Introduction of trivial method redefinitions, when there is not an explicit redefinition, in allsubclasses of Z . We do this from Z in the direction of the leaf subclasses—those in thebottom of the class hierarchy—of Z ;

Application of Law 88 〈introduce method redefinition〉, from left to right.

3. Elimination of super in all definitions of m, starting from the immediate subclasses of Z inthe direction of its leaf subclasses;

Application of Law 94 〈eliminate super〉, from left to right.

4. Introduction of (trivial) casts in all definitions of the method m;

Application of Law 97 〈introduce trivial cast in expressions〉, from left to right.

5. Exhaustively move up the method m from the bottom of the hierarchy in the direction of Z .After each move of m from a class to its superclass, introduce new (trivial) casts in expressions.This should be carried out until we reach the immediate subclasses of Z , in which we alsointroduce trivial casts;

Application of laws:

Law 89 〈move redefined method to superclass〉, from left to right.

Law 97 〈introduce trivial cast in expressions〉, from left to right.

2

190 APPENDIX C. LEMMAS FOR PROGRAM DERIVATION

Lemma 3 (Push Down Method in the Whole Hierarchy) In a class inheritance hierarchy, the defi-nition of a method in the hierarchy is moved from the topmost class in the hierarchy that introducessuch method to all its subclasses, provided private attributes do not appear in the definition of themethod being moved down in such topmost class.

Proof

We call Z the topmost class in the class inheritance hierarchy of that first introduces a definitionm, the method we want to move down. The steps of this proof are as follows.

1. Exhaustively moving down the method m from Z in the direction of the bottom of thehierarchy.

Application of law:

Law 89 〈move redefined method to superclass〉, from right to left.

2. Elimination of (trivial) casts in all definitions of the method m;

Application of Law 97 〈introduce trivial cast in expressions〉, from right to left.

3. Introduction of super in all definitions of m, starting from leaf subclasses—those in thebottom of the class hierarchy of the hierarchy in direction of Z

Application of Law 94 〈eliminate super〉, from right to left.

4. Elimination of method redefinitions, when there is not an explicit redefinition, in all subclassesof Z . We do this from leaf subclasses in the direction of Z .

Application of Law 88 〈introduce method redefinition〉, from right to left.

5. Change the visibility of public attributes that appear in every definition of m to private;

Application of Law 85 〈change visibility: from private to public〉, from right to left.

2

191

Example. Here we present an example of the application of Lemmas 2 and 3. The derivation fromStep 1 to Step 5 corresponds to Lemma 2. The derivation in the reverse direction corresponds toLemma 3. Let us consider the following class declarations.

class Dadscmeth m = (val x : T • cd )mtsc [self .m(a)]

endclass B extends D

adsbmeth m = (val x : T • cb)mtsb [self .m(a)]

endcds2[le.m(a)] • c[le.m(a)]

class A extends Dadsameth m = (val x : T • ca)mtsa [self .m(a)]

endclass C extends A

adscmtsc [self .m(a)]

end

In this example, we want to move up all definitions of m to D . The argument a is an expressionof type T .

Step 1 First we change the visibility of private attributes that appear the every definition of mfrom private to public. We apply Law 85 〈change visibility: from private to public〉, from leftto right.

Step 2 The class C does not redefine the method m: it does not have an explicit definition of m.We must introduce such definition by applying the Law 88 〈introduce method redefinition〉.

class C extends Aadscmeth m = super.mmtsc

end

Step 3 By applying the Law 94 〈eliminate super〉, we eliminate the occurrence of super in themethod m of class C , resulting in the command cc , which is, in fact, the same as ca .

class C extends Aadscmeth m = (val x : T • cc)mtsc

end

Step 4 We need to introduce trivial casts in all definitions of m in the subclasses of D so thatwe can apply the law for moving redefined methods to the superclass in a later step. Tointroduce the trivial casts, we apply Law 97 〈introduce trivial cast in expressions〉.

192 APPENDIX C. LEMMAS FOR PROGRAM DERIVATION

Step 5 Now we move all definitions of m in the direction of D , as this is the topmost class in theinheritance hierarchy of A that first introduces a definition of m. We exhaustively apply the〈move redefined method to superclass〉move redefined method to superclass, from left to right,starting from C until class D . We apply the Law 89 〈move redefined method to superclass〉,moving method m from C to A. This result in the following method m in class A, in whichthere are occurrences of self without casts.

if self is C → c′c[] ¬ (self is C ) → c′afi

where c′a indicates that this command differs from the original ca by the introduction of trivialcasts in expressions present in ca . Similarly, the command c′c denotes the command cc thatwas present in class C with trivial casts in expressions. In order to move this method from Ato D , it is necessary to introduce casts, as required by the law for moving redefined methodsto a superclass. Again, we apply Law 97 〈introduce trivial cast in expressions〉, yielding thefollowing alternation.

if (A)self is C → c′c[] ¬ ((A)self is C ) → c′afi

The method m of class A can be moved to D . As in the previous steps, after we introducetrivial casts, we can move such method from B to D . Finally, we move the definitions of min B and A to D . This yields the following classes.

class Dadscmeth m = (val x : T •

if self is B → c′b[] ¬ (self is B) → if ¬ (self is A)is A → cd

[] self is A → if (A)self is C → c′c[] ¬ ((A)self is C ) → c′afi

fifi)

mtsd [self .m(a)]end

193

class B extends Dadsbmtsb [self .m(a)]

endcds2[le.m(a)] • c[le.m(a)]

class A extends Dadsamtsa [self .m(a)]

end

class C extends Aadscmtsc [self .m(a)]

end

This exemplifies how we move all definitions of a method to the topmost class that first intro-duces a definition of that method. Following the proposed steps in the reverse order, moves thedefinition of a method in the direction of the subclasses of the class where the method is defined.

2

Lemma 4 (Eliminate super in Hierarchy) In an inheritance hierarchy, the occurrences of super

are eliminated in the definition of a method and in superclasses, which do not redefine such method,of the class in which we want to eliminate the occurrences of super.

Proof

We call Z the superclass in the inheritance hierarchy of the class whose method m we want toremove occurrences of super from. The class Z first introduces a definition for m or redefines it.The steps of this proof are as follows.

1. Change the visibility of private attributes that appear in the topmost definition or redefinitionof m to public;

Application of Law 85 〈change visibility: from private to public〉, from left to right.

2. Introduction of trivial method redefinitions, when there is not an explicit redefinition, in allsubclasses of Z . We do this from Z in the direction of the leaf subclasses—those in thebottom of the class hierarchy—of Z ;

Application of Law 88 〈introduce method redefinition〉, from left to right.

3. Elimination of super in all definitions of m, starting from the immediate subclasses of Z inthe direction of its leaf subclasses;

Application of Law 94 〈eliminate super〉, from left to right.

2

194 APPENDIX C. LEMMAS FOR PROGRAM DERIVATION

Lemma 5 (Eliminate super and Trivial Methods in Hierarchy) In an inheritance hierarchy super

is introduced in every trivial definition of a method m that appear in subclasses of a class that isthe first to introduce a definition for m or is the last to redefine m.

Proof

We call Z the first superclass in the inheritance hierarchy of the class whose method m we want toremove occurrences of super from, and that first introduces a definition for it or redefines it. Thesteps of this proof are as follows.

1. Introduction of super in all definitions of m, starting from the leaf subclasses of Z in thedirection of Z ;

Application of Law 94 〈eliminate super〉, from right to left.

2. Elimination of trivial method redefinitions in all subclasses of Z . We do this from Z in thedirection of the root subclasses—those in the top of the class hierarchy—of Z ;

Application of Law 88 〈introduce method redefinition〉, from right to left.

3. Change the visibility of private attributes that appear in the topmost definition or redefinitionof m to private;

Application of Law 85 〈change visibility: from private to public〉, from right to left.

2

Lemma 6 (self non-null non-error) An assumption about self , which is not null nor error isintroduced in any position in a method of a class.

Proof

The steps of this proof are as follows.

• Introduction of class invariant {self 6= null ∧ self 6= error}

Application of Law 107 〈introduce class invariant〉, from left to right.

• Moving the invariant to the adequate code position

Applications of Law 53 〈assumption before or after command〉, from right to left.

2

195

Lemma 7 (Type changes in program)

cds1 • c1 = cds2 • c2

where

cds2 = cds1[visib at : M ,var v : M , par p : M /visib at : N ,var v : N , par p : N ]

where visib ∈ {pri,prot,pub} and par ∈ {val, res}c2 = c1[var x : B , par p : M /var x : C , par p : N ]

provided

(→) (1) every non-assignable occurrence of attributes, local variables, value andresult parameters of type N in expressions are cast with N or any subtype ofN ; (2) every actual parameter associated with formal parameters of type N incds1 and c1 are of type M or any supertype of M .

(←) (1) every non-assignable occurrence of attributes, local variables, value andresult parameters of type M in expressions are cast with N or any subtype ofN ; (2) every expression assigned to an attribute of type M is of type N ro anysubtype of N ; (3) every use of an attribute of type M as a result argumentis for a corresponding formal parameter of type N or any subtype of N ; (4)every actual parameter associated with a value parameter of type M is of typeN of any subtype of N ; (5) every expression assigned to a value argument oftype M is of type N or any subtype of N ; (6) every use of a value argument oftype M as result argument is for a corresponding formal parameter of type Nor any subtype of N ; (7) every use of a result parameter of type M as a resultargument is for a corresponding formal parameter of type N or any subtype ofN ; (8) every expression assigned to a result parameter of type M is of type Nor any subtype of N ; (9) every expression assigned to variables of type M isof type N or any subtype of N ; (10) and every use of variables of type M isfor a corresponding formal parameter of type N or any subtype of N .

Proof (From left to right) By the application of laws

• Law 86 〈change attribute type〉, from left to right;

• Law 99 〈change variable type〉, from left to right;

• Law 93 〈change result parameter type〉, from left to right;

• Law 92 〈change value parameter type〉, from left to right.

196 APPENDIX C. LEMMAS FOR PROGRAM DERIVATION

(From right to left) By the application of laws

• Law 86 〈change attribute type〉, from right to left;

• Law 99 〈change variable type〉, from right to left;

• Law 93 〈change result parameter type〉, from right to right;

• Law 92 〈change value parameter type〉, from right to right.

2

Lemma 8 (Program cast elimination) Type casts for a class N that appears in program cds • care removed along with any assumption with type tests provided

Proof By the application of the following laws

• Law 96 〈eliminate cast of method call〉, from left to right;

• Law 98 〈eliminate cast of expressions〉, from left to right;

For each assumption that results from application of the previous laws, apply laws

• Law 77 〈remove assumption〉, from left to right;

• Law 16 〈; −skip unit〉

in this order.2

Lemma 9 (pcom value-argument)

c = (val vl : T • c[vl/x ] )(x )

provided vl is fresh—not free in c—; in c, x is not on the left-hand side of assignments, it is not aresult argument, x does not occur in the frame of specification statements in c, x is not a methodcall target, and x 6= error

Proof

c= var l : T • l := x ; c[l/x ] end [by Law 62 〈var block-val〉]= (val vl : T • c[vl/x ] )(x ) [by a syntactic transformation]

2

197

Lemma 10 (pcom result-argument)

c = (res vl : T • c[vl/x ])(x )

provided vl is fresh—not free in c—; in c, x is not on the right-hand side of assignments and it isnot a value argument nor a method call target, x is not used in attribute selection nor in updateexpression.

Proof

c= var l : T • c[l/x ]; x := l end [by Law 63 〈var block-res〉]= (res vl : T • c[vl/x ] )(x ) [by a syntactic transformation]

2

198 APPENDIX C. LEMMAS FOR PROGRAM DERIVATION

Appendix D

Laws of Commands

D.1 Assignment

Law 1 〈:= skip〉If le 6= error, then (le := le) = skip

2

Law 2 〈:= identity〉If e 6= error, then (le, le1 := e, le1) = (le := e)

2

Law 3 〈:= symmetry〉If i ranges over 1..n and π is any permutation of 1..n, then(lei := ei) = (leπ(i) := eπ(i)), provided ei 6= error

2

D.2 Conditional

Law 4 〈if symmetry〉If i ranges over 1..n and π is any permutation of 1..n, thenif []i • ψi → ci fi = if []i • ψπ(i) → cπ(i) fi

2

Law 5 〈if true guard〉if true → c fi = c

2

200 APPENDIX D. LAWS OF COMMANDS

Law 6 〈if false unity〉if false → c [] ψi → ci fi = if ψi → ci fi

2

Law 7 〈if abort unity〉if () fi = abort

2

Law 8 〈if - ∨ distrib1 〉if ψ1 → c[]ψ2 → c[](ψi → ci) fi = if (ψ1 ∨ ψ2) → c [] ([]i • ψi → ci) fi

2

Law 9 〈if elim〉If i ranges over 1..n

if ψ →

if ψ → c

[] ([]i • ψi → ci)

fi

[] ([]j • ψj → cj )fi

=if ψ → c

[] ([]j • ψj → cj )

fi

2

Law 10 〈if - ∨ distrib2 〉

if ψ1 → c1

[] ¬ ψ1 →

if ψ2 → c1

[] ¬ ψ2 → c2

fi

fi

=if (ψ1 ∨ ψ2) → c1

[] ¬ (ψ1 ∨ ψ2) → c2

fi

2

Law 11 〈if - ∧ distrib〉

if ψ1 →

if ψ2 → c1

[] ¬ ψ2 → c2

fi

[] ¬ ψ1 → c2

fi

=if (ψ1 ∧ ψ2) → c1

[] ¬ ψ1 → c2

fi

D.3. RECURSION 201

2

Law 12 〈if gc intro〉If i ranges over 1..n and ¬ (ψ ∧ ψi), for all i , thenif []i • ψi → ci fi v if ([]i • ψi → ci) [] ψ → c fi

2

Law 13 〈if gc elim〉If i ranges over 1..n and ψ ⇒∨ i • ψi , thenif ψ → c [] ([]i • ψi → ci) fi v if ([]i • ψi → ci) fi

2

Law 14 〈if true guard ref 〉if true → c [] ([]i • ψi → ci) fi v c

2

D.3 Recursion

Law 15 〈rec fixed point〉rec X • F(X) = F(rec • F(X))

2

D.4 Sequential Composition

Law 16 〈; −skip unit〉(skip; c) = c = (c; skip)

2

Law 17 〈; −abort left zero〉abort; c = abort

2

Law 18 〈; −miracle left zero〉miracle; c = miracle

2

202 APPENDIX D. LAWS OF COMMANDS

Law 19 〈; assoc〉(c1; c2); c3 = c1; (c2; c3)

2

Law 20 〈; −if left dist〉If i ranges over 1..nif []i • ψi → ci fi; c = if []i • ψi → (ci ; c) fi

2

Law 21 〈; −if selection〉If i and j range over 1..n and ¬ (ψj ∧ ψi), then for j 6= i we have[ψj ] if []i • ψi → ci fi = [ψj ]; cj

2

Law 22 〈; − := combination〉(le := e1; le := e2) = (le := e2[e1/le])

2

Law 23 〈:= − CB right dist〉If e is total, thenle := e; if []i • ψi → ci fi = if []i • ψi [e/le] → (le := e; ci) fi

2

D.5 Local Variable Block

Law 24 〈var symmetry〉var x1 : T1 • (var x2 : T2 • c end) end = var x2 : T2 • (var x1 : T1 • c end) end 2

Law 25 〈var elim〉If x is not free in c, then var x : T • c end = c

2

Law 26 〈var rename〉If x2 is not free in c, thenvar x1 : T • c end = var x2 : T • c[x2/x1] end

2

D.6. ANGELIC VARIABLE BLOCK 203

Law 27 〈var− if dist〉If i ranges over 1..n and x is not free in ψi , thenif []i • ψi → (var x : T • ci end) fi = var x : T • if []i • ψi → ci fi end

2

Law 28 〈var-; left dist〉If x is not free in c2, then var x : T • c1 end; c2 = var x : T • c1; c2 end

2

Law 29 〈var−; right dist〉If x is not free in c1, then c1; var x : T • c2 end = var x : T • c1; c2 end

2

Law 30 〈var- := final value〉If x is not free in c, then var x : T • c; x := e end = var x : T • c end

2

Law 31 〈var−; dist〉var x : T • c1 end; var x : T • c2 end v var x : Tc1; c2 end

2

Law 32 〈var− := initial value〉Provided e 6= error, then var x : T • c end v var x : T • x := e; c end

2

D.6 Angelic Variable Block

Law 33 〈avar symmetry〉avar x1 : T1 • (avar x2 : T2 • c end) end = avar x2 : T2 • (avar x1 : T1 • c end) end

2

Law 34 〈avar elim〉If x is not free in c, then avar x : T • c end = c

2

204 APPENDIX D. LAWS OF COMMANDS

Law 35 〈avar rename〉If x2 is not free in c, thenavar x1 : T • c end = avar x2 : T • c[x2/x1] end

2

Law 36 〈avar - if dist〉If i ranges over 1..n and x is not free in ψi , thenif []i • ψi → (avar x : T • ci end) fi = avar x : T • if []i • ψi → ci fi end

2

Law 37 〈avar-; left dist〉If x is not free in c2, thenavar x : T • c1 end; c2 = avar x : T • c1; c2 end

2

Law 38 〈avar-; right dist〉If x is not free in c1, thenc1; avar x : T • c2 end = avar x : T • c1; c2 end

2

Law 39 〈avar- := final value〉If x is not free in c, thenavar x : T • c; x := e end = avar x : T • c end

2

Law 40 〈avar - var relationship〉If x is not free in e, thenavar x : T • {x = e}; c end = var x : T • [x = e]; c end

2

Law 41 〈avar-; dist〉avar x : T • c1; c2 end v avar x : T • c1 end; avar x : T • c2 end

2

Law 42 〈avar- := initial value〉Provided e 6= error, then avar x : T • x := e; c end v avar x : T • c end

2

D.7. ADDITIONAL LAWS 205

Law 43 〈var - avar refinement〉var x : T • c end v avar x : T • c end

2

D.7 Additional Laws

In this section we present some additional command laws that have arisen along the derivation ofrefactoring rules.

D.7.1 Alternation

Law 44 〈if identical guarded commands〉If (

∨i : 1..n • ψi = true), then

if []i : 1..n • ψi → c fi = c

2

D.7.2 Guards

Law 45 〈iteration guards〉

do []i • gi → cc od v do []i • hi → ci od

providedi . hi ⇒ gi

ii . gg ⇒ hh

2

Law 46 〈weakening guards〉

if []i • gi ∧ g → ci fi v if []i • gi → ci fi

providedi . (∨ i • gi ∧ g) ⇒ (∨ i • gi)ii . (∨ i • gi ∧ g) ∧ gi ⇒ gi ∧ g

2

206 APPENDIX D. LAWS OF COMMANDS

D.7.3 Assumptions

Law 47 〈innocuous assumption-reading〉If x is an attribute of the object denoted by le, thenle1 := le.x = {le 6= null ∧ le 6= error}; le1 := le.x

2

Law 48 〈innocuous assumption-writing〉If x is an attribute of the object denoted by le, thenle.x := exp = {le 6= null ∧ le 6= error}; le.x := exp

2

Law 49 〈assumption guard〉if []i • ψi → ci fi = if []i • ψi → {ψi} ci fi

2

Law 50 〈var block absorb assumption〉If x is not free in ψ, then{ψ} var x : T • c end = var x : T • {ψ} ; c end

2

Law 51 〈alternation absorb assumption〉{φ} if ψi → ci fi = if φ ∧ ψi → ci fi

2

Law 52 〈pcom absorb assumption〉If the parameters present in pd and pds do not occur free in φ, then{φ}(pd ; pds • c)(an) = (pd ; pds • {φ}c)(an)

2

Law 53 〈assumption before or after command〉Provided the free variables of φ are not free in expressions on the left-hand side of assignments inc, they are not used as result arguments c, they are not in the frame of specification statements inc, and they are not targets of method calls, then

{φ} c = c; {φ}

2

D.7. ADDITIONAL LAWS 207

Law 54 〈assumption advance command〉If free variables of φ are not on the left-hand side of assignments in c, they are not result argumentsin method calls in c, they are not in the frame of specification statements in c, and they are nottargets of method calls, then

{φ} c = {φ}c; {φ}

2

Law 55 〈assumption distribution〉Provided the free variables of φ are not free in expressions on the left-hand side of assignments inci , they are not used as result arguments ci , they are not in the frame of specification statementsin ci , and they are not targets of method calls, then

{φ} c[i : 1..n • ci ] = c[i : 1..n • {φ} ci ]

2

Law 56 〈new assumption〉If c is the body of new of class N , l is is the list of global variables of c, and l : [true, true] v c,then

x := new N () v x := new N (); {x 6= null ∧ x 6= error}

2

Law 57 〈assumption intro〉w : [ψ1, ψ2] v w : [ψ1, ψ2]; {ψ2}

2

D.7.4 Assignment

Law 58 〈repeated assignment〉(le := e) = (le := e; le := e)

2

Law 59 〈order independent assignment〉If x and y are not free in e2 and e1, respectively, then

208 APPENDIX D. LAWS OF COMMANDS

(x := e1; y := e2) = (y := e2; x := e1)

2

Law 60 〈assignment seq comp exp substitution〉If le and exp are not used as left-expressions in c, then

(le := exp; c[exp]) = (le := exp; c[le])

2

D.7.5 Local Variable Block

Law 61 〈var dec separation〉

(var x , xi : T ,Ti • c end) = (var x : T • var xi : Ti • c end end)

2

D.7.6 Variable blocks and parameterised commands

Law 62 〈var block-val〉

c = var l : T • l := x ; c[l/x ] end

provided l is fresh—not free in c—; x is not on the left-hand side of assignments, it is not a resultargument, x does not occur in the frame of specification statements in c, x is not a method calltarget, and x 6= error.

2

Law 63 〈var block-res〉

c = var l : T • c[l/x ]; x := l end

provided l is fresh—not free in c—; x is not on the right-hand side of assignments and it is nota value argument nor a method call target, x is not used in attribute selection nor in updateexpression.

2

D.7. ADDITIONAL LAWS 209

Law 64 〈pcom elimination-val〉

(val vl : T • c)(x ) = var l : T • l := x ; c[l/vl ] end

provided the variables of l are fresh: not free in c, x , and vl . Variables in vl do not appear onthe left-hand side of assignments, are not used as result arguments, do not occur in the frame ofspecification statement, nor are method call targets, and they are not error.

2

Law 65 〈pcom elimination-res〉

(res vl : T • c)(x ) = var l : T • c[l/vl ]; x := l end

provided the variables of l are fresh: not free in c, x , and vl . Variables in vl are not on the right-hand side of assignments, they are not used as value arguments nor are method call targets, andthey are not used in attribute selection nor in update expression.

2

Law 66 〈pcom merge〉

(par x : T ; pds • c)(a1, a2) = (par x : T • (pds • c)(a2))(a1)

where par ∈ {val, res}, and provided the variables of x are not free in a2.

2

Law 67 〈command refinement-class refinement〉

class Nadsn ;meth m = (pds • c1)mtsn

end

vcds,c

class Nadsn ;meth m = (pds • c2)mtsn

end

provided

c1 v c2

2

210 APPENDIX D. LAWS OF COMMANDS

D.8 Laws from Morgan’s work [64]

In this section, we present laws proposed by Morgan [64] that we have used in our work.

Law 68 〈absorb coercion〉

w : [ψ1, ψ2]; [φ] = w : [ψ,ψ2] ∧ φ

2

Law 69 〈assignment〉If ψ1 ⇒ ψ2[E/w ], then w , x : [ψ1, ψ2] v w := E

2

Law 70 〈augment assignment〉The assignment w := E can be replaced by the fragment w , c := E ,F provided that CI ⇒ CI [E ,F/w , c]

2

Law 71 〈augment guards〉The guard G may be replaced by G ′ provided that [CI ⇒ (G ⇔ G ′)

2

Law 72 〈augment specification〉The specification w : [ψ1, ψ2] becomes w , c : [CI ∧ ψ1,CI ∧ ψ2]

2

Law 73 〈diminish assignment〉If E contains no variables a, then the assignment w , a := E ,F can be replaced by the assignmentw := E .

2

Law 74 〈diminish specification〉The specification w , a : [ψ1, ψ2] becomes

w : [(∃ a : A • ψ1), (∀ a0 : A • ψ10 ⇒ (∃ a : A • ψ2))]

2

D.9. DATA REFINEMENT 211

Law 75 〈merge assumptions〉{ψ2}{ψ2} = {ψ1 ∧ ψ2}

2

Law 76 〈merge coercions〉[ψ1][ψ2] = [ψ1 ∧ ψ2]

2

Law 77 〈remove assumption〉{ψ} v skip

2

Law 78 〈simple specification〉Provided E contains no w , w := E = w : [w = E ]

2

Law 79 〈strengthen postcondition〉If ψ′2 ⇒ ψ2, then

w : [ψ1, ψ2] v w : [ψ1, ψ′2]

2

Law 80 〈weaken precondition〉If ψ1 ⇒ ψ′1, then

w : [ψ1, ψ2] v w : [ψ′1, ψ2]

2

D.9 Data Refinement

Law 81 〈Data refinement—variable blocks with initialisation〉

var vl ; avl • avl : [true, init ]; c1 end

v

var vl ; cvl • cvl : [true, (∃ avl • CI ∧ init ]; c2 end

212 APPENDIX D. LAWS OF COMMANDS

provided

c1 ¹ c2

The variables of cvl are not free in init and c1, and are not in avl ;

The variables of avl are not free in c2;

2

Appendix E

Laws of Classes

E.1 Normal Form Laws

In this section, we present laws that are useful for the description and justification of a strategyfor reducing programs to a normal form expressed in terms of restricted subset of rool [17, 16].The major application of these laws is to formally derive elaborate behaviour preserving programtransformations.

E.1.1 Class Declaration

Law 82 〈class elimination〉

cds cd1 • c = cds • c

provided

(→) The class declared in cd1 is not referred to in cds or c;

(←) (1) The name of the class declared in cd1 is distinct from those of all classesdeclared in cds; (2) the superclass appearing in cd1 is either object or declared incds; (3) and the attribute and method names declared by cd1 are not declared byits superclasses in cds, except in the case of method redefinitions.

2

214 APPENDIX E. LAWS OF CLASSES

E.1.2 Attribute Declaration

Law 83 〈attribute elimination〉class B extends A

pri a : T ; adsops

end

=cds,c

class B extends Aadsops

end

provided

(→) B .a does not appear in ops;

(←) a does not appear in ads and is not declared as an attribute by a superclass orsubclass of B in cds.

2

Law 84 〈change visibility: from protected to public〉

class C extends Dprot a : T ; adsops

end

=cds,c

class C extends Dpub a : T ; adsops

end

provided

(←) B .a, for any B ≤ C , appears only in ops and in the subclasses of C in cds.

2

Law 85 〈change visibility: from private to public〉

class C extends Dpri a : T ; adsops

end

=cds,c

class C extends Dpub a : T ; adsops

end

provided

(←) B .a, for any B ≤ C , does not appear in cds, c.

2

E.1. NORMAL FORM LAWS 215

The law that allows us to change attribute visibility from private to protected, and vice-versa,can be derived from the above two laws. For instance, you can make a private attribute protected,by making it public, with an application of Law 85, and then protected, by applying Law 84.

In subsequent laws we use the concept of non-assignable identifiers. We define the concept orassignable and non-assignable occurrences of identifiers [17, 16]. Assignable occurrences of identifersare result arguments and targets of assignments. For instance, in self .a := e and le.m(self .a), theoccurrences of a are assignable, if the single parameter of m is passed by result. On the other hand,in an assignment self .a.x := e, there is an assignable occurrence of x but not of a. Therefore, a isrequired to be cast in the proviso above. The same comment applies to a result argument self .a.x .Occurrences of identifiers as result arguments and targets of assignments are not cast anywhere;like in Java, this is not allowed in rool [17, 16].

Law 86 〈change attribute type〉

class C extends Dpub a : T ; adsops

end

=cds,c

class C extends Dpub a : T ′; adsops

end

provided

(↔) T ≤ T ′ and every non-assignable occurrence of a in expressions of ops, cds and cis cast with T or any subtype of T declared in cds.

(←) (1) every expression assigned to a, in ops, cds and c, is of type T or any subtypeof T ; (2) every use of a as result argument is for a corresponding formal parameterof type T or any subtype of T .

2

Law 87 〈move attribute to superclass〉

class B extends Aadsops

end class C extends Bpub a : T ; ads ′

ops ′

end

=cds,c

class B extends Apub a : T ; adsops

end class C extends Bads ′

ops ′

end

provided

(→) The attribute name a is not declared by the subclasses of B in cds;

216 APPENDIX E. LAWS OF CLASSES

(←) D .a, for any D ≤ B and D 6≤ C , does not appear in cds, c, ops, or ops ′.

2

E.1.3 Method Declaration

Law 88 〈introduce method redefinition〉class B extends A

adsmeth m = pcops

end

class C extends Bads ′

ops ′

end

=

class B extends Aadsmeth m = pcops

end

class C extends Bads ′

meth m = super.mops ′

end

provided

(→) m is not declared in ops ′.

2

Law 89 〈move redefined method to superclass〉

class B extends Aadsmeth m = (pds • b)ops

end

class C extends Bads ′

meth m = (pds • b′)ops ′

end

=cds,c

class B extends Aadsmeth m = (pds •if ¬(self is C ) → b[] self is C → b′

fi)ops

end

class C extends Bads ′

ops ′

end

provided

(↔) (1) super and private attributes do not appear in b′; (2) super.m does not appearin ops ′;

E.1. NORMAL FORM LAWS 217

(→) b′ does not contain uncast occurrences of self nor expressions in the form ((C )self).afor any private attribute a in ads ′;

(←) m is not declared in ops ′.

2

Law 90 〈method elimination〉

class C extends Dadsmeth m = pc end; ops

end

=cds,c

class C extends Dadsops

end

provided

(→) B .m does not appear in cds, c nor in ops, for any B such that B ≤ C .

(←) m is not declared in ops nor in any superclass or subclass of C in cds.

2

Law 91 〈move original method to superclass〉

class B extends Aadsops

end

class C extends Bads ′

meth m = pcops ′

end

=cds,c

class B extends Aadsmeth m = pcops

end

class C extends Bads ′

ops ′

end

provided

(↔) (1) super and private attributes do not appear in pc; (2) m is not declared in anysuperclass of B in cds;

(→) (1) m is not declared in ops, and can only be declared in a class D , for anyD ≤ B and D 6≤ C , if it has the same parameters as pc; (2) pc does not containuncast occurrences of self nor expressions in the form ((C )self).a for any privateattribute a in ads ′;

(←) (1) m is not declared in ops ′; (2) D .m, for any D ≤ B , does not appear in cds, c,ops or ops ′.

2

218 APPENDIX E. LAWS OF CLASSES

E.1.4 Parameter Type

Law 92 〈change value parameter type〉

class C extends Dadsmeth m =

val x : T ; pds • bops

end

=cds,c

class C extends Dadsmeth m =

val x : T ′; pds • bops

end

provided

(↔) T ≤ T ′ and every non-assignable occurrence of x in expressions of b are cast withT or any subtype of T ;

(←) (1) every actual parameter associated with x in ops, cds, and c is of type T orany subtype of it; (2) every expression assigned to x in b, is of type T or anysubtype of T ; (3) every use of x as result argument in b is for a correspondingformal parameter of type T or any subtype of T .

2

Law 93 〈change result parameter type〉

class C extends Dadsmeth m =

res x : T ; pds • bops

end

=cds,c

class C extends Dadsmeth m =

res x : T ′; pds • bops

end

provided

(↔) T ≤ T ′ and every non-assignable occurrence of x in expressions of b are cast withT or any subtype of T ;

(→) every actual parameter associated with formal parameter x in ops, cds, and c isof type T ′ or any supertype of it;

(←) (1) every expression assigned to x in b is of type T or any subtype of T ; (2) everyuse of x as result argument in b is for a corresponding formal parameter of typeT or any subtype of T .

2

E.1. NORMAL FORM LAWS 219

E.1.5 Method Calls

Law 94 〈eliminate super〉Consider that CDS is a set of two class declarations as follows.

class B extends Aadsmeth m = pcops

end

class C extends Bads ′

ops ′

end

Then we have that

cds CDS ,C B super.m = pc

provided

(→) super and the private attributes in ads do not appear in pc.

2

Law 95 〈method call elimination〉Consider that the following class declaration

class C extends Dadsmeth m = pcops

end

is included in cds and cds,A B le : C . Then

cds,A B le.m(e) = {le 6= null ∧ le 6= error}; pc[le/self ](e)

provided

(↔) (1) m is not redefined in cds and pc does not contain references to super; (2) allattributes which appear in the body pc of m are public.

2

220 APPENDIX E. LAWS OF CLASSES

E.1.6 Casts

Law 96 〈eliminate cast of method call〉If cds,A B e : B , C ≤ B and m is declared in B or in any of its superclasses in cds, then

cds,A B ((C )e).m(e ′) = {e is C}; e.m(e ′)

2

Law 97 〈introduce trivial cast in expressions〉If cds,A B e : C , then cds,A B e = (C )e. 2

For simplicity, this is formalised as a law of expressions, not commands. Nevertheless, it should beconsidered as an abbreviation for several laws of assignments, conditionals, and method calls thatdeal with each possible pattern of expressions. For example, it abbreviates the following laws, allwith the same antecedent as Law 97.

cds,A B le := e.x = le := ((C )e).xcds,A B e ′.m(e) = e ′.m((C )e)

This is equally valid for left-expressions, which are a particular form of expression.

Law 98 〈eliminate cast of expressions〉If cds,A B le : B , e : B ′, C ≤ B ′ and B ′ ≤ B , then

cds,A B le := (C )e = {e is C}; le := e

2

E.1.7 Commands and expressions

Law 99 〈change variable type〉

cds,A B var x : T • c end = var x : T ′ • c end

provided

(↔) T ≤ T ′ and every non-assignable occurrence of x in expressions of c is cast withT or any subtype of T ;

(←) (1) every expression assigned to x in c is of type T or any subtype of T ; (2) everyuse of x as result argument in c is for a corresponding formal parameter of typeT or any subtype of T .

E.2. FURTHER OBJECT-ORIENTED PROGRAMMING LAWS 221

2

Law 100 〈change angelic variable type〉

cds,A B avar x : T • c end = avar x : T ′ • c end

provided

(↔) T ≤ T ′ and every non-assignable occurrence of x in expressions of c is cast withT or any subtype of T ;

(←) (1) every expression assigned to x in c is of type T or any subtype of T ; (2) everyuse of x as result argument in c is for a corresponding formal parameter of typeT or any subtype of T .

2

Law 101 〈is test true〉If N ≤cds M , then cds,N B self is M = true 2

Law 102 〈law:is test false〉If N �cds M and M �cds N , then cds,N B self is M = false 2

E.2 Further object-oriented programming laws

In this section, we present additional object-oriented programming laws that deal with the expres-sion new and with changing a superclass of a class.

E.2.1 Laws for new

Law 103 〈new superclass〉

class A extends Cadsamtsa

end

class B extends Aend

cds • c

=

class A extends Cadsamtsa

end

class B extends Aend

cds ′ • c′

222 APPENDIX E. LAWS OF CLASSES

where

cds ′ = cds[new A/new B ]

c′ = c[new A/new B ]

provided

(→) (1) B is not used in type casts or type tests in cds or c for expressions of type A;

(2) ‘new B ’ is assigned only to attributes or variables of type A or any supertypeof A.

(3) ‘new B ’ is used as a value argument only in calls to methods with a corre-sponding formal parameter of type A or any supertype of A;

(4) ‘new B ’ only is assigned to a result argument of type A or any supertypeof A.

2

Law 104 〈new subclass〉

class A extends Cadsamtsa

end

class B extends Aadsbmtsb

end

cds • c

=

class A extends Cadsamtsa

end

class B extends Aadsbmtsb

end

cds ′ • c′

where

cds ′ = cds[new B/new A]

c′ = c[new B/new A]

provided

(↔) (1) Methods of mtsa are not redefined by methods of mtsb ;

(←) (1) B is not used in type casts or type tests in cds or c for expressions of type A;

E.2. FURTHER OBJECT-ORIENTED PROGRAMMING LAWS 223

(2) ‘new B ’ is assigned only to attributes or variables of type A or any supertypeof A.

(3) ‘new B ’ is passed as a value argument in calls to methods with a correspondingformal parameter of type A or any supertype of A.

(4) ‘new B ’ only is assigned to a result argument of type A or any supertypeof A.

2

E.2.2 Laws for changing a superclass

Law 105 〈change superclass: from object to any class〉

class C extends object

adscmtsc

end

=cds,c

class C extends Badscmtsc

end

provided

(→) (1) All attributes in adsc and in subclasses of C are distinct from those declaredin B and in superclasses of B ;

(2) Methods in mtsc and in subclasses of C that have the same name must havethe same parameter declaration of methods declared or inherited by B ;

(←) (1) C or any of its subclasses in cds is not used in type casts or tests involvingany expression of type B or of any supertype of B ;

(2) There are no assignments of the form le := exp, for any le whose declaredtype is B or any superclass of B and any exp whose type is C or any subclassof C ;

(3) Expressions of type C or of any subclass of C are not used as value argu-ments in calls with a corresponding formal parameter whose type is B or anysuperclass of B ;

(4) Expressions whose declared type is B or any of its superclasses are not resultarguments in calls with a corresponding formal parameter whose declared typeis C or any subclass of C ;

(5) self .a does not appear in C , nor in any subclass of C , for any public orprotected attribute a of B or of any of its superclasses;

(6) le.a, for any le : C , does not appear in cds or c for public attribute a of B orof any of its superclasses;

224 APPENDIX E. LAWS OF CLASSES

(7) There is no D .m, for any m and D such that m is declared in B or in any ofits superclasses, but not in mtsc , and D ≤ C ;

(8) super does not appear in any method in mtsc .

2

Law 106 〈change superclass: from an empty class to immediate superclass〉

class B extends Aend

class C extends Badscmtsc

end

=cds,c

class B extends Aend

class C extends Aadscmtsc

end

provided

(→) (1) C or any of its subclasses in cds is not used in type casts or tests involvingexpressions of type B ;

(2) There are no assignments of the form le := exp, for any le whose declaredtype is B or any of its superclasses and the type of exp is C or any subclassof C ;

(3) Expressions of type C or of any subclass of C are not used as value argumentsin calls with a corresponding formal value parameter whose type is B ;

(4) Expressions whose declared type is B are not result arguments in calls witha corresponding formal result parameter whose declared type is C or anysubclass of C ;

(→) (1) Casts to class B are not applied to attributes, variables or parameters of typeA to which are assigned expressions of type C

2

E.2.3 Class invariant

Law 107 〈introduce class invariant〉

E.3. SIMULATION 225

class A extends Cadsa ;meth m = (pds • c′)mtsa

end

=cds,c

class A extends Cadsa ;meth m = (pds • c′; {inv})mtsa

end

provided

inv is an invariant of class A.

2

E.3 Simulation

Law 108 〈private attribute-coupling invariant〉

class A extends Cpri x : T ; adsmts

end

cds • c

¹CI

class A extends Cpri y : T ′; adsCI (mts)

end

cds • c2

Law 109 〈superclass attribute-coupling invariant〉

class A extends CadsAmts

end

cds ′ cds

¹CI

class A extends CadsCCI (mts)

end

CI (cds ′) cds

provided

CI refers only to public and protected attributes in adsA;

cds ′ only contains subclasses of A

cds contains no subclasses of A

2

226 APPENDIX E. LAWS OF CLASSES

Appendix F

Proofs of Laws of Commands

Lemma 11

[[Γ,N B skip : com]]η ψ

= [[Γ,N B : [true, true] : com]]η ψ [by definition of skip]= true ∧ true ⇒ ψ [by the semantics of specification statement]= ψ [by predicate calculus]

Lemma 12

[[Γ,N B abort : com]]η ψ

= [[Γ,N B x : [false, true] : com]]η ψ [by definition of abort]= false ∧ (∀ x : T • true ⇒ ψ) [by the semantics of specification statement]= false [by predicate calculus]

Lemma 13 If x is not free in c and ψ, then x is not free in

[[Γ,N ,N B c : com]]η ψ

Proof Straightforward induction. 2

Lemma 14 For a typing environment Γ, a class N, a proper environment η, a command c, apredicate ψ, and x a variable of type T not free in c and ψ, if y is not free in c, then

[[Γ; x : T ,N B c : com]]η ψ = [[Γ,N B c : com]]η ψ

228 APPENDIX F. PROOFS OF LAWS OF COMMANDS

Proof

[[Γ; x : T ,N B c : com]]η ψ

= [[Γ; x : T ,N B c[y/x ][x/y ] : com]]η ψ [by y not free in c]= ([[Γ,N B c[y/x ] : com]]η ψ[x/y ])[x/y ] [by Lemma 13-[22]]= ([[Γ,N B c : com]]η ψ[x/y ])[x/y ] [by y not free in c]= ([[Γ,N B c : com]]η ψ)[x/y ] [by x not free in ψ]= [[Γ,N B c : com]]η ψ [by Lemma 13]

2

F.1 Proofs of laws

F.1.1 Assignment

Proof F.1.1 Law 〈:= skip〉

[[Γ,N B le := le : com]]η ψ

= le 6= error ∧ ψ[le/le] [by the semantics of assignment]= ψ [by the hypothesis and a property of substitution]= [[Γ,N B skip : com]]η ψ [by Lemma 11]

2

Proof F.1.2 Law 〈:= identity〉

[[Γ,N B le, le1 := e, le1 : com]]η ψ

= e 6= error ∧ le1 6= error ∧ ψ[e, le1/le, le1] [by the semantics of assignment]= e 6= error ∧ ψ[e/le] [by the hypothesis and a property of substitution]= [[Γ,N B le := e : com]]η ψ [by the semantics of assignment]

2

Proof F.1.3 Law 〈:= symmetry〉

[[Γ,N B lei := ei : com]]η ψ

= lei 6= error ∧ ψ[ei/lei ] [by the semantics of assignment]= leπ(i) 6= error ∧ ψ[eπ(i)/leπ(i)] [by a property a substitution]

F.1. PROOFS OF LAWS 229

= [[Γ,N B leπ(i) := eπ(i) : com]]η ψ [by the semantics of assignment]

2

F.1.2 Conditional

Proof F.1.4 Law 〈if symmetry〉

[[Γ,N B if []i • ψi → ci fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ) [by the semantics of alternation]= (∨ i • ψπ(i)) ∧ (∧ i • ψπ(i) ⇒ [[Γ,N B cπ(i) : com]]η ψ)

[by commutativity of disjunction and conjunction]= [[Γ,N B if []i • ψπ(i) → cπ(i) fi : com]]η ψ [by the semantics of alternation]

2

Proof F.1.5 Law 〈if true guard〉

[[Γ,N B if true → c fi : com]]η ψ

= true ∧ true ⇒ [[Γ,N B c : com]]η ψ [by the semantics of alternation]= [[Γ,N B c : com]]η ψ [by predicate calculus]

2

Proof F.1.6 Law 〈if false unity〉

[[Γ,N B if false → c [] ψi → ci fi : com]]η ψ

= (∨ i • ψi ∨ false) ∧ (false ⇒ [[Γ,N B c : com]]η ψ) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)[by the semantics of alternation]

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ) [by predicate calculus]= [[Γ,N B if ψi → ci fi : com]]η ψ [by the semantics of alternation]

2

Proof F.1.7 Law 〈if abort unity〉

[[Γ,N B if () fi : com]]η ψ

230 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= false [by the semantics of alternation and predicate calculus]= [[Γ,N B abort : com]]η ψ [by Lemma 12]

2

Proof F.1.8 Law 〈if - ∨ distrib1 〉

[[Γ,N B if ψ1 → c[]ψ2 → c[]([]i • ψi → ci) fi : com]]η ψ

= (∨ i • ψi ∨ ψ1 ∨ ψ2) ∧ (ψ1 ⇒ [[Γ,N B c : com]]η ψ)∧ (ψ2 ⇒ [[Γ,N B c : com]]η ψ) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)

[by the semantics of alternation]= (∨ i • ψi ∨ ψ1 ∨ ψ2) ∧ ((ψ1 ∨ ψ2 ⇒ [[Γ,N B c : com]]η ψ) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ))

[by predicate calculus]= [[Γ,N B if (ψ1 ∨ ψ2) → c [] ([]i • ψi → ci) : com]]η ψ [by the semantics of alternation]

2

Proof F.1.9 Law 〈if elim〉

[[Γ,N B if ψ → (if ψ → c [] (ψi → ci) fi)[] ψj → cj fi : com]]η ψ

= (∨ j • ψj ∨ ψ) ∧ (ψ ⇒ (if ψ → c([]i • ψi → ci)) ∧ (ψj ⇒ [[Γ,N B cj : com]]η ψ)[by the semantics of alternation]

= (∨ j • ψj ∨ ψ) ∧ (ψ ⇒ (([]i • ψi ∨ ψ) ∧ (ψ ⇒ [[Γ,N B c : com]]η ψ) ∧([]i • ψi ⇒ [[Γ,N B ci : com]]η ψ))) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by the semantics of alternation]= (∨ j • ψj ∨ ψ) ∧ (¬ ψ ∨ (([]i • ψi ∨ ψ) ∧ (ψ ⇒ [[Γ,N B c : com]]η ψ) ∧([]i • ψi ⇒ [[Γ,N B ci : com]]η ψ))) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ (¬ ψ ∨ (([]i • ψi ∨ ψ) ∧(¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧ (ψi ∨ [[Γ,N B ci : com]]η ψ))) ∧([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ) [by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ (([]i • ψi ∨ ψ ∨ ¬ ψ) ∧ (¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧([]i • ψi¬ ψ ∨ ¬ ψ ∨ [[Γ,N B ci : com]]η ψ)) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ ((¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧([]i • ψi¬ ψ ∨ ¬ ψ ∨ [[Γ,N B ci : com]]η ψ)) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ (¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧

F.1. PROOFS OF LAWS 231

(¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧ (([]i • ψi¬ ψ ∨ ¬ ψ) ∨ [[Γ,N B ci : com]]η ψ) ∧([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ (¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧ (¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧(true ∨ [[Γ,N B ci : com]]η ψ) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by the hypothesis]= (∨ j • ψj ∨ ψ) ∧ (¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧(false ⇒ [[Γ,N B ci : com]]η ψ ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ (¬ ψ ∨ [[Γ,N B c : com]]η ψ) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= (∨ j • ψj ∨ ψ) ∧ (ψ ⇒ [[Γ,N B c : com]]η ψ) ∧ ([]j • ψj ⇒ [[Γ,N B cj : com]]η ψ)

[by predicate calculus]= [[Γ,N B if ψ → c [] ([]j • ψj → cj ) fi : com]]η ψ)

[by the semantics of alternation]

2

Proof F.1.10 Law 〈if - ∨ distrib2 〉

[[Γ,N B if ψ1 → c1 [] ¬ ψ1 → (if ψ2 → c1 [] ¬ ψ2 → c2 fi) fi : com]]η ψ

= (ψ1 ∨ ¬ ψ1) ∧ (ψ1 ⇒ [[Γ,N B c1 : com]]η ψ) ∧(¬ ψ1 ⇒ [[Γ,N B if ψ2 → c1 [] ¬ ψ2 → c2 fi : com]]η ψ)

[by the semantics of alternation]= (ψ1 ⇒ [[Γ,N B c1 : com]]η ψ) ∧ (¬ ψ1 ⇒ ((ψ2 ∨ ¬ ψ2) ∧ (ψ2 ⇒ [[Γ,N B c1 : com]]η ψ) ∧(¬ ψ2 ⇒ [[Γ,N B c2 : com]]η ψ)))

[by the semantics of alternation and predicate calculus]= (ψ1 ⇒ [[Γ,N B c1 : com]]η ψ) ∧ (¬ ψ1 ⇒ ((ψ2 ⇒ [[Γ,N B c1 : com]]η ψ) ∧(¬ ψ2 ⇒ [[Γ,N B c2 : com]]η ψ)))

[by predicate calculus]= (¬ ψ1 ∨ [[Γ,N B c1 : com]]η ψ) ∧ (ψ1 ∨ ((¬ ψ2 ∨ [[Γ,N B c1 : com]]η ψ) ∧(ψ2 ∨ [[Γ,N B c2 : com]]η ψ))

[by predicate calculus]= (¬ ψ1 ∨ [[Γ,N B c1 : com]]η ψ) ∧ ((ψ1 ∨ ¬ ψ2 ∨ [[Γ,N B c1 : com]]η ψ) ∧(ψ1 ∨ ψ2 ∨ [[Γ,N B c2 : com]]η ψ))

[by predicate calculus]= ([[Γ,N B c1 : com]]η ψ(¬ ψ1 ∧ (ψ1 ∨ ¬ ψ2))) ∧ (ψ1 ∨ ψ2 ∨ [[Γ,N B c2 : com]]η ψ)

[by predicate calculus]

232 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= ([[Γ,N B c1 : com]]η ψ ∨ ((¬ ψ1 ∧ ψ1) ∨ (¬ ψ1 ∧ ¬ ψ2)) ∧ (ψ1 ∨ ψ2 ∨ [[Γ,N B c2 : com]]η ψ)[by predicate calculus]

= ([[Γ,N B c1 : com]]η ψ ∨ (¬ (ψ1 ∨ ψ2)) ∧ (ψ1 ∨ ψ2 ∨ [[Γ,N B c2 : com]]η ψ)[by predicate calculus]

= ((ψ1 ∨ ψ2) ⇒ [[Γ,N B c1 : com]]η ψ) ∧ (¬ (ψ1 ∨ ψ2) ⇒ [[Γ,N B c2 : com]]η ψ)[by predicate calculus]

= [[Γ,N B if (ψ1 ∨ ψ2) → c1[]¬ (ψ1 ∨ ψ2) → c2 fi : com]]η ψ

[by the semantics of alternation]

2

Proof F.1.11 Law 〈if - ∧ distrib〉

[[Γ,N B if ψ1 → (if ψ2 → c1 [] ¬ ψ2 → c2 fi) [] ¬ ψ1 → c2 fi : com]]η ψ

= (ψ1 ∨ ¬ ψ1) ∧ (ψ1 ⇒ [[Γ,N B if ψ2 → c1 [] ¬ ψ2 → c2 : com]]η ψ) ∧(¬ ψ1 ⇒ [[Γ,N B c2 : com]]η ψ [by the semantics of alternation]= (ψ1 ∨ ¬ ψ1) ∧ (ψ1 ⇒ ((ψ2 ∨ ¬ ψ2) ∧ (ψ2 ⇒ [[Γ,N B c1 : com]]η ψ) ∧(¬ ψ2 ⇒ [[Γ,N B c2 : com]]η ψ))) ∧ (¬ ψ1 ⇒ [[Γ,N B c2 : com]]η ψ

[by the semantics of alternation]= (ψ1 ⇒ ((ψ2 ⇒ [[Γ,N B c1 : com]]η ψ) ∧ (¬ ψ2 ⇒ [[Γ,N B c2 : com]]η ψ))) ∧(¬ ψ1 ⇒ [[Γ,N B c2 : com]]η ψ) [by predicate calculus]= (¬ ψ1 ∨ ((¬ ψ2 ∨ [[Γ,N B c1 : com]]η ψ) ∧ (ψ2 ∨ [[Γ,N B c2 : com]]η ψ))) ∧(ψ1 ∨ [[Γ,N B c2 : com]]η ψ) [by predicate calculus]= (¬ ψ1 ∨ ¬ ψ2 ∨ [[Γ,N B c1 : com]]η ψ) ∧ (¬ ψ1 ∨ ψ2 ∨ [[Γ,N B c2 : com]]η ψ))) ∧(ψ1 ∨ [[Γ,N B c2 : com]]η ψ) [by predicate calculus]= (¬ (ψ1 ∧ ψ2) ∨ [[Γ,N B c1 : com]]η ψ) ∧ (¬ ψ1 ∨ ψ2 ∨ [[Γ,N B c2 : com]]η ψ))) ∧(ψ1 ∨ [[Γ,N B c2 : com]]η ψ) [by predicate calculus]= (¬ (ψ1 ∧ ψ2) ∨ [[Γ,N B c1 : com]]η ψ) ∧((¬ ψ1 ∧ ψ1) ∨ (ψ1 ∧ ψ2) ∨ [[Γ,N B c2 : com]]η ψ) [by predicate calculus]= (¬ (ψ1 ∧ ψ2) ∨ [[Γ,N B c1 : com]]η ψ) ∧ ((ψ1 ∧ ψ2) ∨ [[Γ,N B c1 : com]]η ψ)

[by predicate calculus]= ((ψ1 ∧ ψ2) ⇒ [[Γ,N B c1 : com]]η ψ) ∧ (¬ (ψ1 ∧ ψ2) ⇒ [[Γ,N B c2 : com]]η ψ)

[by predicate calculus]= ((ψ1 ∧ ψ2) ∨ ¬ (ψ1 ∧ ψ2)) ∧((ψ1 ∧ ψ2) ⇒ [[Γ,N B c1 : com]]η ψ) ∧ (¬ (ψ1 ∧ ψ2) ⇒ [[Γ,N B c2 : com]]η ψ)

[by predicate calculus]= [[Γ,N B if (ψ1 ∧ ψ2) → c1 [] ¬ (ψ1 ∧ ψ2) → c2 fi : com]]η ψ

[by the semantics of alternation]

F.1. PROOFS OF LAWS 233

2

Proof F.1.12 Law 〈if gc intro〉

[[Γ,N B if []i • ψi → ci fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ) [by the semantics of alternation]⇒ (∨ i • ψi ∨ ψ) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ) ∧ (ψ ⇒ [[Γ,N B c : com]]η ψ))

[by the hypothesis]= [[Γ,N B if ([]i • ψi → ci) [] ψ → c fi : com]]η ψ [by the semantics of alternation]

2

Proof F.1.13 Law 〈if gc elim〉

[[Γ,N B if ψ → c [] ([]i • ψi → ci) fi : com]]η ψ

= (ψ ⇒ [[Γ,N B c : com]]η ψ) ∧ ((∨ i • ψi) ∧(∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)) [by the semantics of alternation]⇒ (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ) [by the hypothesis]= [[Γ,N B if ([]i • ψi → ci) fi : com]]η ψ [by the semantics of alternation]

2

Proof F.1.14 Law 〈if true guard ref 〉

[[Γ,N B if true → c [] ([]i • ψi → ci) fi : com]]η ψ

= (∨ i • ψi ∨ true) ∧ (true ⇒ [[Γ,N B c : com]]η ψ) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)[by the semantics of alternation]

= (true ⇒ [[Γ,N B c : com]]η ψ) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)[by predicate calculus]⇒ [[Γ,N B c : com]]η ψ [by predicate calculus]

2

F.1.3 Recursion

Proof F.1.15 Law 〈rec fixed point〉

[[Γ,N B recX • F (X ) : com]]η ψ

234 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= [[Γ,N B µX • F (X ) : com]]η ψ [by the semantics of recursion]= [[Γ,N B F (µX • F (X )) : com]]η ψ [by unfolding least fixpoint]= [[Γ,N B F (recX • F (X )) : com]]η ψ [by the semantics of recursion]

2

F.1.4 Sequential Composition

Proof F.1.16 Law 〈; −skip unit〉

[[Γ,N B skip; c : com]]η ψ

= [[Γ,N B skip : com]]η ([[Γ,N B c : com]]η ψ)[by the semantics of sequential composition]= [[Γ,N B : [true, true] : com]]η ([[Γ,N B c : com]]η ψ) [by the definition of skip]= [[Γ,N B c : com]]η ψ [by the semantics of spec. statement and predicate calculus]= [[Γ,N B c : com]]η (true ∧ true ⇒ ψ) [by predicate calculus]= [[Γ,N B c : com]]η ([[Γ,N B : [true, true] : com]]η ψ)

[by the semantics of specification statement]= [[Γ,N B c : com]]η ([[Γ,N B skip : com]]η ψ) [by the definition of skip]= [[Γ,N B c; skip : com]]η ψ [by the semantics of sequential composition]

2

Proof F.1.17 Law 〈; −abort left zero〉

[[Γ,N B abort; c : com]]η ψ

= [[Γ,N B abort : com]]η ([[Γ,N B c : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B x : [false, true] : com]]η ([[Γ,N B c : com]]η ψ) [by the definition of abort]= false ∧ true ⇒ ([[Γ,N B c : com]]η ψ) [by the semantics of specification statement]= false [by predicate calculus]= ∀ x : T • false ∧ true ⇒ ψ [by predicate calculus]= [[Γ,N B x : [false, true] : com]]η ψ [by the semantics of specification statement]= [[Γ,N B abort : com]]η ψ [by the definition of abort]

2

F.1. PROOFS OF LAWS 235

Proof F.1.18 Law 〈; −miracle left zero〉

[[Γ,N B miracle; c : com]]η ψ

= [[Γ,N B miracle : com]]η ([[Γ,N B c : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B x : [true, false] : com]]η ([[Γ,N B c : com]]η ψ) [by the definition of miracle]= true ∧ false ⇒ (∀ x : T • [[Γ,N B c : com]]η ψ)

[by the semantics of specification statement]= true [by predicate calculus]= ∀ x : T • true ∧ false ⇒ ψ [by predicate calculus]= [[Γ,N B x : [true, false] : com]]η ψ [by the semantics of specification statement]= [[Γ,N B miracle : com]]η ψ [by the definition of miracle]

2

Proof F.1.19 Law 〈; assoc〉

[[Γ,N B (c1; c2); c3 : com]]η ψ

= [[Γ,N B c1; c2 : com]]η ([[Γ,N B c3 : com]]η ψ)[by the semantics of sequential composition]

= ([[Γ,N B c1 : com]]η ([[Γ,N B c2 : com]]η)) ([[Γ,N B c3 : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B c1 : com]]η ([[Γ,N B c2 : com]]η([[Γ,N B c3 : com]]η ψ)) [by associativity]= [[Γ,N B c1 : com]]η ([[Γ,N B c2; c3 : com]]η ψ)[by the semantics of sequential composition]= [[Γ,N B c1; (c2; c3) : com]]η ψ [by the semantics of sequential composition]

2

Proof F.1.20 Law 〈; −if left dist〉

[[Γ,N B if []i • ψi → ci fi; c : com]]η ψ

= [[Γ,N B if []i • ψi → ci fi : com]]η ([[Γ,N B c : com]]η ψ)[by the semantics of sequential composition]

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ([[Γ,N B c : com]]η ψ))[by the semantics of alternation]

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci ; c : com]]η ψ)[by the semantics of sequential composition]

236 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= [[Γ,N B if []i • ψi → ci ; c fi : com]]η ψ [by the semantics of alternation]

2

Proof F.1.21 Law 〈; −if selection〉

[[Γ,N B [ψj ]; if []i • ψi → ci fi : com]]η ψ

= [[Γ,N B [ψj ] : com]]η ([[Γ,N B if []i • ψi → ci fi : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B : [true, ψj ] : com]]η ([[Γ,N B if []i • ψi → ci fi : com]]η ψ)[definition of coercion]

= [[Γ,N B : [true, ψj ] : com]]η ((∨ i • ψi) ∧ ψi ⇒ [[Γ,N B ci : com]]η ψ)[by the semantics of alternation]

= ψj ⇒ (∨ i • ψi) ∧ ψi ⇒ [[Γ,N B ci : com]]η ψ[by the semantics of specification statement]= ψj ⇒ ψi ⇒ [[Γ,N B ci : com]]η ψ [by predicate calculus]= (ψj ∧ ψi) ⇒ [[Γ,N B ci : com]]η ψ [by predicate calculus]= ψj ⇒ [[Γ,N B cj : com]]η ψ [by the hypothesis]= [[Γ,N B : [true, ψj ] : com]]η ([[Γ,N B cj : com]]η ψ)

[by the semantics of specification statement]= [[Γ,N B [ψj ] : com]]η ([[Γ,N B cj : com]]η ψ) [definition of coercion]= [[Γ,N B [ψj ]; cj : com]]η ψ [ by the semantics of sequential composition

2

Proof F.1.22 Law 〈; − := combination〉

[[Γ,N B (le := e1; le := e2) : com]]η ψ

= [[Γ,N B le := e1 : com]]η ([[Γ,N B le := e2 : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B le := e1 : com]]η (e2 6= error ∧ ψ[e2/le]) [by the semantics of assignment]= e1 6= error ∧ (e2 6= error ∧ ψ[e2/le])[e1/le] [by the semantics of assignment]= e1 6= error ∧ e2 6= error ∧ (ψ[e2/le])[e1/le] [by predicate calculus]= [[Γ,N B le := e2[e1/le] : com]]η ψ [by the semantics of assignment]

2

Proof F.1.23 Law 〈:= − CB right dist〉

F.1. PROOFS OF LAWS 237

[[Γ,N B le := e; if []i • ψi → ci fi : com]]η ψ

= [[Γ,N B le := e : com]]η ([[Γ,N B if []i • ψi → ci fi : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B le := e : com]]η ((∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)))

[by the semantics of alternation= e 6= error ∧ ((∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ))[e/le]

[by the semantics of assignment]= e 6= error ∧ (∨ i • ψi)[e/le] ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ)[e/le][le is not free in ψi ]= (∨ i • ψi [e/le]) ∧ (∧ i • ψi [e/le] ⇒ [[Γ,N B le := e : com]]η ([[Γ,N B ci : com]]η ψ)

[by the semantics of assignment]= (∨ i • ψi [e/le]) ∧ (∧ i • ψi [e/le] ⇒ [[Γ,N B (le := e; ci) : com]]η ψ)

[by the semantics of sequential composition]= [[Γ,N B if []i • ψi [e/le] → (le := e; ci) fi : com]]η ψ [by the semantics of alternation]

2

F.1.5 Local Variable Block

Proof F.1.24 Law 〈var symmetry〉

[[Γ,N B var x1 : T1 • (var x2 : T2 • c end) end : com]]η ψ

= ∀ x1 : T1 • [[Γ; x1 : T1,N B var x2 : T2 • c end : com]]η ψ

[by the semantics of local blocks]= ∀ x1 : T1 • ∀ x2 : T2 • [[Γ; x1, x2 : T1,T2,N B c : com]]η ψ[by the semantics of local blocks]= ∀ x2 : T2 • ∀ x1 : T1 • [[Γ; x1, x2 : T1,T2,N B c : com]]η ψ [by predicate calculus]= ∀ x2 : T2 • [[Γ; x2 : T2,N B var x1 : T1 • c end : com]]η ψ

[by the semantics of local blocks]= [[Γ,N B var x2 : T2 • (var x1 : T1 • c end) end : com]]η ψ

[by the semantics of local blocks]

2

Proof F.1.25 Law 〈var elim〉

[[Γ,N B var x : T • c end : com]]η ψ

= ∀ x : T • [[Γ; x : T ,N B c : com]]η ψ [by the semantics of local blocks]= ∀ x : T • [[Γ,N B c : com]]η ψ [by x not free in c]= [[Γ,N B c : com]]η ψ [by x not free in c and ψ and predicate calculus]

238 APPENDIX F. PROOFS OF LAWS OF COMMANDS

2

Proof F.1.26 Law 〈var rename〉

[[Γ,N B var x1 : T • c end : com]]η ψ

= ∀ x1 : T • [[Γ; x1 : T ,N B c end : com]]η ψ [by the semantics of local blocks]= ∀ x2 : T • ([[Γ; x1 : T ,N B c end : com]]η ψ)[x2/x1] [by Lemma 13 and predicate calculus]= ∀ x2 : T • ([[Γ; x1 : T ,N B c end : com]]η)[x2/x1]ψ[x2/x1] [x2 not free in c]= ∀ x2 : T • [[Γ; x2 : T ,N B c[x2/x1]ψ [by Lemma 14]= [[Γ,N B var x2 : T • c[x2/x1] end : com]]η ψ [by the semantics of local blocks]

2

Proof F.1.27 Law 〈var− if dist〉

[[Γ,N B if []i • ψi → (var x : T • ci end) fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B var x : T • ci : com]]η ψ)[by the semantics of alternation]

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ ∀ x : T • [[Γ; x : T ,N B ci : com]]η ψ)[by the semantics of local blocks]

= ∀ x : T • (∧ i • ψi ⇒ [[Γ; x : T ,N B ci : com]]η ψ) [by predicate calculus]= ∀ x : T • [[Γ; x : T ,N B if []i • ψi → ci fi : com]]η ψ [by the semantics of alternation]= [[Γ,N B var x : T • if []i • ψi → ci fi end : com]]η ψ [by the semantics of local blocks]

2

Proof F.1.28 Law 〈var-; left dist〉

[[Γ,N B var x : T • c1 end; c2 : com]]η ψ

= [[Γ,N B var x : T • c1 end : com]]η ([[Γ,N B c2 : com]]η ψ)[by the semantics of sequential composition]

= ∀ x : T • [[Γ; x : T ,N B c1 : com]]η ([[Γ,N B c2 : com]]η ψ)[by the semantics of local blocks]

= ∀ x : T • [[Γ; x : T ,N B c1 : com]]η ([[Γ; x : T ,N B c2 : com]]η ψ)[x not free in c and ψ]= ∀ x : T • [[Γ; x : T ,N B c1; c2 : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B var x : T • c1; c2 end : com]]η ψ [by the semantics of local blocks]

2

F.1. PROOFS OF LAWS 239

Proof F.1.29 Law 〈var−; right dist〉

[[Γ,N B c1; var x : T • c2 end : com]]η ψ

= [[Γ,N B c1 : com]]η ([[Γ,N B varx : T • c2 end : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B c1 : com]]η (∀ x : T • [[Γ; x : T ,N B c2 end : com]]η ψ)[by the semantics of local blocks]

= ∀ x : T • [[Γ,N B c1 : com]]η (∀ x : T • [[Γ; x : T ,N B c2 end : com]]η ψ)[x is not free in c1]

= ∀ x : T • [[Γ,N B c1 : com]]η ([[Γ; x : T ,N B c2 end : com]]η ψ) [by predicate calculus]= ∀ x : T • [[Γ; x : T ,N B c1; c2 : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B var x : T • c1; c2 end : com]]η ψ [by the semantics of local blocks]

2

Proof F.1.30 Law 〈var- := final value〉

[[Γ,N B var x : T • c; x := e end : com]]η ψ

= ∀ x : T • [[Γ; x : T ,N B c; x := e : com]]η ψ [by the semantics of local blocks]= ∀ x : T • [[Γ; x : T ,N B c : com]]η ([[Γ; x : T ,N B x := e : com]]η ψ)

[by the semantics of sequential composition]= ∀ x : T • [[Γ; x : T ,N B c : com]]η (e 6= error ∧ ψ[e/x ])[by the semantics of assignment]= ∀ x : T • [[Γ; x : T ,N B c : com]]η ψ [x is not free in ψ]= [[Γ,N B var x : T • c end : com]]η ψ [by the semantics of local blocks]

2

Proof F.1.31 Law 〈var−; dist〉

[[Γ,N B var x : T • c1 end; var x : T • c2 end : com]]η ψ

= [[Γ,N B var x : T • c1 end : com]]η ([[Γ,N B var x : T • c2 end : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B var x : T • c1 end : com]]η (∀ x : T • [[Γ; x : T ,N B c2 : com]]η ψ)[by the semantics of local blocks]

= ∀ x : T • ([[Γ; x : T ,N B c1 : com]]η (∀ x : T • [[Γ; x : T ,N B c2 : com]]η ψ)[by the semantics of local blocks]

⇒ ∀ x : T • ([[Γ; x : T ,N B c1 : com]]η ([[Γ; x : T ,N B c2 : com]]η ψ)

240 APPENDIX F. PROOFS OF LAWS OF COMMANDS

[by predicate calculus and monotonicity]= ∀ x : T • [[Γ; x : T ,N B c1; c2 : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B var x : T • c1; c2 end : com]]η ψ [by the semantics of local blocks]

2

Proof F.1.32 Law 〈var− := initial value〉

[[Γ,N B var x : T • c end : com]]η ψ

= ∀ x : T • [[Γ; x : T ,N B c : com]]η ψ [by the semantics of local blocks]⇒ (∀ x : T • [[Γ; x : T ,N B c : com]]η ψ)[e/x ] [by predicate calculus]= ∀ x : T • ([[Γ; x : T ,N B c : com]]η ψ)[e/x ] [by predicate calculus]= ∀ x : T • e 6= error ∧ ([[Γ; x : T ,N B c : com]]η ψ)[e/x ] [by the hypothesis]= ∀ x : T • [[Γ; x : T ,N B x := e : com]]η ([[Γ; x : T ,N B c : com]]η ψ)

[by the semantics of assignment]= ∀ x : T • [[Γ; x : T ,N B x := e; c : com]]η ψ[by the semantics of sequential composition]= [[Γ,N B var x : T • x := e; c end : com]]η ψ [by the semantics of local blocks]

2

F.1.6 Angelic Variable Block

Proof F.1.33 Law 〈avar symmetry〉

[[Γ,N B avar x1 : T1 • (avar x2 : T2 • c end) end : com]]η ψ

= ∃ x1 : T1 • [[Γ; x1 : T1,N B avar x2 : T2 • c end : com]]η ψ

[by the semantics of angelic blocks]= ∃ x1 : T1 • (∃ x2 : T2 • [[Γ; x1, x2 : T1,T2,N B c : com]]η ψ

[by the semantics of angelic blocks]= ∃ x2 : T2 • (∃ x1 : T1 • [[Γ; x1, x2 : T1,T2,N B c : com]]η ψ

[by predicate calculus]= ∃ x2 : T2 • [[Γ; x2 : T2,N B avar x1 : T1 • c end : com]]η ψ

[by the semantics of angelic blocks]= [[Γ,N B avar x2 : T2 • (avar x1 : T1 • c end) end : com]]η ψ

[by the semantics of angelic blocks]

2

F.1. PROOFS OF LAWS 241

Proof F.1.34 Law 〈avar elim〉

[[Γ,N B avar x : T • c end : com]]η ψ

= ∃ x : T • [[Γ; x : T ,N B c : com]]η ψ [by the semantics of angelic blocks]= ∃ x : T • [[Γ,N B c : com]]η ψ [x not free in c]= [[Γ,N B c : com]]η ψ [x not free in c and ψ]

2

Proof F.1.35 Law 〈avar rename〉

[[Γ,N B avar x1 : T • c end : com]]η ψ

= ∃ x1 : T • [[Γ; x1 : T ,N B c end : com]]η ψ [by the semantics of angelic blocks]= ∃ x2 : T • ([[Γ; x1 : T ,N B c end : com]]η ψ)[x2/x1]

[by Lemma 13 and predicate calculus]= ∃ x2 : T • ([[Γ; x1 : T ,N B c end : com]]η)[x2/x1]ψ[x2/x1] [by x2 not free in c]= ∃ x2 : T • ([[Γ; x2 : T ,N B c end : com]]η)ψ [by Lemma 14]= [[Γ,N B avar x2 : T • c[x2/x1] end : com]]η ψ [by the semantics of angelic blocks]

2

Proof F.1.36 Law 〈avar - if dist〉

[[Γ,N B if []i • ψi → (avar x : T • ci end) fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B avar x : T • ci : com]]η ψ)[by the semantics of alternation]

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ ∃ x : T • [[Γ; x : T ,N B ci : com]]η ψ)[by the semantics of angelic blocks]

= ∃ x : T • (∧ i • ψi ⇒ [[Γ; x : T ,N B ci : com]]η ψ) [by predicate calculus]= ∃ x : T • [[Γ; x : T ,N B if []i • ψi → ci fi : com]]η ψ [by the semantics of alternation]= [[Γ,N B avar x : T • if []i • ψi → ci fi end : com]]η ψ

[by the semantics of angelic blocks]

2

Proof F.1.37 Law 〈avar-; left dist〉

242 APPENDIX F. PROOFS OF LAWS OF COMMANDS

[[Γ,N B avar x : T • c1 end; c2 : com]]η ψ

= [[Γ,N B avar x : T • c1 end : com]]η ([[Γ,N B c2 : com]]η ψ)[by the semantics of sequential composition]

= ∃ x : T • [[Γ; x : T ,N B c1 : com]]η ([[Γ,N B c2 : com]]η ψ)[by the semantics of angelic blocks]

= ∃ x : T • [[Γ; x : T ,N B c1 : com]]η ([[Γ; x : T ,N B c2 : com]]η ψ)[x not free in c and ψ]

= ∃ x : T • [[Γ; x : T ,N B c1; c2 : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B avar x : T • c1; c2 end : com]]η ψ [by the semantics of angelic blocks]

2

Proof F.1.38 Law 〈avar-; right dist〉

[[Γ,N B c1; avar x : T • c2 end : com]]η ψ

= [[Γ,N B c1 : com]]η ([[Γ,N B avarx : T • c2 end : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B c1 : com]]η (∃ x : T • [[Γ; x : T ,N B c2 end : com]]η ψ)[by the semantics of angelic blocks]

= ∃ x : T • [[Γ,N B c1 : com]]η (∃ x : T • [[Γ; x : T ,N B c2 end : com]]η ψ)[x not free in c1]

= ∃ x : T • [[Γ,N B c1 : com]]η ([[Γ; x : T ,N B c2 end : com]]η ψ) [by predicate calculus]= ∃ x : T • [[Γ; x : T ,N B c1; c2 : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B avar x : T • c1; c2 end : com]]η ψ [by the semantics of angelic blocks]

2

Proof F.1.39 Law 〈avar- := final value〉

[[Γ,N B avar x : T • c; x := e end : com]]η ψ

= ∃ x : T • [[Γ; x : T ,N B c; x := e : com]]η ψ [by the semantics of angelic blocks]= ∃ x : T • [[Γ; x : T ,N B c : com]]η ([[Γ; x : T ,N B x := e : com]]η ψ)

[by the semantics of sequential composition]= ∃ x : T • [[Γ; x : T ,N B c : com]]η (e 6= error ∧ ψ[e/x ])

[by the semantics of assignment]= ∃ x : T • [[Γ; x : T ,N B c : com]]η ψ [x not free in ψ]= [[Γ,N B avar x : T • c end : com]]η ψ [by the semantics of angelic blocks]

F.1. PROOFS OF LAWS 243

2

Proof F.1.40 Law 〈avar - var relationship〉

[[Γ,N B (avar x : T • {x = e}; c end) : com]]η ψ

= ∃ x : T • [[Γ; x : T ,N B {x = e}; c : com]]η ψ

[by the semantics of angelic blocks]= ∃ x : T • [[Γ; x : T ,N B {x = e} : com]]η ([[Γ; x : T ,N B c : com]]η ψ)

[by the semantics of sequential composition]= ∃ x : T • [[Γ; x : T ,N B : [x = e, true] : com]]η ([[Γ; x : T ,N B c : com]]η ψ)

[by the definition of assumption]= ∃ x : T • x = e ∧ ([[Γ; x : T ,N B c : com]]η ψ)

[by the semantics of specification statement]= ∀ x : T • x = e ⇒ ([[Γ; x : T ,N B c : com]]η ψ) [by predicate calculus]= ∀ x : T • [[Γ; x : T ,N B : [true, x = e] : com]]η ([[Γ; x : T ,N B c : com]]η ψ)

[by the semantics of specification statement]= ∀ x : T • [[Γ; x : T ,N B [x = e] : com]]η ([[Γ; x : T ,N B c : com]]η ψ)

[by the definition of coercion]= ∀ x : T • [[Γ; x : T ,N B [x = e]; c : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B (var x : T • [x = e]; c end) : com]]η ψ [by the semantics of angelic blocks]

2

Proof F.1.41 Law 〈avar-; dist〉

[[Γ,N B avar x : T • c1; c2 end : com]]η ψ

= ∃ x : T • [[Γ; x : T ,N B c1; c2 : com]]η ψ [by the semantics of angelic blocks]= ∃ x : T • [[Γ; x : T ,N B c1 : com]]η ([[Γ; x : T ,N B c2 : com]]η ψ)

[by the semantics of sequential composition]⇒ ∃ x : T • [[Γ; x : T ,N B c1 : com]]η (∃ x : T • [[Γ; x : T ,N B c2 : com]]η ψ)

[by predicate calculus and monotonicity]= ∃ x : T • [[Γ; x : T ,N B c1 : com]]η ([[Γ,N B avar x : T • c2 end : com]]η ψ)

[by the semantics of angelic blocks]= [[Γ,N B avar x : T • c1 end : com]]η ([[Γ,N B avar x : T • c2 end : com]]η ψ)

[by the semantics of angelic blocks]= [[Γ,N B avar x : T • c1 end; avar x : T • c2 end : com]]η ψ

[by the semantics of sequential composition]

244 APPENDIX F. PROOFS OF LAWS OF COMMANDS

2

Proof F.1.42 Law 〈avar- := initial value〉

[[Γ,N B (avar x : T • x := e; c end) : com]]η ψ

= ∃ x : T • [[Γ; x : T ,N B x := e; c : com]]η ψ [by the semantics of angelic blocks]= ∃ x : T • [[Γ; x : T ,N B x := e : com]]η([[Γ; x : T ,N B c : com]]η ψ)

[by the semantics of sequential composition]= ∃ x : T • e 6= error ∧ ([[Γ; x : T ,N B c : com]]η ψ)[e/x ]

[by the semantics of assignment]= ∃ x : T • [[Γ; x : T ,N B c : com]]η ψ[e/x ]

⇒ ∃ x : T • ∃ x • [[Γ; x : T ,N B c : com]]η ψ [by predicate calculus]= [[Γ,N B (avar x : T • c end) : com]]η ψ [by the semantics of angelic blocks]

2

Proof F.1.43 Law 〈var - avar refinement〉

[[Γ,N B (var x : T • c end) : com]]η ψ

= ∀ x : T • [[Γ; x : T ,N B c : com]]η ψ [by the semantics of angelic blocks]⇒ ∃ x : T • [[Γ; x : T ,N B c : com]]η ψ [by predicate calculus]= [[Γ,N B (avar x : T • c end) : com]]η ψ

[by the semantics of angelic blocks]

2

F.2 Proof of additional command laws

In this section, we present some proofs of laws presented in Section D.7.

Proof F.2.1 Law 〈if identical guarded commands〉

[[Γ,N B if []i : 1..n • ψi → c fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B c : com]]η ψ) [by the semantics of alternation]= (∨ i • ψi) ∧ ((∨ i • ψi) ⇒ [[Γ,N B c : com]]η ψ) [by predicate calculus]= [[Γ,N B c : com]]η ψ [by predicate calculus]

2

F.2. PROOF OF ADDITIONAL COMMAND LAWS 245

Proof F.2.2 Law 〈iteration guards〉

do []i • gi → ci od

= Abbreviation

rec Y • if []i • Gi → ci ; Y [] ¬ (∨ i • Gi) → skip fi end

v 〈alternation guards〉

rec Y • if []i • Hi → ci ; Y [] ¬ (∨ i • Hi) → skip fi end

= Abbreviation

do []i • hi → ci od

For the proof obligation of law 〈alternation guards〉 we have

(i) GG ∨ ¬ GG ⇒ HH ∨ ¬ HH(ii) GG ∨ ¬ GG ⇒ (Hi ⇒ Gi) ≡ Hi ⇒ Gi

GG ∨ ¬ GG ⇒ ¬ HH ⇒ ¬ GG ≡ GG ⇒ HH

2

Proof F.2.3 Law 〈weakening guards〉

if []i • gi ∧ g → ci fi

v 〈alternation guards〉

if []i • gi → ci fi

For the proof obligation of law 〈alternation guards〉

(∨ i • gi ∧ g)≡ (∨ i • gi) ∧ g⇒ (∨ i • gi)

(∨ i • gi ∧ g) ∧ gi

≡ (∨ i • gi) ∧ g ∧ gi

246 APPENDIX F. PROOFS OF LAWS OF COMMANDS

⇒ gi ∧ g

2

Proof F.2.4 Law 〈innocuous assumption-reading〉

[[Γ,N B le1 := le.x : com]]η ψ

= le.x 6= error ∧ ψ[le.x/le] [by the semantics of assignment]= le 6= null ∧ le 6= error ∧ le.x 6= error ∧ ψ[le.x/le1]

[by the semantic definition of attribute selection]= le 6= null ∧ le 6= error ∧ (le.x 6= error ∧ ψ[le.x/le1]) [by predicate calculus]= le 6= null ∧ le 6= error ∧ true ⇒ (le.x 6= error ∧ ψ[le.x/le1]) [by predicate calculus]= le 6= null ∧ le 6= error ∧ true ⇒ ([[Γ,N B le1 := le.x : com]]η ψ)

[by the semantics of assignment]= [[Γ,N B : [le 6= null ∧ le 6= error] : com]]η ([[Γ,N B le1 := le.x : com]]η ψ)

[by the semantics of specification statement]= [[Γ,N B {le 6= null ∧ le 6= error} le1 := le.x : com]]η ψ

[by the semantics of sequential composition]

2

Proof F.2.5 Law 〈innocuous assumption-writing〉

We assume that exp is not error, as our main concern here is the value of the expression le.

[[Γ,N B le.x := exp : com]]η ψ

= [[Γ,N B le := (le; x : exp) : com]]η ψ [by a syntactic transformation]= (le; x : exp) 6= error ∧ ψ[(le; x : exp)/le] [by the semantics of assignment]= le 6= null ∧ le 6= error ∧ (le; x : exp) 6= error ∧ ψ[(le; x : exp)/le]

[by the semantic definition of update expression and assumption]= le 6= null ∧ le 6= error ∧ [[Γ,N B le := (le; x : exp) : com]]η ψ

[by the semantics of assignment]= le 6= null ∧ le 6= error ∧ true ⇒ [[Γ,N B le := (le; x : exp) : com]]η ψ

[by predicate calculus]= [[Γ,N B : [le 6= null ∧ le 6= error] : com]]η ([[Γ,N B le := (le; x : exp) : com]]η ψ

[by the semantics of specification statement]= [[Γ,N B : [le 6= null ∧ le 6= error]; le := (le; x : exp) : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B {le 6= null ∧ le 6= error} le := (le; x : exp) : com]]η ψ

F.2. PROOF OF ADDITIONAL COMMAND LAWS 247

[by the definition of assumption]= [[Γ,N B {le 6= null ∧ le 6= error} le.x := exp : com]]η ψ [by a syntactic transformation]

2

Proof F.2.6 Law 〈assumption guard〉

[[Γ,N B if []i • ψi → ci fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B c : com]]η ψ) [by the semantics of alternation]= (∨ i • ψi) ∧ (∧ i • ψi ∧ ψi ⇒ [[Γ,N B c : com]]η ψ) [by predicate calculus]= (∨ i • ψi) ∧ (∧ i • ψi ⇒ ψi ⇒ ([[Γ,N B ci fi : com]]η ψ)) [by predicate calculus]= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B : [ψi , true] com]]η ([[Γ,N B ci fi : com]]η ψ))

[by the semantics of specification statement]= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B {ψi} com]]η ([[Γ,N B ci fi : com]]η ψ))

[by definition of assumption]= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B {ψi} ci fi : com]]η ψ)

[by the semantics of sequential composition]= [[Γ,N B if []i • ψi → {ψi} ci fi : com]]η ψ [by the semantics of alternation]

2

Proof F.2.7 Law 〈var block absorb assumption〉

[[Γ,N B {ψ} var x : T • c end : com]]η ψ

= [[Γ,N B : [φ, true]; var x : T • c end : com]]η ψ [by definition of assumption]= [[Γ,N B : [φ, true] : com]]η ([[Γ,N B var x : T • c end : com]]η ψ)

[by the semantics of sequential composition]= φ ∧ true ⇒ [[Γ,N B var x : T • c end : com]]η ψ

[by the semantics of specification statement]= φ ∧ [[Γ,N B var x : T • c end : com]]η ψ [by predicate calculus]= φ ∧ (∀ x : T • [[Γ; x : T ,N B c : com]]η ψ) [by the semantics of local blocks]= (∀ x : T • φ) ∧ (∀ x : T • [[Γ; x : T ,N B c : com]]η ψ) [by hypothesis]= ∀ x : T • φ ∧ [[Γ; x : T ,N B c : com]]η ψ [by predicate calculus]= ∀ x : T • φ ∧ true ⇒ ([[Γ; x : T ,N B c : com]]η ψ) [by predicate calculus]= ∀ x : T • [[Γ; x : T ,N B : [φ, true] : com]]η ([[Γ; x : T ,N B c : com]]η ψ)

[by the semantics of specification statement]= ∀ x : T • [[Γ; x : T ,N B : [φ, true]; c : com]]η ψ

[by the semantics of sequential composition]

248 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= ∀ x : T • [[Γ; x : T ,N B {φ}c : com]]η ψ [by definition of assumption]= [[Γ,N B {φ}c : com]]η ψ [by the semantics of local blocks]

2

Proof F.2.8 Law 〈alternation absorb assumption〉

[[Γ,N B {φ} if ψi → ci fi : com]]η ψ

= [[Γ,N B : [φ, true]; if ψi → ci fi : com]]η ψ [by the definition of assumption]= [[Γ,N B : [φ, true] : com]]η ([[Γ,N B if ψi → ci fi : com]]η ψ)

[by the semantics of sequential composition]= φ ∧ true ⇒ ([[Γ,N B if ψi → ci fi : com]]η ψ)[by the semantics of specification statement]= φ ∧ ([[Γ,N B if ψi → ci fi : com]]η ψ) [by predicate calculus]= φ ∧ ((∨ i • ψi) ∧ (∧ i • ψi ⇒ ([[Γ,N B ci : com]]η ψ))) [by the semantics of alternation]= (φ ∧ (∨ i • ψi) ∧ (φ ∧ (∧ i • ψi ⇒ ([[Γ,N B ci : com]]η ψ)))) [by predicate calculus]= (∨ i • φ ∧ ψi) ∧ (∧ i • φ ∧ ψi ⇒ [[Γ,N B ci : com]]η ψ) [by predicate calculus]= [[Γ,N B if φ ∧ ψi → ci fi : com]]η ψ [by the semantics of alternation]

2

Proof F.2.9 Law 〈pcom absorb assumption〉

By induction on the structure of parameterised command of the form pds • c.

Case (• c)

[[Γ,N B {φ}; (• c)() : com]]η ψ

= [[Γ,N B {φ}; c : com]]η ψ [by a syntactic transformation]= [[Γ,N B ( • {φ}; c)() : com]]η ψ [by a syntactic transformation ]

Case Value parameter.

[[Γ,N B {φ}; (val x : T • c)(e) : com]]η ψ

= [[Γ,N B {φ} : com]]η ([[Γ,N B (val x : T • c)(e) : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B : [φ, true] : com]]η ([[Γ,N B (val x : T • c)(e) : com]]η ψ)[by the definition of assumption]

= φ ∧ true ⇒ ([[Γ,N B (val x : T • c)(e) : com]]η ψ)[by the semantics of specification statement]

F.2. PROOF OF ADDITIONAL COMMAND LAWS 249

= φ ∧ [[Γ,N B (val x : T • c)(e) : com]]η ψ

[by the predicate calculus]= φ ∧ [[Γ,N B var l : T • l := e; c[l/x ]end : com]]η ψ

[by a syntactic transformation]= φ ∧ ∀ l : T • e 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e/l ]

[by the semantics definitions]= ∀ l : T • φ ∧ e 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e/l ]

[by the hypothesis and the predicate calculus]= ∀ l : T • e 6= error ∧ φ([[Γ; l : T ,N B c[l/x ] end : com]]η ψ)[e/l ]

[by the predicate calculus]= ∀ l : T • e 6= error ∧ φ[l/x ][e/l ] ∧ ([[Γ; l : T ,N B c[l/x ] end : com]]η ψ)[e/l ]

[by the hypothesis and a property of substitution]= ∀ l : T • e 6= error ∧ (φ[l/x ] ∧ ([[Γ; l : T ,N B c[l/x ] end : com]]η ψ))[e/l ]

[by the predicate calculus and a property of substitution]= ∀ l : T • e 6= error ∧ (φ[l/x ] ∧ true ⇒ ([[Γ; l : T ,N B c[l/x ] end : com]]η ψ))[e/l ]

[by the predicate calculus]= ∀ l : T • e 6= error ∧ ([[Γ; l : T ,N B : [φ[l/x ], true] : com]]η

([[Γ; l : T ,N B c[l/x ] end : com]]η ψ))[e/l ][by the semantics of specification statement]

= ∀ l : T • e 6= error ∧ ([[Γ; l : T ,N B (: [φ, true])[l/x ] : com]]η([[Γ; l : T ,N B c[l/x ] end : com]]η ψ))[e/l ]

[by a property of substitution]= ∀ l : T • e 6= error ∧ ([[Γ; l : T ,N B ({φ})[l/x ] : com]]η

([[Γ; l : T ,N B c[l/x ] end : com]]η ψ))[e/l ][by the definition of assumption]

= ∀ l : T • e 6= error ∧ ([[Γ; l : T ,N B ({φ})[l/x ]; c[l/x ] end : com]]η ψ)[e/l ][by the semantics of sequential composition]

= ∀ l : T • e 6= error ∧ ([[Γ; l : T ,N B ({φ}; c)[l/x ] end : com]]η ψ)[e/l ][by a property of substitution]

= [[Γ,N B var l : T • l := e; ({φ}; c)[l/x ] end : com]]η ψ [by the semantics definitions]= [[Γ,N B (val l : T • {φ}; c)(e) : com]]η ψ [by a syntactic transformation]

Case Result parameter: similar.

Case (pd ; pds • c)

[[Γ,N B {φ}; (pd ; pds • c)(e, e ′) : com]]η ψ

= [[Γ,N B {φ}; (pd • (pds • c)(e ′))(e) : com]]η ψ [by a syntactic transformation]

250 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= [[Γ,N B (pd • (pds • {φ}; c)(e ′))(e) : com]]η ψ [by the induction hypothesis]= [[Γ,N B (pd ; pds • {φ}c)(e, e ′) : com]]η ψ [by a syntactic transformation]

2

Proof F.2.10 Law 〈assumption before or after command〉By induction.

Case x := e

[[Γ,N B {φ} x := e : com]]η ψ

= [[Γ,N B : [φ, true]; x := e : com]]η ψ [by definition of assumption]= [[Γ,N B : [φ, true] : com]]η ([[Γ,N B x := e : com]]η ψ)

[by the semantics of sequential composition]= φ ∧ true ⇒ [[Γ,N B x := e : com]]η ψ [by the semantics of specification statement]= φ ∧ [[Γ,N B x := e : com]]η ψ [by predicate calculus]= φ ∧ e 6= error ∧ ψ[e/x ] [by the semantics of assignment]= e 6= error ∧ ψ[e/x ] ∧ φ [by predicate calculus]= e 6= error ∧ ψ[e/x ] ∧ φ[e/x ] [by x is not free in φ]= e 6= error ∧ (φ ∧ ψ)[e/x ] [by predicate calculus]= [[Γ,N B x := e : com]]η (φ ∧ ψ) [by the semantics of assignment]= [[Γ,N B x := e : com]]η (φ ∧ true ⇒ ψ) [by predicate calculus]= [[Γ,N B x := e : com]]η ([[Γ,N B : [φ, true] : com]]η ψ)

[by the semantics of specification statement]= [[Γ,N B x := e; : [φ, true] : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B x := e; {φ} : com]]η ψ [by definition of assumption]

Case x : [ψ1, ψ2]

From left to right.

[[Γ,N B {φ} x : [ψ1, ψ2] : com]]η ψ

= [[Γ,N B : [φ, true]; x : [ψ1, ψ2] : com]]η ψ [by definition of assumption]= [[Γ,N B : [φ, true] : com]]η ([[Γ,N B x : [ψ1, ψ2] : com]]η ψ)

[by the semantics of sequential composition]= φ ∧ true ⇒ [[Γ,N B x : [ψ1, ψ2] : com]]η ψ [by the semantics of specification statement]= φ ∧ [[Γ,N B x : [ψ1, ψ2] : com]]η ψ [by predicate calculus]= φ ∧ ψ1 ∧ (∀ x : T • ψ2 ⇒ ψ) [by the semantics of specification statement]= ψ1 ∧ (∀ x : T • φ ∧ (ψ2 ⇒ ψ)) [by x is not free in φ]⇒ ψ1 ∧ (∀ x : T • ψ2 ⇒ (φ ∧ ψ)) [by predicate calculus]

F.2. PROOF OF ADDITIONAL COMMAND LAWS 251

= [[Γ,N B x : [ψ1, ψ2] : com]]η (φ ∧ ψ) [by the semantics of specification statement]= [[Γ,N B x : [ψ1, ψ2] : com]]η (φ ∧ true ⇒ ψ) [by predicate calculus]= [[Γ,N B x : [ψ1, ψ2] : com]]η ([[Γ,N B : [φ, true] : com]]η ψ)

[by the semantics of specification statement]= [[Γ,N B x : [ψ1, ψ2] : com]]η ([[Γ,N B {φ} : com]]η ψ) [by definition of assumption]= [[Γ,N B x : [ψ1, ψ2]; {φ} : com]]η ψ [by the semantics of sequential composition]

From right to left.

[[Γ,N B x : [ψ1, ψ2]; {φ} : com]]η ψ

= [[Γ,N B x : [ψ1, ψ2] : com]]η ([[Γ,N B {φ} : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B x : [ψ1, ψ2] : com]]η ([[Γ,N B : [φ, true] : com]]η ψ) [by definition of assumption]= [[Γ,N B x : [ψ1, ψ2] : com]]η (φ ∧ true ⇒ ψ) [by the semantics of specification statement]= ψ1 ∧ (∀ x : T • ψ2 ⇒ (φ ∧ true ⇒ ψ)) [by the semantics of specification statement]= ψ1 ∧ (∀ x : T • ψ2 ⇒ (φ ∧ ψ)) [by predicate calculus]⇒ ψ1 ∧ (∀ x : T • φ ∧ (ψ2 ⇒ ψ)) [by predicate calculus]= φ ∧ ψ1 ∧ (∀ x : T • ψ2 ⇒ ψ) [by x is not free in φ]= φ ∧ [[Γ,N B x : [ψ1, ψ2] : com]]η ψ [by the semantics of specification statement]= φ ∧ true ⇒ [[Γ,N B x : [ψ1, ψ2] : com]]η ψ [by predicate calculus]= [[Γ,N B : [φ, true] : com]]η ([[Γ,N B x := e : com]]η ψ)

[by the semantics of specification statement]= [[Γ,N B : [φ, true]; x : [ψ1, ψ2] : com]]η ψ [by the semantics of sequential composition]= [[Γ,N B {φ} x : [ψ1, ψ2] : com]]η ψ [by definition of assumption]

The other cases are consequence of the induction hypothesis.

2

Proof F.2.11 Law 〈assumption advance command〉

{φ}c= {φ}{φ}c [by predicate calculus and law 〈merge assumptions〉]= {φ}c; {φ} [by law 〈assumption before or after command〉]

2

Proof F.2.12 Law 〈assumption distribution〉This is a consequence of the application of laws 〈assumption advance command〉 (from left to right)

252 APPENDIX F. PROOFS OF LAWS OF COMMANDS

and 〈assumption before or after command〉 (from left to right), as many times as the number ofcommands in the command c.

2

Proof F.2.13 Law 〈new assumption〉

x := new N ()= x : [x = new N ()] [by law 〈simple specification〉]v x : [x = new N () ∧ x 6= null ∧ x 6= error]

[by law 〈strengthen postcondition〉 and hypothesis]v x : [x = new N () ∧ x 6= null ∧ x 6= error]; {x = new N () ∧ x 6= null ∧ x 6= error}

[by law 〈assumption intro〉]= x : [x = new N () ∧ x 6= null ∧ x 6= error]; {x = new N ()}{x 6= null ∧ x 6= error}

[by law 〈merge assumption〉, from right to left]v x : [x = new N () ∧ x 6= null ∧ x 6= error]; skip; {x 6= null ∧ x 6= error}

[by law 〈remove assumption〉]= x : [x = new N () ∧ x 6= null ∧ x 6= error]; {x 6= null ∧ x 6= error}[by law 〈; −skip unit〉]= x := new N (); {x 6= null ∧ x 6= error} [by law 〈assignment〉]

2

Proof F.2.14 Law 〈assumption intro〉

w : [ψ1, ψ2]= w : [ψ1, ψ2][ψ2] [by predicate calculus and law 〈absorb coercion〉]v w : [ψ1, ψ2][ψ2]; {ψ2} [by law 〈introduce assumption〉]= w : [ψ1, ψ2]; {ψ2} [by law 〈absorb coercion〉]

2

Proof F.2.15 Law 〈repeated assignment〉

[[Γ,N B le := e : com]]η ψ

= e 6= error ∧ ψ[e/le] [by the semantics of assignment]= e 6= error ∧ (e 6= error ∧ ψ[e/le])[e/le]

[by predicate calculus and a property of substitution]= [[Γ,N B le := e : com]]η (e 6= error ∧ ψ[e/le]) [by the semantics of assignment]

F.2. PROOF OF ADDITIONAL COMMAND LAWS 253

= [[Γ,N B le := e : com]]η ([[Γ,N B le := e : com]]η ψ) [by the semantics of assingment]= [[Γ,N B le := e; le := e : com]]η ψ [by the semantics of sequential composition]

2

Proof F.2.16 Law 〈order independent assignment〉

[[Γ,N B x := e1; y := e2 : com]]η ψ

= [[Γ,N B x := e1 : com]]η ([[Γ,N B y := e2 : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B x := e1 : com]]η (e2 6= error ∧ ψ[e2/y ]) [by the semantics of assignment]= e1 6= error ∧ (e2 6= error ∧ ψ[e2/y ])[e1/x ] [by the semantics of assignment]= e1 6= error ∧ e2 6= error ∧ ψ[e2/y ][e1/x ] [by x is not free in e2]= e1 6= error ∧ e2 6= error ∧ ψ[e1/x ][e2/y ]

[by y is not free in e1 and a property of substitution]= e2 6= error ∧ e1 6= errorψ[e1/x ][e2/y ] [by predicate calculus]= e2 6= error ∧ (e1 6= errorψ[e1/x ])[e2/y ] [by y is not free in e1]= [[Γ,N B y := e2 : com]]η (e1 6= errorψ[e1/x ]) [by the semantics of assignment]= [[Γ,N B y := e2 : com]]η ([[Γ,N B x := e1 : com]]η ψ) [by the semantics of assignment]= [[Γ,N B y := e2; x := e1 : com]]η ψ [by the semantics of sequential composition]

2

Proof F.2.17 Law 〈assignment seq comp exp substitution〉

By induction.

Case x := e, with x 6= le

[[Γ,N B le := exp; x := e1[exp] : com]]η ψ

= [[Γ,N B le := exp : com]]η ([[Γ,N B x := e1[exp] : com]]η ψ)[by the semantics of sequential composition]

= exp 6= error ∧ ([[Γ,N B x := e1[exp] : com]]η ψ)[exp/le] [by the semantics of assignment]= exp 6= error ∧ (e1[exp] 6= error ∧ ψ[e1[exp]/x ])[exp/le] [by the semantics of assignment]= exp 6= error ∧ e1[exp][exp/le] 6= error ∧ ψ[e1[exp]/x ][exp/le]

[by a property of substitution]= exp 6= error ∧ e1[le][exp/le] 6= error ∧ ψ[e1[le]/x ][exp/le] [by a property of substitution]= exp 6= error ∧ ([[Γ,N B x := e1[le] : com]]η ψ)[exp/le] [by the semantics of assignment]= [[Γ,N B le := exp : com]]η ([[Γ,N B x := e1[le] : com]]η ψ)[by the semantics of assignment]

254 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= [[Γ,N B le := exp; x := e1[le] : com]]η ψ) [by the semantics of sequential composition]

Case x : [ψ1[exp], ψ2[exp]]

[[Γ,N B le := exp; x : [ψ1[exp], ψ2[exp]] : com]]η ψ

= [[Γ,N B le := exp : com]]η ([[Γ,N B x : [ψ1[exp], ψ2[exp]] : com]]η ψ)[by the semantics of sequential composition]

= exp 6= error ∧ ([[Γ,N B x : [ψ1[exp], ψ2[exp]] : com]]η ψ)[exp/le][by the semantics of assignment]

= exp 6= error ∧ (ψ1[exp] ∧ (∀ x : T • ψ2[exp] ⇒ ψ))[exp/le][by the semantics of specification statement]

= exp 6= error ∧ (ψ1[exp][exp/le] ∧ (∀ x : T • ψ2[exp] ⇒ ψ)[exp/le])[by a property of substitution]

= exp 6= error ∧ (ψ1[exp][exp/le] ∧ (∀ x : T • ψ2[exp][exp/le] ⇒ ψ[exp/le]))[by a property of substitution]

= exp 6= error ∧ (ψ1[le][exp/le] ∧ (∀ x : T • ψ2[le][exp/le] ⇒ ψ[exp/le]))[by a property of substitution]

= exp 6= error ∧ (ψ1[le][exp/le] ∧ (∀ x : T • ψ2[le] ⇒ ψ)[exp/le])[by a property of substitution]

= exp 6= error ∧ (ψ1[le] ∧ (∀ x : T • ψ2[le] ⇒ ψ))[exp/le] [by a property of substitution]= exp 6= error ∧ ([[Γ,N B x : [ψ1[le], ψ2[le]] : com]]η ψ)[exp/le]

[by the semantics of specification statement]= [[Γ,N B le := exp : com]]η ([[Γ,N B x : [ψ1[le], ψ2[le]] : com]]η ψ)

[by the semantics of assignment]= [[Γ,N B le := exp; x : [ψ1[le], ψ2[le]] : com]]η ψ

[by the semantics of sequential composition]

Case c; c′

[[Γ,N B le := exp; (c; c′)[exp] : com]]η ψ

= [[Γ,N B le := exp : com]]η ([[Γ,N B (c; c′)[exp] : com]]η ψ)[by the semantics of sequential composition]

= exp 6= error ∧ ([[Γ,N B (c; c′)[exp] : com]]η ψ)[exp/le] [by the semantics of assignment]= exp 6= error ∧ ([[Γ,N B (c; c′)[le] : com]]η ψ)[exp/le] [by the induction hypothesis]= [[Γ,N B le := exp : com]]η ([[Γ,N B (c; c′)[le] : com]]η ψ)

[by the semantics of assignment]= [[Γ,N B le := exp; (c; c′)[le] : com]]η ψ) [by the semantics of sequential composition]

Case if []i • ψi → ci fi

F.2. PROOF OF ADDITIONAL COMMAND LAWS 255

[[Γ,N B le := exp; (if []i • ψi → ci fi)[exp] : com]]η ψ

= [[Γ,N B le := exp : com]]η ([[Γ,N B (if []i • ψi → ci fi)[exp] : com]]η ψ)[by the semantics of sequential composition]

= exp 6= error ∧ ([[Γ,N B (if []i • ψi → ci fi)[exp] : com]]η ψ)[exp/le][by the semantics of assignment]

= exp 6= error ∧ ([[Γ,N B (if []i • ψi → ci fi)[le] : com]]η ψ)[exp/le][by the induction hypothesis]

= [[Γ,N B le := exp : com]]η ([[Γ,N B (if []i • ψi → ci fi)[le] : com]]η ψ)[by the semantics of assignment]

= [[Γ,N B le := exp; (if []i • ψi → ci fi)[le] : com]]η ψ

[by the semantics of sequential composition]

Case (val x : T • c)(e)

[[Γ,N B le := exp; ((val x : T • c)(e))[exp] : com]]η ψ

= [[Γ,N B le := exp : com]]η ([[Γ,N B ((val x : T • c)(e))[exp] : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B le := exp : com]]η ([[Γ,N B (var l : T • l := e; c[l/x ] end)[exp] : com]]η ψ)[by a syntactic transformation]

= [[Γ,N B le := exp : com]]η (∀ l : T • [[Γ; l : T ,N B (l := e; c[l/x ])[exp] : com]]η ψ)[by the semantics of local blocks]

= [[Γ,N B le := exp : com]]η (∀ l : T • [[Γ; l : T ,N B l := e[exp]; c[l/x ] : com]]η ψ)[by a property of substitution]

= [[Γ,N B le := exp : com]]η(∀ l : T • [[Γ; l : T ,N B l := e[exp] : com]]η ([[Γ; l : T ,N B c[l/x ] : com]]η ψ))

[by the semantics of sequential composition]= [[Γ,N B le := exp : com]]η

(∀ l : T • e[exp] 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e[exp]/l ])[by the semantics of assignment]

= exp 6= error ∧(∀ l : T • e[exp] 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e[exp]/l ])[exp/le]

[by the semantics of assignment]= exp 6= error ∧

(∀ l : T • e[exp][exp/le] 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e[exp]/l ][exp/le])[by a property of substitution]

= exp 6= error ∧(∀ l : T • e[le][exp/le] 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e[le]/l ][exp/le])

[by a property of substitution]

256 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= exp 6= error ∧(∀ l : T • e[le] 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e[le]/l ])[exp/le]

[by a property of substitution]= [[Γ,N B le := exp : com]]η

(∀ l : T • e[le] 6= error ∧ ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[e[le]/l ])[by the semantics of assignment]

= [[Γ,N B le := exp : com]]η(∀ l : T • [[Γ; l : T ,N B l := e[le] : com]]η ([[Γ; l : T ,N B c[l/x ] : com]]η ψ))

[by the semantics of assignment]= [[Γ,N B le := exp : com]]η

(∀ l : T • [[Γ; l : T ,N B l := e[le]; c[l/x ] : com]]η ψ)[by the semantics of sequential composition]

= [[Γ,N B le := exp : com]]η([[Γ,N B var l : T • l := e[le]; c[l/x ] end : com]]η ψ)

[by the semantics of local blocks]= [[Γ,N B le := exp : com]]η

([[Γ,N B (val x : T • c)(e[le]) end : com]]η ψ)[by the semantics of local blocks]

= [[Γ,N B le := exp; (val x : T • c)(e[le]) end : com]]η ψ)[by the semantics of sequential composition]

Case var x : T • c end.

[[Γ,N B le := exp; (var x : T • c end)[exp] : com]]η ψ

= [[Γ,N B le := exp : com]]η ([[Γ,N B (var x : T • c end)[exp] : com]]η ψ)[by the semantics of sequential composition]

= exp 6= error ∧ ([[Γ,N B (var x : T • c end)[exp] : com]]η ψ)[exp/le][by the semantics of assignment]

= exp 6= error ∧ (∀ x : T • [[Γ; x : T ,N B c[exp] : com]]η ψ)[exp/le][by the semantics of local blocks]

= exp 6= error ∧ (∀ x : T • [[Γ; x : T ,N B c[le] : com]]η ψ)[exp/le][by the induction hypothesis]

= exp 6= error ∧ ([[Γ,N B (var x : T • c[le] end) : com]]η ψ)[exp/le][by the semantics of local blocks]

= [[Γ,N B le := exp : com]]η ([[Γ,N B (var x : T • c[le] end) : com]]η ψ)[by the semantics of assignment]

= [[Γ,N B le := exp; (var x : T • c[le] end) : com]]η ψ)[by the semantics of sequential composition]

F.2. PROOF OF ADDITIONAL COMMAND LAWS 257

Case avar x : T • c end: similar.2

Proof F.2.18 Law 〈var dec separation〉

[[Γ,N B var x , x ′ : T ,T ′ • c end : com]]η ψ

= ∀ x , x ′ : T ,T ′ • [[Γ; x , x ′ : T ,T ′,N • c : com]]η ψ [by the semantics of local blocks]= ∀ x : T • ∀ x ′ : T ′ • [[Γ; x , x ′ : T ,T ′,N • c : com]]η ψ [by predicate calculus]= ∀ x : T • ∀ x ′ : T ′ • [[Γ; x , x ′ : T ,T ′,N B c : com]]η ψ [by predicate calculus]= ∀ x : T • [[Γ; x : T ,N B var x ′ : T ′ • c end : com]]η ψ [by the semantics of local blocks]= [[Γ,N B var x : T • var x ′ : T ′ • c end end : com]]η ψ [by the semantics of local blocks]

2

Lemma 15 If l is not free in c and ψ; x is not on the left-hand side of assignments and it is nota method call target, result argument, nor it occurs in the frame of specification statements in c,then

[[Γ,N B c : com]]η ψ = ([[Γ; l : T ,N B c[l/x ] : com]]η ψ)[x/l ]

Proof By induction.

Case y := e, with y 6= x

[[Γ,N B y := e : com]]η ψ

= e 6= error ∧ ψ[e/y ] [by the semantics of assignment]= (e 6= error)[l/x ][x/l ] ∧ ψ[e[l/x ]/y ][l/x ][x/l ] [by a property of substitution]= (e[l/x ] 6= error)[x/l ] ∧ ψ[e[l/x ]/y ][l/x ][x/l ] [by a property of substitution]= (e[l/x ] 6= error ∧ ψ[e[l/x ]/y ][l/x ])[x/l ] [by a property of substitution]= (e[l/x ] 6= error ∧ ψ[e[l/x ]/y ])[x/l ] [by a property of substitution]= ([[Γ; l : T ,N B y := e[l/x ] : com]]η ψ)[x/l ] [by the semantics of assignment]= ([[Γ; l : T ,N B (y := e)[l/x ] : com]]η ψ)[x/l ] [by a property of substitution]

Case y : [ψ1, ψ2], with y 6= x

[[Γ; y : T ,N B y : [ψ1, ψ2] : com]]η ψ

= ψ1 ∧ (∀ y : T • ψ2 ⇒ ψ) [by the semantics of specification statement]= ψ1 ∧ (∀ y : T • ψ2 ⇒ ψ) [by the hypothesis and predicate calculus]

258 APPENDIX F. PROOFS OF LAWS OF COMMANDS

= ψ1 ∧ (∀ y : T • ψ2 ⇒ ψ[x/l ]) [by a property of substitution]= ψ1[l/x ][x/l ] ∧ (∀ y : T • ψ2[l/x ][x/l ] ⇒ ψ[x/l ]) [by a property of substitution]= ψ1[l/x ][x/l ] ∧ (∀ y : T • ψ2[l/x ] ⇒ ψ)[x/l ] [by a property of substitution]= (ψ1[l/x ] ∧ (∀ y : T • ψ2[l/x ] ⇒ ψ))[x/l ] [by a property of substitution]= ([[Γ; y : T ,N B y : [ψ1[l/x ], ψ2[l/x ]] : com]]η ψ)[x/l ]

[by the semantics of specification statement]= ([[Γ; y : T ,N B (x : [ψ1, ψ2])[l/x ] : com]]η ψ)[x/l ]

[by a property of substitution]

Case c; c′

[[Γ,N B c; c′ : com]]η ψ

= ([[Γ,N B c : com]]η ([[Γ,N B c′ : com]]η ψ) [by the semantics of sequential composition]= ([[Γ; l : T ,N B c[l/x ] : com]]η ([[Γ,N B c′[l/x ] : com]]η ψ))[x/l ]

[by the induction hypothesis]= ([[Γ; l : T ,N B c[l/x ]; c′[l/x ] : com]]η ψ)[x/l ][by the semantics of sequential composition]

Case if []i • ψ1 → ci fi

= [[Γ,N B if []i • ψi → ci fi : com]]η ψ

= (∨ i • ψi) ∧ (∧ i • ψi ⇒ [[Γ,N B ci : com]]η ψ [by the semantics of alternation]= ([[Γ; l : T ,N B (if []i • ψi → ci)[l/x ] fi : com]]η ψ)[x/l ]

[by the induction hypothesis]

Case rec Y • c end

= [[Γ,N B rec Y • c end : com]]η ψ

= [[Γ,N B µY c end : com]]η ψ [by the semantics of recursion]= ([[Γ; l : T ,N B µY c[l/x ] end : com]]η ψ)[x/l ] [by the induction hypothesis]= ([[Γ; l : T ,N B (rec Y • c end)[l/x ] : com]]η ψ)[x/l ] [by semantics of recursion]

Case var y : T • c end

[[Γ,N B var y : T • c end : com]]η ψ

= ∀ y : T ′ • [[Γ; y : T ,N B c : com]]η ψ [by the semantics local blocks]= (∀ y : T ′ • [[Γ; l : T ; y : T ,N B c[l/x ] : com]]η ψ)[x/l ] [by the induction hypothesis]= ([[Γ; l : T ,N B (var y : T • c end)[l/x ] : com]]η ψ)[x/l ][by the semantics of local blocks]

Case avar y : T ′ • c end: similar.

F.2. PROOF OF ADDITIONAL COMMAND LAWS 259

Case y .z .m(e), with y 6= x

= [[Γ; l : T ,N B y .z .m(e) : com]]η ψ)=∨N ′≤ΓN ′′• y .z isExactly N ′ ∧ [[Γ,N B (η N ′ m)((N ′)y .z , e) : com]]η ψ

[by the semantics of method call]= (∨N ′≤ΓN ′′• l .y isExactly N ′) ∧

([[Γ,N B ((η N ′ m)((N ′)l .y , e))[l/x ] : com]]η ψ)[x/l ] [by the induction hypothesis]= ([[Γ; l : T ,N B (y .z .m(e))[l/x ] : comη ψ)[x/l ] [by the semantics of method calls]

2

Proof F.2.19 Law 〈var block-val〉By induction.

Case y := e, with y 6= x

[[Γ,N B y := e : com]]η ψ

= ∀ l : T • [[Γ,N B y := e : com]]η ψ [by the hypothesis and predicate calculus]= ∀ l : T • ([[Γ; l : T ,N B (y := e)[l/x ] : com]]η ψ)[x/l ] [by Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B y := e[l/x ] : com]]η ψ)[x/l ] [by hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : com]]η ([[Γ; l : T ,N B (y := e)[l/x ] : com]]η ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; (y := e)[l/x ] : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B var l : T • l := x ; (y := e)[l/x ] end : com]]η ψ [by the semantics of local blocks]

Case y : [ψ1, ψ2], with y 6= x

[[Γ,N B y : [ψ1, ψ2] : com]]η ψ

= ∀ l : T • [[Γ; l : T ,N B y : [ψ1, ψ2] : com]]η ψ [by the hypothesis and predicate calculus]= ∀ l : T • ([[Γ; l : T ,N B y : [ψ1[l/x ], ψ2[l/x ]] : com]]ηψ)[x/l ] [by Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B y : [ψ1[l/x ], ψ2[l/x ]] : com]]ηψ)[x/l ]

[by the hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : com]]η ([[Γ; l : T ,N B y : [ψ1[l/x ], ψ2[l/x ]] : com]]ηψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; y : [ψ1[l/x ], ψ2[l/x ]] : com]]ηψ

[by the semantics of sequential composition]= [[Γ; l : T ,N B var l : T • l := x ; y : [ψ1[l/x ], ψ2[l/x ]] end : com]]ηψ

[by the semantics of local blocks]

260 APPENDIX F. PROOFS OF LAWS OF COMMANDS

Case c; c′

[[Γ,N B c; c′ : com]]η ψ

= ∀ l : T • [[Γ; l : T ,N B c; c′ : com]]η ψ [by the hypothesis and predicated calculus]= ∀ l : T • ([[Γ; l : T ,N B c[l/x ]; c′[l/x ] : com]]η ψ)[x/l ] [Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B c[l/x ]; c′[l/x ] : com]]η ψ)[x/l ] [by the hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : com]]η ([[Γ; l : T ,N B c[l/x ]; c′[l/x ] : com]]η ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; c[l/x ]; c′[l/x ] : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B var l : T • l := x ; c[l/x ]; c′[l/x ] end : com]]η ψ

[by the semantics of local blocks]

Case if []i • ψ1 → ci fi

= [[Γ,N B if []i • ψi → ci fi : com]]η ψ

= ∀ l : T • [[Γ; l : T ,N B if []i • ψi → ci fi : com]]η ψ

[by the hypothesis and predicate calculus]= ∀ l : T • ([[Γ; l : T ,N B if []i • ψi → ci [l/x ] fi : com]]η ψ)[x/l ] [by Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B (if []i • ψi → ci fi)[l/x ] : com]]η ψ)[x/l ]

[by the hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : com]]η ([[Γ; l : T ,N B (if []i • ψi → ci fi)[l/x ] : com]]η ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; (if []i • ψi → ci fi)[l/x ] : com]]η ψ

[by the semantics of sequential composition]= [[Γ; l : T ,N B var l : T • l := x ; (if []i • ψi → ci fi)[l/x ] end : com]]η ψ

[by the semantics of local blocks]

Case rec Y • c end

= [[Γ,N B rec Y • c end : com]]η ψ

= ∀ l : T • [[Γ; l : T ,N B rec Y • c end : com]]η ψ

[by the hypothesis and predicate calculus]= ∀ l : T • ([[Γ; l : T ,N B (rec Y • c end)[l/x ] : com]]η ψ)[x/l ] [by Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B (rec Y • c end)[l/x ] : com]]η ψ)[x/l ]

[by the hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : com]]η ([[Γ; l : T ,N B (rec Y • c end)[l/x ] : com]]η ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; (rec Y • c end)[l/x ] : com]]η ψ

F.2. PROOF OF ADDITIONAL COMMAND LAWS 261

[by the semantics of sequential composition]= [[Γ; l : T ,N B var l : T • l := x ; (rec Y • c end)[l/x ] end : com]]η ψ

[by the semantics of local blocks]

Case var y : T ′ • c end

[[Γ,N B var y : T ′ • c end : com]]η ψ

= ∀ l : T • [[Γ; l : T ,N B var y : T ′ • c end : com]]η ψ

[by the hypothesis and predicate calculus]= ∀ l : T • ([[Γ; l : T ,N B (var y : T ′ • c end)[l/x ] : com]]η ψ)[x/l ] [by Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B (var y : T ′ • c end)[l/x ] : com]]η ψ)[x/l ]

[by the hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : com]]η ([[Γ; l : T ,N B (var y : T ′ • c end)[l/x ] : com]]η ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; (var y : T ′ • c end)[l/x ] : com]]η ψ)

[by the semantics of sequential composition]= [[Γ; N B var l : T • l := x ; (var y : T ′ • c end)[l/x ] end : com]]η ψ)

[by the semantics of local blocks]

Case avar y : T ′ • c end: similar.

Case y .z .m(e), with e as a value argument.

= [[Γ; l : T ,N B y .z .m(e) : com]]η ψ

= ∀ l : T • [[Γ; l : T ,N B y .z .m(e) : com]]η ψ [by the hypothesis and predicate calculus]= ∀ l : T • ([[Γ; l : T ,N B (y .z .m(e)[l/x ]) : comη ψ)[x/l ] [by Lemma 15]= ∀ l : T • x 6= error ∧ ([[Γ; l : T ,N B (y .z .m(e))[l/x ] : comη ψ)[x/l ] [by the hypothesis]= ∀ l : T • [[Γ; l : T ,N B l := x : comη ([[Γ; l : T ,N B (y .z .m(e))[l/x ] : comη ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := x ; (y .z .m(e))[l/x ] : comη ψ)

[by the semantics of sequential composition]= [[Γ,N B var l := x ; (y .z .m(e))[l/x ] end : comη ψ) [by the semantics of local blocks]

2

Proof F.2.20 Law 〈var block-res〉By induction.

Case x := e

262 APPENDIX F. PROOFS OF LAWS OF COMMANDS

[[Γ,N B x := e : com]]η ψ

= e 6= error ∧ ψ[e/x ] [by the semantics of assignment]= ∀ l : T • e 6= error ∧ ψ[e/x ] [by predicate calculus]= ∀ l : T • e[l/x ] 6= error ∧ ψ[e/x ][l/x ] [by a property of substitution and hypothesis]= ∀ l : T • e[l/x ] 6= error ∧ ψ[e[l/x ]/x ] [by a property of substitution]= ∀ l : T • e[l/x ] 6= error ∧ e[l/x ] 6= error ∧ ψ[e[l/x ]/x ] [by predicate calculus]= ∀ l : T • e[l/x ] 6= error ∧ e[l/x ] 6= error ∧ ψ[l/x ][e[l/x ]/l ] [by a property of substitution]= ∀ l : T • e[l/x ] 6= error ∧ (e[l/x ] 6= error ∧ ψ[l/x ][e[l/x ]/l ]) [by predicate calculus]= ∀ l : T • e[l/x ] 6= error ∧ (l 6= error ∧ ψ[l/x ])e[l/x ]/l ] [by a property of substitution]= ∀ l : T • e[l/x ] 6= error ∧ ([[Γ; l : T B x := l : com]]η ψ)e[l/x ]/l ]

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T B l := e[l/x ] : com]]η ([[Γ; l : T B x := l : com]]η ψ)e[l/x ]/l ]

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l := e[l/x ]; x := l : com]]η ψ)

[by the semantics of sequential composition]= ∀ l : T • [[Γ; l : T ,N B (x := e)[l/x ]; x := l : com]]η ψ) [by a property of substitution]= [[Γ,N B var l : T • (x := e)[l/x ]; x := l end : com]]η ψ [by the semantics of local blocks]

Case x : [ψ1, ψ2]

First, we assume that x does not get error in the specification statement.

[[Γ,N B x : [ψ1, ψ2] : com]]η ψ

= ψ1 ∧ (∀ x : T • ψ2 ⇒ ψ) [by the semantics of specification statement]= ∀ l : T • ψ1 ∧ (∀ x : T • ψ2 ⇒ ψ) [by predicate calculus]= ∀ l : T • ψ1 ∧ (∀ l : T • ψ2 ⇒ (x 6= error ∧ ψ)) [by assumption]= ∀ l : T • ψ1[l/x ] ∧ (∀ l : T • ψ2[l/x ] ⇒ (l 6= error ∧ ψ[l/x ])) [by predicate calculus]= ∀ l : T • [[Γ; l : T ,N B l : [ψ1[l/x ], ψ2[l/x ]] : com]]η (l 6= error ∧ ψ[l/x ])

[by the semantics of specification statement]= ∀ l : T • [[Γ; l : T ,N B l : [ψ1[l/x ], ψ2[l/x ]] : com]]η ([[Γ; l : T ,N B x := l : com]]η ψ)

[by the semantics of assignment]= ∀ l : T • [[Γ; l : T ,N B l : [ψ1[l/x ], ψ2[l/x ]]; x := l : com]]η ψ

[by the semantics of sequential composition]= [[Γ,N B var l : T • l : [ψ1[l/x ], ψ2[l/x ]]; x := l : com]]η ψ

[by the semantics of local blocks]

The case in which x gets error in the specification statement result in program abortion. As lreplaces x , in the specification statement, and l is assigned to x , if l get error the program aborts.

F.2. PROOF OF ADDITIONAL COMMAND LAWS 263

The other cases are consequence of the induction hypothesis.2

Proof F.2.21 Law 〈pcom elimination-val〉

[[Γ,N B (val vl : T • c)(x ) : com]]η ψ

= [[Γ,N B var l : T • l := x ; c[l/vl ] end : com]]η ψ [by a syntactic transformation]

2

Proof F.2.22 Law 〈pcom elimination-res〉

[[Γ,N B (res vl : T • c)(x ) : com]]η ψ

= [[Γ,N B var l : T • c[l/vl ]; x := l end : com]]η ψ [by a syntactic transformation]

2

264 APPENDIX F. PROOFS OF LAWS OF COMMANDS

Appendix G

Proof of Laws of Classes

In this appendix we present the proofs of the programming laws related to classes. We concentrateon proof in the dynamic semantics of rool. So, we assume programs in the proof to be well-typed.Proofs in the static semantics of rool would involved verifying against the grammar of rool andtyping rules.

G.1 Normal Form Laws

G.1.1 Class Declaration

Lemma 16 Consider a class N , and typing environments Γ and Γ′ such that N ∈ Γ.cnames andΓ′.cnames = Γ.cnames \{N }. Let η and η′ be environments compatible with Γ and Γ′, respectively.If N is not used in Γ in anywhere, except in cnames, nor in η, then

[[Γ,A B c : com]]η ψ = [[Γ′,A B c : com]]η′ ψ

Proof Straightforward induction. Here, we consider only the case of a call to a method m that isnot declared by N . A call to a method of N is not well-typed.

Case le.m(e), with m 6∈ dom (Γ.meth N )

[[Γ,D B le.m(e) : com]]η ψ

= (∨N ′≤ΓC • le isExactly N ′ ∧ [[Γ,D B (η N ′ m)((N ′) le, e) : com]]η ψ)

[by the semantics of method call]= (∨N ′≤Γ′C

• le isExactly N ′ ∧ [[Γ′,D B (η N ′ m)((N ′) le, e) : com]]η′ ψ)

[by the assumption]= [[Γ′,D B le.m(e) : com]]η′ ψ [by the semantics of method calls]

2

266 APPENDIX G. PROOF OF LAWS OF CLASSES

Proof G.1.1 Law 〈class elimination〉

[[∅; x : T B cdscd1 • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η′ ψ [by Lemma 16]= [[∅; x : T B cds • c : program]]η′ ψ [by the semantics of programs]

The environments Γ, Γ′, η, and η′ are as in Lemma 16. The provisos of the law 〈class elimination〉guarantee that the programs are well-typed.

2

G.1.2 Attribute Declaration

Proof G.1.2 Law 〈attribute elimination〉

Law 〈attribute elimination〉 can be proved by applying law 〈private attribute-coupling invariant〉;the attribute a should be regarded as the abstract attribute, there should be no concrete attributes,and the coupling invariant should be true.

2

Lemma 17 Let Γ and Γ′ be typing environments such that Γ.vis N a = prot andΓ′.vis N = Γ.vis N ⊕ {a 7→ pub}, but are otherwise identical.

[[Γ,N B c : com]]η ψ = [[Γ′,N B c : com]]η ψ

Proof By induction. Since the semantics is defined with basis on the extended typing system,which does not enforce the visibility constraints, the difference between Γ and Γ′ is irrelevant.

2

Proof G.1.3 Law 〈change visibility: from protected to public〉

[[∅; x : T B class C extends D prot a : T ; ads ops end cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 17 and the law proviso]= [[∅; x : T B class C extends D pub a : T ; ads ops end cds • c : program]]η ψ

[by the semantics of programs]

2

G.1. NORMAL FORM LAWS 267

Lemma 18 Let Γ and Γ′ be typing environments such that Γ.vis N a = pri andΓ′.vis N = Γ.vis N ⊕ {a 7→ pub}, but are otherwise identical.

[[Γ,N B c : com]]η ψ = [[Γ′,N B c : com]]η ψ

Proof By induction. Since the semantics is defined with basis on the extended typing system,which does not enforce the visibility constraints, the difference between Γ and Γ′ is irrelevant.

2

Proof G.1.4 Law 〈change visibility: from private to public〉

[[∅; x : T B class C extends D pri a : T ; ads ops end cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 18 and the law proviso]= [[∅; x : T B class C extends D pub a : T ; ads ops end cds • c : program]]η ψ

[by the semantics of programs]

2

Lemma 19 Let Γ and Γ′ be typing environments such that Γ′.attr N = Γ.attr N ⊕ {a 7→ T},but are otherwise identical. For a type T ′′, such that T ′′ ≤Γ T, if every non-assignable occurrenceof a in expressions in η is cast with type T ′′, every expression assigned to a in the environment η

has type T ′′, and every use of a as result argument in η is for a formal parameter of type T ′′, suchthat T ′′ ≤Γ T, and T ≤Γ T ′, then

[[Γ,N B c : com]]η ψ = [[Γ′,N B c : com]]η ψ

Proof By induction. Here we present the cases of assignment and the application of a parameterisedcommand with a result parameter to the argument a.

Case a := e

[[Γ,N B a := e : com]]η ψ

= e 6= error ∧ ψ[e/a] [by the semantics of assignment]= [[Γ′,N B a := e : com]]η ψ [by the semantics of assignment and a := e is well-typed]

The assignment a := e is well-type because the type of a is changed to T and the type of e isT ′′, such that T ′′ ≤Γ T , according to the hypothesis.

268 APPENDIX G. PROOF OF LAWS OF CLASSES

Case (res x : T • c)(a)

[[Γ,N B (res x : T • c)(a) : com]]η ψ

= [[Γ,N B var l : T • l := a; c[l/x ]; a := l end : com]]η ψ [by a syntactic transformation]= ∀ l : T • [[Γ; l : T ,N B l := a; c[l/x ]; a := l : com]]η ψ [by the semantics of local blocks]= [[Γ′,N B var l : T • l := a; c[l/x ]; a := l end : com]]η ψ

[by the semantics of local blocks and parameterised command application to a is well-type]= [[Γ′,N B (res x : T • c)(a) : com]]η ψ [by a syntactic transformation]

The type of a is changed from T ′ to T and every use of a is for a corresponding formal param-eter of type T or any subtype of T , according the hypothesis. Consequently, the parameterisedcommand application is well-typed.

2

Proof G.1.5 Law 〈change attribute type〉

[[∅; x : T1 B class C extends D pub a : T ′; ads ops end cds • c : program]] ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 19]= [[∅; x : T1 B class C extends D pub a : T ; ads ops end cds • c : program]] ψ

[by the semantics of programs]

The provisos of the law 〈change attribute type〉 guarantee that the program is well-formed andthe typing environments Γ and Γ′ are as in the hypothesis of Lemma 19.

2

Lemma 20 Let Γ and Γ′ be typing environments such that

Γ′.attr B = Γ.attr B ⊕ {a 7→ T}

and

Γ′.vis B = Γ.vis B ⊕ {a 7→ pub}

but are otherwise identical. If a 6∈ dom(Γ.attr D) for any class D such that D ≤Γ B, D �Γ C,and C ≤Γ B, then

[[Γ,N B c : com]]η ψ = [[Γ′,N B c : com]]η ψ

G.1. NORMAL FORM LAWS 269

Proof By induction. The environment Γ′ is relevant when dealing with accesses to the attribute a.For instance, when assigning to a. We consider this assignment through an expression of type Cor of any subtype of C .

Case le.a := e, with le : M such that M ≤Γ C

[[Γ,N B le.a := e : com]]η ψ

= [[Γ,N B le := (le; a : e) : com]]η ψ [by a syntactic transformation]= (le; a : e) 6= error ∧ ψ[(le; a : e)/le] [by the semantics of assignment]= [[Γ′,N B le := (le; a : e) : com]]η ψ [by the semantics of assignment and the hypothesis]= [[Γ′,N B le.a := e : com]]η ψ [by a syntactic transformation]

The expression le.a := e is well-typed because the attribute a is still visible inside C or any ofits subclasses.

2

Lemma 21

[[∅; x : T1 B class B extends A ads ops end

class C extends B pub a : T ; ads ′ ops ′ end cds • c : program]] ψ

= [[∅; x : T1 B class B extends A pub a : T ; ads ops end

class C extends B ads ′ ops ′ end cds • c : program]] ψ

Proof

[[∅; x : T1 B class B extends A ads ops end

class C extends B pub a : T ; ads ′ ops ′ end cds • c : program]] ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 20][[∅; x : T1 B class B extends A pub a : T ; ads ops end

class C extends B ads ′ ops ′ end cds • c : program]] ψ [by the semantics of programs]

The proviso of the law, from left to right, guarantees that the program is well-formed and thetyping environments Γ and Γ′ are as in the hypothesis of Lemma 20.

2

Lemma 22 Let Γ and Γ′ be typing environments such that

Γ′.attr B = Γ.attr B \ {a 7→ T},

270 APPENDIX G. PROOF OF LAWS OF CLASSES

Γ′.vis B = Γ.vis B \ {a 7→ pub},

and

Γ′.attr C = Γ.attr C ⊕ {a 7→ T}, Γ′.vis C = Γ.vis C ⊕ {a 7→ pub},

but are otherwise identical. If le.a does not appear in η, for any expression le of type D, such thatD ≤Γ B, D �Γ C, and C ≤Γ B, then

[[Γ,N B c : com]]η ψ = [[Γ′,N B c : com]]η ψ

Proof By induction.

Proof By induction. The environment Γ′ is relevant when dealing with accesses to the attribute a.For instance, when assigning to a. We consider this assignment through an expression of type Cor of any subtype of C .

Case le.a := e, with le : M such that M ≤Γ C

[[Γ,N B le.a := e : com]]η ψ

= [[Γ,N B le := (le; a : e) : com]]η ψ [by a syntactic transformation]= (le; a : e) 6= error ∧ ψ[(le; a : e)/le] [by the semantics of assignment]= [[Γ′,N B le := (le; a : e) : com]]η ψ [by the semantics of assignment and the hypothesis]= [[Γ′,N B le.a := e : com]]η ψ [by a syntactic transformation]

2

Lemma 23

[[∅; x : T1 B class B extends A pub a : T ; ads ops end

class C extends B ads ′ ops ′ end cds • c : program]] ψ

= [[∅; x : T1 B class B extends A ads ops end

class C extends B pub a : T ; ads ′ ops ′ end cds • c : program]] ψ

Proof

[[∅; x : T1 B class B extends A pub a : T ; ads ops end

class C extends B ads ′ ops ′ end cds • c : program]] ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 22]

G.1. NORMAL FORM LAWS 271

= [[∅; x : T1 B class B extends A ads ops end

class C extends B pub a : T ; ads ′ ops ′ end cds • c : program]] ψ

[by the semantics of programs]

2

Proof G.1.6 Law 〈move attribute to superclass〉The proof of this law is given by Lemmas 21 and 23.

2

G.1.3 Method Declaration

Lemma 24 Consider and typing environment Γ, and let η and η′ be environments such that

η B m = (vres me : B ; Γ.meth B m • c)},

η C m = (vres me : C ; Γ.meth C m • c)}, and

η′ C = η C ⊕ {m 7→ (vres me : C ; Γ.meth C m • super.m(α(pds)))},

with C ≤Γ B, and m 6∈ (dom(Γ.meth C ) \ dom(Γ.meth B)). For all other classes and methods, η

and η′ are equal. Then,

[[Γ,N B c : com]]η ψ = [[Γ,N B c : com]]η′ ψ

Proof By induction. The case of calls to the method m is relevant as the definition for this methodis being modified. We assume that the type of le has exact type C . The proof for the other casesfollows from an argument that is similar.

Case le.m(e)

[[Γ,D B le.m(e) : com]]η ψ

= (∨N ′≤ΓC • le isExactly N ′ ∧ [[Γ,D B (η N ′ m) ((N ′)le, e) : com]]η ψ

[by the semantics of method call]

Here, as said above, we concentrate on the case in which le is exactly an object of type C . Thisrequires that le is not null or error.

= le 6= null ∧ le 6= error ∧ [[Γ,D B (η C m) ((C )le, e) : com]]η ψ

= [[Γ,D B (η C m) ((C )le, e) : com]]η ψ

272 APPENDIX G. PROOF OF LAWS OF CLASSES

By the construction of the environment, we know that η C m contains a modified version of m.

[[Γ,D B (η C m) ((C )le, e) : com]]η ψ

= [[Γ,D B µ(vres me : C ; pds • meI Γ D m c)((C )le, e) : com]]η ψ [by the definition of η]= [[Γ,D B (vres me : C ; pds • meI Γ D m c)((C )le, e) : com]]η ψ

[by the unfold property of fixed points]= [[Γ,D B var me : C •

me := (C )le; (pds • meI Γ D m c)(e); (C )le := meend : com]]η ψ [by a syntactic transformation]

= [[Γ,D B (pds • meI Γ D m c)[le/me](e) : com]]η ψ [by the semantics]= [[Γ,D B (pds • c)[le/me](e) : com]]η ψ [by the definition of meI ]= [[Γ,D B super.m[le/me](e) : com]]η ψ [by a syntactic transformation]= [[Γ,D B super.m(e) : com]]η ψ [me is not free in super.m]

2

Proof G.1.7 Law 〈introduce method redefinition〉

[[∅; x : T B class B extends A ads meth m = (pds • c) ops end

class C extends B ads ′ops ′ end cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ,main B c : com]]η′ ψ [by Lemma 24]= [[∅; x : T B class B extends A ads meth m = (pds • c) ops end

class C extends B ads ′ meth m = (pds • super.m(αpds)) ops ′ end

cds • c : program]]η′ ψ

[by the semantics of programs]

2

Lemma 25 Consider a typing environment Γ, and environments η and η′ such that

η B m = (vres me : B ; pds • meI Γ B m b)

and

η C m = (vres me : C ; pds • meI Γ C m b ′)

G.1. NORMAL FORM LAWS 273

Moreover,

η′ B m = (vres me : B ; pds • if ¬(me is C ) → meI Γ B m b[] me is C → meI Γ B m b′

fi)

and

η′ C m = (vres me : C ; pds • if ¬(me is C ) → meI Γ C m b[] me is C → meI Γ C m b ′

fi)

For all other classes and methods, η and η′ are equal. If B, C , b, and b′ are as in law〈move redefined method to superclass〉, then, for all classes N ,

[[Γ,N B c : com]]η ψ = [[Γ,N B c : com]]η′ ψ

Proof By induction. The different environments potentially affect the semantics of method calls.If the method called is not m, then the semantics recorded in η and η′ are the same, so the resultis trivial. The case we consider below is that of a call to m.Case le.m(e)

[[Γ,N B le.m(e) : com]]η ψ

=∨N ′≤ΓN ′′• le isExactly N ′′ ∧[[Γ,N B (η N ′ m) ((N ′)le, e) : com]]η ψ [semantics]

In this definition, le isExactly N ′′ holds for exactly one subclass N ′′ of the type N of le. If N ′′

is B or C , then η and η′ record different semantics for m. Otherwise, the semantics are the same,and the result is trivial.

If the exact type of le is B , we can proceed as follows.

∨N ′≤ΓN ′′• le isExactly N ′′ ∧[[Γ,N B (η N ′ m ′) ((N ′)le, e) : com]]η ψ

= [[Γ,N B (η B m) ((B)le, e) : com]]η′ ψ [assumption]

= [[Γ,N B (vres me : B ; pds • meI Γ B m b)((B)le, e) : com]]η′ ψ

[hypothesis]

= [[Γ,N B var me : B •me := (B)le; (pds • meI Γ B m b)(e); (B)le := me

end : com]]η′ ψ

[semantics]

274 APPENDIX G. PROOF OF LAWS OF CLASSES

= [[Γ,N B var me : B •me := (B)le;if ¬(me is C ) → (pds • meI Γ B m b)(e)[] me is C → (pds • meI Γ B m b ′)(e)fi;(B)le := me

end : com]]η′ ψ

[¬(me is C ) holds after me := (B)le]

= [[Γ,N B var me : B •me := (B)le;(pds • if ¬(me is C ) → meI Γ B m b

[] me is C → meI Γ B m b ′

fi)(e);(B)le := me

end : com]]η′ ψ

[me is not declared in pds]

= [[Γ,N B (vres me : B ; pds •if ¬(me is C ) → meI Γ B m b[] me is C → meI Γ B m b′

fi)(e) : com]]η′ ψ

[semantics]

= [[Γ,N B (η′ B m) ((B)le, e) : com]]η′ ψ [hypothesis]

= [[Γ,N B le.m(e) : com]]η′ ψ [assumption and semantics]

Some of the above steps are justified by properties of commands. They are formalised by standardcommand laws.

If the exact type of le is C , the proof is similar.2

Proof G.1.8 Law 〈move redefined method to superclass〉

[[∅; x : T Bclass B extends A

adsmeth m = (pds • b); ops

end

class C extends Bads ′

meth m = (pds • b ′)ops ′

G.1. NORMAL FORM LAWS 275

end

cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ,main B c : com]]η′ ψ [by Lemma 25][[∅; x : T B

class B extends Aadsmeth m = (pds •

if ¬ (self is C ) → b[] self is C → b′

fi);ops

end

class C extends Bads ′

ops ′

end

cds • c : program]]η ψ

[by the semantics of programs]

The semantics of super is given by a copy-rule, but, since super is not present in b ′ andops ′, the different definitions of m do not affect the result of applying such a rule. The typingenvironments defined by the programs are the same, since the methods available in the classes Band C are the same in both of then. The provisos guarantee that they are well-typed.

The environments η and η′ defined by the programs in law 〈move redefined method to superclass〉are as in Lemma 25. The only final detail is that, in Lemma 25, we did not consider the fact that,if a subclass of C does not redefine m, then its semantics in the environment is also affected bythe change. This generalisation of Lemma 25 is rather lengthier, but its proof is similar to thatpresented above.

2

Lemma 26 Let Γ and Γ′ be typing environments such that Γ′.meth N = Γ.meth N \ {m 7→ pds ′},but are otherwise identical. Consider also environments η and η′ such thatη′ N = η N \ {m 7→ (vres me : N ; pds ′ • meI Γ′ N m c′)}. If m is not used in η, then

[[Γ,N B (η N ′ m ′) ((N ′)le, e) : com]]η ψ = [[Γ′,N B (η′ N ′ m ′) ((N ′)le, e) : com]]η ψ

Proof By induction. The environments Γ′ and η′ are relevant when dealing with method calls. Inthis case, the called method cannot call the method that is being removed.

276 APPENDIX G. PROOF OF LAWS OF CLASSES

Case le.m ′(e), with m ′ 6= m

[[Γ,N B le.m ′(e) : com]]η ψ

= (∨N ′≤ΓN ′′• le isExactly N ′′ ∧ [[Γ,N B (η N ′ m ′) ((N ′)le, e) : com]]η ψ

[by the semantics of method call]= (∨N ′≤Γ′N ′′• le isExactly N ′′ ∧ [[Γ′,N B (η′ N ′ m ′) ((N ′)le, e) : com]]η′ ψ

[by the hypothesis]= [[Γ′,N B le.m ′(e) : com]]η′ ψ [by the semantics of method call]

2

Proof G.1.9 Law 〈method elimination〉

[[∅; x : T B class C extends D ads; meth m = pc end; ops end cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η′ ψ [by Lemma 26]= [[∅; x : T B class C extends D ads; ops end cds • c : program]]η ψ

[by the semantics of programs]

The provisos of the law 〈method elimination〉 guarantee that the program is well-formed andthe environments η and η′ are as in the hypothesis of Lemma 26.

2

Lemma 27 Consider that B and C are classes such that C ≤Γ B, and let Γ, Γ′, η, and η′ areenvironments such that

η C m = (vres me : C ; pds • meI Γ C m c)},

Γ′.meth B = Γ.meth B ⊕ {m 7→ pds},

and

η′ B = η B ⊕ {m 7→ (vres me : B ; pds • c)},

but are otherwise identical. If

m 6∈ dom(Γ.meth A), for any A, such that B ≤Γ A,m 6∈ dom(Γ.meth B),Γ.meth C m = Γ.meth D m, for any D, such that D ≤Γ B and D �Γ C ,

and

G.1. NORMAL FORM LAWS 277

m 6∈ dom(Γ′.meth C \ Γ′.meth B),

then

[[Γ,N B c : com]]η ψ = [[Γ′,N B c : com]]η′ ψ

Proof By induction.

The environments η and η′ are relevant when dealing with method calls. They potentially affectthe semantics of method calls. If the method called is not m, then the semantics recorded in η andη′ are the same; thus the result is trivial. We consider the case of a call to m. The other cases arestraightforward.

Case le.m(e)

[[Γ,N B le.m(e) : com]]η ψ

= (∨N ′≤ΓN ′′• le isExactly N ′′ ∧ [[Γ,N B (η N ′ m) ((N ′)le, e) : com]]η ψ

[by the semantics of method call]= (∨N ′≤Γ′N ′′• le isExactly N ′′ ∧ [[Γ′,N B (η′ N ′ m) ((N ′)le, e) : com]]η′ ψ [by hypothesis]

= [[Γ′,N B le.m(e) : com]]η′ ψ [by the semantics of method call]

2

Proof G.1.10 Law 〈move original method to superclass〉

= [[∅; x : T B class B extends A ads ops end

class C extends B ads ′ meth m = (pds • c) ops ′ end

cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η′ ψ [by Lemma 27]= [[∅; x : T B class B extends A ads meth m = (pds • c) ops end

class C extends B ads ′ops ′ end

cds • c : program]]η ψ [by the semantics of programs]

Since super is not present in (pds • c) and m is not declared by B or any superclass of B , wecan move the definition of m to the superclass. The environments Γ, Γ′, η, and η′ are as defined inLemma 27. The provisos guarantee that the environments Γ and Γ′ are well-typed.

2

278 APPENDIX G. PROOF OF LAWS OF CLASSES

G.1.4 Parameter type

Lemma 28 Let Γ and Γ′ be typing environments such that (val x : T ′; pds) ∈ Γ.meth C m, and(val x : T ; pds) ∈ Γ′.meth C m, but are otherwise identical, where T ≤Γ T ′. For a type T ′′, suchthat T ′′ ≤Γ T, if every non-assignable occurrence of x in expressions in η C m is cast with T ′′,every actual parameter associated to x in η is of type T ′′, every expression assigned to x in theη C m has type T ′′, and every use of x as result argument in η C m is for a formal parameter oftype T ′′, then

[[Γ,C B c : com]]η ψ = [[Γ′,C B c : com]]η ψ

Proof By induction. Here we present the cases of application of a parameterised command with avalue parameter to the argument a. As we interested in changing the type of just one parameter,we ignore other ones.

Case (val x : T • b)(a), with a of type T or of any subtype of T

[[Γ,C B (val x : T ′ • b)(a) : com]]η ψ

= [[Γ,C B var l : T ′ • l := a; b[l/x ] end : com]]η ψ [by a syntactic transformation]= ∀ l : T ′ • [[Γ; l : T ′,C B l := a; b[l/x ] : com]]η ψ [by the semantics of local blocks]= ∀ l : T • [[Γ′; l : T ,C B l := a; b[l/x ] : com]]η ψ

[by the hypothesis]= [[Γ′,C B var l : T • l := a; b[l/x ] end : com]]η ψ [by the semantics of local blocks]= [[Γ′,C B (val x : T • b)(a) : com]]η ψ [by a syntactic transformation]

The semantics of a parameterised command does not depend on the type of its parameters, buton it being well-typed. Therefore, the main risk in the change of a parameter type is to rendermethod calls ill-typed. If this is not the case, then the semantics of the calls depend on the valueof the arguments. These are not changed in Lemma 28.

2

Proof G.1.11 Law 〈change value parameter type〉

[[∅; x : T1 B class C extends D ads meth = (val x : T ′; pds • b) ops end

cds • c : program]] ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 28]= [[∅; x : T1 B class C extends D ads meth = (val x : T ; pds • b) ops end

cds • c : program]] ψ [by the semantics of programs]

G.1. NORMAL FORM LAWS 279

The environments Γ and Γ′ are as in Lemma 28. The provisos of the law guarantee that theprograms are well-typed.

2

Lemma 29 Let Γ and Γ′ be typing environments such that (res x : T ; pds) ∈ Γ.meth C m, and(res x : T ′; pds) ∈ Γ′.meth C m, but are otherwise identical, where T ≤Γ T ′. For a type T ′′, suchthat T ′′ ≤Γ T, if every non-assignable occurrence of x in expressions in η C m is cast with T ′′,and every actual parameter associated to x in η is of type T ′ or a any supertype of T ′, then

[[Γ,C B c : com]]η ψ = [[Γ′,C B c : com]]η ψ

Proof By induction. Here we present the case of an application of a parameterised command witha result parameter to the argument a.

Case (res x : T • b)(le), with le of type T ′ or of any supertype of T ′.

[[Γ,C B (res x : T • b)(a) : com]]η ψ

= [[Γ,C B var l : T • b[l/x ]; le := l end : com]]η ψ [by a syntactic transformation]= ∀ l : T • [[Γ; l : T ,C B b[l/x ]; le := l : com]]η ψ [by the semantics of local blocks]= ∀ l : T ′ • [[Γ′; l : T ′,C B b[l/x ]; le := l : com]]η ψ [by the hypothesis]= [[Γ′,C B var l : T ′ • b[l/x ]; le := l end : com]]η ψ [by the semantics of local blocks]= [[Γ′,C B (res x : T ′ • b)(le) : com]]η ψ [by a syntactic transformation]

The semantics of a parameterised command does not depend on the type of its parameters, buton it being well-typed. Therefore, the main risk in the change of a parameter type is to rendermethod calls ill-typed. If this is not the case, then the semantics of the calls depend on the valueof the arguments. These are not changed in Lemma 29.

2

Proof G.1.12 Law 〈change result parameter type〉

[[∅; x : T1 B class C extends D ads meth = (res x : T ; pds • b) ops end

cds • c : program]] ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 29]= [[∅; x : T1 B class C extends D ads meth = (res x : T ′; pds • b) ops end

cds • c : program]] ψ [by the semantics of programs]

280 APPENDIX G. PROOF OF LAWS OF CLASSES

The environments Γ and Γ′ are as in Lemma 29. The provisos guarantee that the programs arewell-typed.

2

G.1.5 Method calls

Proof G.1.13 Law 〈eliminate super〉

Let Γ and η be environments such that

Γ.supcls C = B ,

and

η B m = (vres m : B ; pds • meI Γ B m c),

then

[[Γ,C B super.m(e) : com]]η ψ

= [[Γ,C B (pds • c)(e) : com]]η ψ [by a syntactic transformation]

The proof of Law 〈eliminate super〉 is a direct consequence of the semantics of super, which isgiven by the copy rule. Dynamic binding does not apply in this case. Arguments to which super.mis applied remain the same, they are not touched by this law. As required in the law proviso, super

and private attributes do not appear of the superclass of C do not appear in the parameterisedcommand that defines the method m.

2

For the proofs of Lemmas 30, 31, and 32, we assume that the type of le is C . In the law〈method call elimination〉; it can be any of its subclasses, but the proof is the same.

Lemma 30 If the method m is not redefined in any subclass of C , then

∨N ′≤ΓC • le isExactly N ′ ∧ [[Γ,A B (η N ′ m) ((N ′)le, e) : com]]η) =

∨N ′≤ΓC • le isExactly N ′ ∧ [[Γ,A B (η C m) ((C )le, e) : com]]η)

Proof By the construction the environment η.

2

G.1. NORMAL FORM LAWS 281

Lemma 31 For an environment η and a method m in this environment, we have that

[[Γ,A B (η C m) ((C )le, e) : com]]η ψ

= [[Γ,A B µ(vres me : C ; pds • meI Γ,A m c)((C )le, e) : com]]η ψ

Proof By the definition of the environment η, η C m contains the method m modified with theextra value-result parameter me.

Lemma 32

[[Γ,A B µ(vres me : C ; pds • meI Γ,A m c)((C )le, e) : com]]η ψ

= [[Γ,A B (pds • c)[le/me](e) : com]]η ψ

Proof

[[Γ,A B µ(vres me : C ; pds • meI Γ,A m c)((C )le, e) : com]]η ψ

= [[Γ,A B (vres me : C ; pds • meI Γ,A m c)((C )le, e) : com]]η ψ

[by a property of fixed points]= [[Γ,A B var me : C •

me := (C )le; (pds • meIΓ,A m c)(e); (C )le := meend : com]]η ψ

[by a syntactic transformation]= [[Γ,A B (pds • meIΓ,A m c)[le/me](e) : com]]η ψ [by the semantics ]= [[Γ,A B (pds • c)[le/self ](e) : com]]η ψ [by the definition of meI ]

2

Proof G.1.14 Law 〈method call elimination〉

[[Γ,A B le.m(e) : com]]η ψ

= (∨N ′≤ΓC • le isExactly N ′ ∧ [[Γ,A B (η N ′ m)((N ′) le, e) : com]]η ψ)

[by the semantics of method call]= le 6= null ∧ le 6= error ∧ [[Γ,A B (η C m) ((C )le, e) : com]]η ψ

[by Lemma 30 and the semantics of isExactly]= le 6= null ∧ le 6= error ∧ [[Γ,A B µ(vres me : C ; pds • meI Γ,A m c)((C )le, e) : com]]η ψ

[by Lemma 31]= le 6= null ∧ le 6= error ∧ [[Γ,A B (pds • c)[le/self ](e) : com]]η ψ

[by Lemma 32]

282 APPENDIX G. PROOF OF LAWS OF CLASSES

= le 6= null ∧ le 6= error ∧ (true ⇒ ([[Γ,A B (pds • c)[le/self ](e) : com]]η ψ))[by the predicate calculus]

= [[Γ,A B : [le 6= null ∧ le 6= error, true] : com]]η([[Γ,A B (pds • c)[le/self ](e) : com]]η ψ)[by the semantics of specification statement]

= [[Γ,A B : [le 6= null ∧ le 6= error, true]; (pds • c)[le/self ](e) : com]]η ψ

[by the semantics of sequential composition]= [[Γ,A B {le 6= null ∧ le 6= error}; (pds • c)[le/self ](e) : com]]η ψ

[by the definition of assumption]

2

G.1.6 Casts

Proof G.1.15 Law 〈eliminate cast of method call〉If cds,A B e : B , C ≤Γ B , and m ∈ dom Γ.meth B or m ∈ dom Γ.meth N , such that B ≤Γ N ,then

First, we assume that e 6∈ {null, error} and the object it holds is of type C or of any subtypeof C .

[[Γ,A B ((C )e).m(e ′) : com]]η ψ

= (∨N ′≤ΓN ′′• ((C )e) isExactly N ′ ∧ [[Γ,D B (η N ′ m) ((N ′)((C )e), e ′) : com]]η ψ

[by the semantics of method call]= ((C )e) isExactly C ∧ [[Γ,A B (η C m)((C )((C )e), e ′) : com]]η

[by the semantics of casts, isExactly, and predicate calculus]= true ∧ (((C )e) isExactly C ∧ [[Γ,A B (η C m)((C )((C )e), e ′) : com]]η)

[by predicate calculus]= (C )e is C ∧ (((C )e) isExactly C ∧ [[Γ,A B (η C m)((C )((C )e), e ′) : com]]η)

[by the semantics of is and assumption]= e is C ∧ (e isExactly C ∧ [[Γ,A B (η C m)((C )e, e ′) : com]]η)

[by the semantics of casts ]= e is C ∧ ([[Γ,A B e.m(e ′) : com]]η ψ) [by the semantics of method call]= e is C ∧ true ⇒ ([[Γ,A B e.m(e ′) : com]]η ψ) [by predicate calculus]= [[Γ,A B : [e is C , true] : com]]η ([[Γ,A B e.m(e ′) : com]]η ψ)

[by the semantics of the specification statement]= [[Γ,A B : [e is C , true]; e.m(e ′) : com]]η ψ

[by the semantics of sequential composition]= [[Γ,A B {e is C}; e.m(e ′) : com]]η ψ [by the definition of assumption]

The case in which e ∈ {null, error} or e holds an object whose type is not C or a subtype

G.1. NORMAL FORM LAWS 283

of C is equivalent to program abortion, because if the value of a cast expression does not have therequired type, it evaluation results in error, by the semantics of casts, and command ((C )e).m(e ′)aborts. If the value of e is null, then the value of the boolean expression e is C is false. In thiscase, the assumption {e is C} behaves like abort. If the value of e is not null or error, but it is anobject that is not of type C or of any subtype of C , the test e is C also gives false. Consequently,the assumption {e is C} is equivalent to abort.

2

Proof G.1.16 Law 〈introduce trivial cast in expressions〉If cds,A B e : C , then

[[Γ,A B e : com]]η ψ

= [[Γ,A B (C )e : com]]η ψ [by the hypothesis and the semantics of casts]

2

Proof G.1.17 Law 〈eliminate cast of expressions〉If cds,A B le : B , e : B ′, C ≤Γ B ′ and B ′ ≤Γ B , then

First, we assume that e 6∈ {null, error} and the object it holds is of type C or of any subtypeof C .

[[Γ,A B le := (C )e : com]]η ψ

= (C )e 6= error ∧ ψ[(C )e/le] [by the semantics of assignment]= true ∧ (C )e 6= error ∧ ψ[(C )e/le] [by predicate calculus]= (C )e is C ∧ (C )e 6= error ∧ ψ[(C )e/le] [by the semantics of is and assumption= e is C ∧ e 6= error ∧ ψ[e/le] [by the semantics of casts and assumption]= e is C ∧ (e 6= error ∧ ψ[e/le]) [by predicate calculus]= e is C ∧ ([[Γ,A B le := e : com]]η ψ) [by the semantics of assignment]= e is C ∧ true ⇒ ([[Γ,A B le := e : com]]η ψ) [by predicate calculus]= [[Γ,A B : [e is C , true] : com]]η ([[Γ,A B le := e : com]]η ψ)

[by the semantics of the specification statement]= [[Γ,A B : [e is C , true]; le := e : com]]η ψ [by the semantics of sequential composition]= [[Γ,A B {e is C}; le := e : com]]η ψ [by the definition of assumption]

The comments presented in the proof of law 〈eliminate cast of method call〉 are applicable here.2

G.1.7 Commands and expressions

Lemma 33 Let Γ and Γ′ be typing environments such that

284 APPENDIX G. PROOF OF LAWS OF CLASSES

Γ.locals x = T ′,

and

Γ′.locals = Γ.locals ⊕ {x 7→ T},

but are otherwise identical, where T ≤Γ T ′. For a type T ′′, such that T ′′ ≤Γ T, if every non-assignable occurrence of x in expressions is cast with T ′′, every expression assigned to x in theη C m has type T ′′, and every use of x as result argument in for a formal parameter of type T ′′,then

[[Γ,A B c : com]]η ψ = [[Γ′,A B c : com]]η ψ

Proof By induction.

Case x := e, with e of type T or any subtype of T .

[[Γ,A B x := e : com]]η ψ

= e 6= error ∧ ψ[e/x ] [by the semantics of assignment]= [[Γ′,A B x := e : com]]η ψ [by the hypothesis and the semantics of assignment]

The assignment x := e is well-type because the type of x is changed from T ′ to T and the typeof e is T ′′, such that T ′′ ≤Γ T , according to the hypothesis.

Case (res y : T ′ • c)(x )

[[Γ,N B (res y : T ′ • c)(x ) : com]]η ψ

= [[Γ,N B var l : T ′ • c[l/y ]; x := l end : com]]η ψ [by a syntactic transformation]= ∀ l : T ′ • [[Γ; l : T ′,N B c[l/y ]; x := l : com]]η ψ [by the semantics of local blocks]= ∀ l : T ′ • [[Γ; l : T ′,N B c[l/y ] : com]]η ([[Γ; l : T ′,N B x := l : com]]η ψ)

[by the semantics of sequential composition]= ∀ l : T • [[Γ′; l : T ,N B c[l/y ] : com]]η ([[Γ′; l : T ,N B x := l : com]]η ψ)

[by the hypothesis]= ∀ l : T • [[Γ′; l : T ,N B c[l/y ]; x := l : com]]η ψ

[by the semantics of sequential composition]= [[Γ′,N B var l : T • c[l/y ]; x := l end : com]]η ψ [by the semantics of local blocks]= [[Γ′,N B (res y : T • c)(x ) : com]]η ψ [by a syntactic transformation]

G.1. NORMAL FORM LAWS 285

The case in which x is used as result argument is similar to that of assignment as in the semanticsof a parameterised command with a result parameter, there is an assignment of a local variable,whose type is the same as the one of the result parameter, to the argument that is applied to theparameterised command. As required by the law, the type of the formal result parameter is T orany subtype of T .

2

Proof G.1.18 Law 〈change variable type〉

[[Γ,A B var x : T ′ • c end : com]]η ψ

= ∀ x : T ′ • [[Γ; x : T ′ B • c : com]]η ψ [by the semantics of local blocks]= ∀ x : T • [[Γ; x : T B • c : com]]η ψ [by Lemma 33]= [[Γ,A B var x : T • c end : com]]η ψ [by the semantics of local blocks]

The environments Γ and Γ′ are as in Lemma 33. The provisos of the law guarantee that theprograms are well-typed.

2

Proof G.1.19 Law 〈change angelic variable type〉

The proof of law 〈change angelic variable type〉 is similar to that of law 〈change variable type〉.2

Proof G.1.20 Law 〈is test true〉If N ≤cds M , then

[[Γ,N B self is M : com]]η ψ

= [[Γ,N B N is M : com]]η ψ [by typing of self ]= [[Γ,N B true : com]]η ψ [by the hypothesis and the semantics of is]

2

Proof G.1.21 Law 〈is test false〉If N �cds M and M �cds N , then

[[Γ,N B self is M : com]]η ψ

= [[Γ,N B N is M : com]]η ψ [by typing of self ]= [[Γ,N B false : com]]η ψ [by the hypothesis and the semantics of is]

2

286 APPENDIX G. PROOF OF LAWS OF CLASSES

G.2 Further object-oriented programming laws

In Lemma 34, in what follows, we abuse of notation and write η[new A/new B ] to denote that,in environment η, expression new B is replaced with new A.

Lemma 34 Let Γ be a typing environment in which Γ.supcls B = A, Γ.attr B \Γ.attr A = ∅, andΓ.meth B \ Γ.meth A = ∅. Let η and η′ be environments such that η′ = η[new A/new B ], then

[[Γ,D B c : com]]η ψ = [[Γ,D B c : com]]η′ ψ

Proof By induction. Here, we consider the case of assignments and method calls. The other casesare consequence of the induction hypothesis.

Case x := e. Assignment of new B is of special interest, since other expressions remain unchanged.

[[Γ,N B x := new B : com]]η ψ

= new B 6= error ∧ ψ[new B/x ] [by the semantics of assignment]= new B 6= error ∧ ψ[new A/x ] [by the hypothesis and definition of η′]= [[Γ,N B x := new A : com]]η′ ψ [by the semantics of assignment]

Case le.m(e). We consider the case of a call on an object of dynamic type B .

[[Γ,D B le.m(e) : com]]η ψ

= (∨N ′≤ΓN ′′• le isExactly N ′ ∧ [[Γ,D B (η N ′ m) ((N ′)le, e) : com]]η ψ

[by the semantics of method call]

We consider the case in which le is exactly an object of type B . Since m is not declared in B ,then, by the way the environment η is constructed, we can deduce that η B m is equal to η A m,except for the type of the extra me parameter. The method m may be redefined in the subclassesof B , but this is irrelevant for the proof.

(∨N ′≤ΓN ′′• le isExactly N ′ ∧ [[Γ,D B (η N ′ m) ((N ′)le, e) : com]]η ψ

= le isExactly B ∧ [[Γ,D B (η B m) ((B)le, e) : com]]η ψ [by assumption]

An object of exact type A also calls the same method that is called on an object of dynamictype B , since class B redefines no methods. By the definition of the environment η′ occurrences ofnew B are replaced with new A.

le isExactly B ∧ [[Γ,D B (η B m) ((B)le, e) : com]]η ψ

= le isExactly A ∧ [[Γ,D B (η A m) ((A)le, e) : com]]η ψ [by definition of η′]= [[Γ,D B le.m(e) : com]]η ψ [by the semantics of method call]

G.2. FURTHER OBJECT-ORIENTED PROGRAMMING LAWS 287

2

Lemma 35 Let Γ be a typing environment in which Γ.supcls B = A, Γ.attr B \ Γ.attr A = ∅,and Γ.meth B \ Γ.meth A = ∅. Let η, and η′ be environments such that η′ = η[new A/new B ].If c′ = c[new A/new B ], then

[[Γ,main B c : com]]η ψ = [[Γ,main B c′ : com]]η′ ψ

Proof Similar to Lemma 34.2

Proof G.2.1 Law 〈new superclass〉

[[∅; x : T B class A extends C adsa mtsa end

class B extends A end • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ,main B c′ : com]]η′ ψ [by Lemmas 34 and 35]= [[∅; x : T B class A extends C adsa mtsa end

class B extends A end • c′ : program]]η′ ψ [by the semantics of programs]

The reason for using Lemma 35 in the proof of Law 〈new superclass〉 is that there may beoccurrences of new B in the main command c. Replacements of new B with new A in c are notcaptured in Lemma 34 because class main is not in Γ.cnames. The environments Γ, η, and η′ areas in Lemmas 34 and 35. The provisos of the law guarantee that the programs are well-typed.

2

Lemma 36 Consider a typing environment Γ in which Γ.supcls B = A. Consider also an envi-ronment η such that

η A m = (vres me : A; pds • meI Γ A m c),

and

η B m = (vres me : B ; pds • meI Γ B m c),

for all method m, with m ∈ dom (Γ.meth A) and m ∈ dom (Γ.meth B). Let η and η′ be environ-ments such that η′ = η[new B/new A], but are otherwise identical, then

[[Γ,D B c : com]]η ψ = [[Γ,D B c : com]]η′ ψ

288 APPENDIX G. PROOF OF LAWS OF CLASSES

Proof By induction. Here, we consider the case of assignments and method calls. The other casesare consequence of the induction hypothesis.

Case x := e. Assignment of new A is of special interest, since other expressions remain unchanged.

[[Γ,N B x := new A : com]]η ψ

= new A 6= error ∧ ψ[new A/x ] [by the semantics of assignment]= new B 6= error ∧ ψ[new B/x ] [by the hypothesis and definition of η′]= [[Γ,N B x := new B : com]]η′ ψ [by the semantics of assignment]

Case le.m(e). We consider the case of a call on an object of dynamic type A.

[[Γ,D B le.m(e) : com]]η ψ

= (∨N ′≤ΓN ′′• le isExactly N ′ ∧ [[Γ,D B (η N ′ m) ((N ′)le, e) : com]]η ψ

[by the semantics of method call]

We consider the case in which le is exactly an object of type A.

(∨N ′≤ΓN ′′• le isExactly N ′ ∧ [[Γ,D B (η N ′ m) ((N ′)le, e) : com]]η ψ

= le isExactly A ∧ [[Γ,D B (η A m) ((A)le, e) : com]]η ψ [by assumption]

Since m is not redefined in B , then, by the way the environment η is constructed, we deducethat η B m is equal to η A m, except for the type of the extra me parameter. The method m maybe redefined in the subclasses of B , but this is irrelevant for the proof.

An object of exact type A also calls the same method that is called on an object of dynamic typeB , since class B redefines no methods of A. By the definition of the environment η′ occurrences ofnew A are replaced with new B .

le isExactly A ∧ [[Γ,D B (η A m) ((A)le, e) : com]]η ψ

= le isExactly B ∧ [[Γ,D B (η B m) ((B)le, e) : com]]η ψ [by definition of η′]= [[Γ,D B le.m(e) : com]]η ψ [by the semantics of method call]

2

Lemma 37 Consider a typing environment Γ in which Γ.supcls B = A. Consider also an envi-ronment η such that

η A m = (vres me : A; pds • meI Γ A m c),

and

η B m = (vres me : B ; pds • meI Γ B m c),

G.2. FURTHER OBJECT-ORIENTED PROGRAMMING LAWS 289

for all method m, with m ∈ dom (Γ.meth A) and m ∈ dom (Γ.meth B). Let η and η′ be environ-ments such that η′ = η[new B/new A], but are otherwise identical. If c′ = c[new B/new A],then

[[Γ,main B c : com]]η ψ = [[Γ,main B c′ : com]]η′ ψ

Proof Similar to Lemma 36.

2

Proof G.2.2 Law 〈new superclass〉

[[∅; x : T B class A extends C adsa mtsa end

class B extends A end • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ,main B c′ : com]]η′ ψ [by Lemmas 36 and 37]= [[∅; x : T B class A extends C adsa mtsa end

class B extends A end • c′ : program]]η′ ψ [by the semantics of programs]

The reason for using Lemma 37 in the proof of aw 〈new subclass〉 is that there may be oc-currences of new A in the main command c. Replacements of new A with new B in c are notcaptured in Lemma 36 because class main is not in Γ.cnames. The environments Γ, η, and η′ areas in Lemmas 36 and 37. The provisos of the law guarantee that the programs are well-typed.

2

G.2.1 Changing a superclass

Lemma 38 in what follows states that, if the environment η remains unchanged, the semantics ofprograms also remains unchanged, in spite of changes in the typing environment.

Lemma 38 Let Γ and Γ′ be environments such that a command c is well-typed for both Γ and Γ′

and a class N , and let η be an environment compatible with both Γ and Γ′. Then,

[[Γ,N B c : com]]η = [[Γ′,N B c : com]]η

Proof Straightforward induction. 2

290 APPENDIX G. PROOF OF LAWS OF CLASSES

Proof G.2.3 Law 〈change superclass: from object to any class〉

[[∅; x : T B class C extends object adscmtsc end

cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η′ ψ [by Lemma 38][[∅; x : T B class C extends B adscmtsc end

cds • c : program]]η ψ [by the semantics of programs]

The environment η does not change. The provisos guarantee that the programs are well-typed.2

Proof G.2.4 Law 〈change superclass: from an empty class to immediate superclass〉

[[∅; x : T B class B extends A end

class C extends B ads ′ops ′ end

cds • c : program]]η ψ

= [[Γ,main B c : com]]η ψ [by the semantics of programs]= [[Γ′,main B c : com]]η ψ [by Lemma 38]= [[∅; x : T B class B extends A end

class C extends A ads ′ops ′ end

cds • c : program]]η ψ [by the semantics of programs]

The environment η does not change, as class B is an empty class. The provisos guarantee thatthe programs are well-typed.

2

G.2.2 Class invariant

Proof G.2.5 Law 〈introduce class invariant〉

From left to right.

For the proof of this law from left to right, we proceed with data refinement of class A. Theabstract and concrete variables are the same. The coupling invariant is the class invariantinv .

Case x := e

x := e

G.2. FURTHER OBJECT-ORIENTED PROGRAMMING LAWS 291

= x : [x = e] [by law 〈simple specification〉]¹ x : [inv , x = e ∧ inv ] [by law 〈augment specification〉]= x : [inv , x = e]; [inv ] [by law 〈absorb coercion〉, from right to left]v x : [inv , x = e]; [inv ]; {inv} [by law 〈introduce assumption〉]= x : [inv , x = e ∧ inv ]; {inv} [by law 〈absorb coercion〉, from left to right]v x := e; {inv} [by law 〈assignment〉]

Case x : [ψ1, ψ2]

x : [ψ1, ψ2]¹ x : [ψ1 ∧ inv , ψ2 ∧ inv ] [by law 〈augment specification〉]= x : [ψ1 ∧ inv , ψ2]; [inv ] [by law 〈absorb coercion〉, from right to left]v x : [ψ1 ∧ inv , ψ2]; [inv ]; {inv} [by law 〈introduce assumption〉]= x : [ψ1 ∧ inv , ψ2 ∧ inv ]; {inv} [by law 〈absorb coercion〉, from left to right]v x : [ψ1, ψ2]; {inv} [since inv is class invariant and w : [inv , inv ] v x : [ψ1, ψ2]]

The last case, in terms of data refinement, is guard augmentation. In this case, we assumeG ∧ inv to be G ′ in law 〈augment guard〉. This deals with the refinement of alternation.

For sequential composition, recall that data refinement distributes over it. For the caseof method calls, we have to eliminate calls before applying data refinement. The case ofapplication of parameterised commands is similar. The case of local variable blocks andrecursion are also consequence of data refinement.

From right to left.

c; {inv}v c [by laws 〈remove assumption〉 and 〈; -skip unit〉]

2

292 APPENDIX G. PROOF OF LAWS OF CLASSES

Appendix H

Typing Rules

N 6= main

Γ,N B self : N

N ′ ∈ Γ.cnames

Γ,N B null : N ′

T ∈ Γ.cnames or T is a primitive type

Γ,N B error : T

N ′ ∈ Γ.cnames

Γ,N B new N ′ : N ′

(Γ; x : T ) B x : TΓ B e : T ′ f : T → U is built-in T ′ ≤Γ T

Γ B f (e) : U

Γ,N B e : N ′ N ′′ ≤Γ N ′

Γ,N B e is N ′′ : bool

Γ,N B e : N ′ N ′′ ≤Γ N ′

Γ,N B (N ′′)e : N ′′

Γ,N B e : N ′ Γ.attr N ′ x = T visib Γ N ′ N x

Γ,N B e.x : T

Γ,N B e : N ′ Γ.attr N ′ x = T Γ,N B e ′ : T ′

T ′ ≤Γ T visib Γ N ′ N x

Γ,N B (e; x : e ′) : N ′

Table H.1: Typing of Expressions

294 APPENDIX H. TYPING RULES

Γ B e : bool

Γ B e : pred

Γ B ψi : pred i ∈ {1, 2}Γ B ψ1 ⇒ ψ2 : pred

Γ B ψi : pred for all i

Γ B (∨ i • ψi) : pred

Γ; x : T B ψ : pred

Γ B ∀ x : T • ψ : pred

Γ,N B e : N ′ N ′′ ≤Γ N ′

Γ,N B e isExactly N ′′ : pred

Table H.2: Typing of Predicates

(Γ; x : N ′′),N B ψ : pred N ′′ ≤Γ N ′

(Γ; x : N ′),N B x isExactly N ′′ ∧ ψ : pred

(Γ; x : N ′′),N B ψ : pred N ′′ ≤Γ N ′

(Γ; x : N ′),N B x isExactly N ′′ ⇒ ψ : pred

(Γ; x : N ′′),N B ψ : pred N ′′ ≤Γ N ′

(Γ; x : N ′),N B x is N ′′ ∧ ψ : pred

(Γ; x : N ′′),N B ψ : pred N ′′ ≤Γ N ′

(Γ; x : N ′),N B x is N ′′ ⇒ ψ : pred

Table H.3: Coercion Rules

(Γ; x : T ) B c : com par ∈ {val, res,vres}Γ B (par x : T • c) : pcom(par x : T )

Γ B c : com

Γ B (• c) : pcom()

(Γ; x : T ) B (pds • c) : pcom(pds) par ∈ {val, res,vres}Γ B (par x : T ; pds • c) : pcom(par x : T ; pds)

Γ,N B le : N ′ Γ.meth N ′ m = pds

Γ,N B le.m : pcom(pds)

Table H.4: Typing of Parameterised Commands

295

Γ B le : T Γ B e : T ′ T ′ ≤Γ T sdisjoint le

Γ B le := e : com

(Γ; x : T ) B ψi : pred i ∈ {1, 2}(Γ; x : T ) B x : [ψ1, ψ2] : com

Γ B (• c) : pcom()

Γ B (• c)() : com

Γ B (val x : T • c) : pcom(val x : T ) Γ B e : T ′ T ′ ≤Γ T

Γ B (val x : T • c)(e) : com

Γ B (res x : T • c) : pcom(res x : T ) Γ B le : T ′ T ≤Γ T ′ sdisjoint le

Γ B (res x : T • c)(le) : com

Γ B (vres x : T • c) : pcom(vres x : T ) Γ B le : T sdisjoint le

Γ B (vres x : T • c)(le) : com

Γ B (pd • (pds • c)(e1))(e2) : com sdisjoint (rvrargs (pd ; pds) (e2, e1))

Γ B (pd ; pds • c)(e2, e1) : com

Γ B le.m : pcom(pds) Γ B e : Tsdisjoint(le, rvrargs pds e) aptype Γ pds e T

Γ B le.m(e) : comΓ B c : com Γ B c′ : com

Γ B c; c′ : com

Γ B ψi : pred Γ B ci : com

Γ B if []i • ψi → ci fi : com

Γ B Y : com ⇒ Γ B c : com

Γ B rec Y • c end : com

(Γ; x : T ) B c : com

Γ B (var x : T • c end) : com

(Γ; x : T ) B c : com

Γ B (avar x : T • c end) : com

Table H.5: Typing of Commands

296 APPENDIX H. TYPING RULES

Bibliography

[1] K. Arnold and J. Gosling. The Java Programming Language. Addison-Wesley, 1996.

[2] D. Astel. Refactoring with UML. In Proc. 3rd Int’l Conf. eXtreme Programming and FlexibleProcesses in Software Engineering, pages 67–70, Alghero, Sardinia, Italy, 2002.

[3] B. H. Liskov and J. M. Wing. A Behavorial Notion of Subtyping. ACM Transactions onProgramming Languages and Systems, 16(6):1811–1841, November 1994.

[4] R. J. R. Back. Procedural Abstraction in the Refinement Calculus. Technical report, Depart-ment of Computer Science, Abo - Finland, 1987. Ser. A. No. 55.

[5] R. J. R. Back. A Calculus of Refinements for Programs Derivations. Acta Informatica,(25):593–624, 1988.

[6] R. J. R. Back. Software Construction by Stepwise Feature Introduction. In Didier Bert et. al.,editor, ZB 2002: Formal Specification and Development in Z and B, volume 2272 of LectureNotes in Computer Science, pages 162–183, 2002.

[7] R. J. R. Back and J. von Wright. Refinement Calculus: A Systematic Introduction. Springer-Verlag, 1998.

[8] J. Banerjee and W. Kim. Semantics and Implementation of Schema Evolution in Object-Oriented Databases. SIGMOD RECORD, 16(3):311–321, 1987.

[9] P. L. Bergstein. Object-Preserving Class Transformations. SIGPLAN Notices, 26(11):299–213,November 1991.

[10] D. Binkley and K. Gallagher. Program Slicing. Advances of Computing, (43):1–50, 1996.

[11] P. Boger, T. Sturm, and P. Fragemann. Refactoring Browser for UML. In Proc. 3rd Int’lConf. on eXtreme Programming and Flexible Processes in Software Engineering, pages 77–81,Alghero, Sardinia, Italy, 2002.

[12] Booch and Rumbaugh and Jacobson. The Unified Modelling Language - User Guide. Addison-Wesley, 1997.

298 BIBLIOGRAPHY

[13] P. Borba. Where are the laws of object-oriented programming? In I Brazilian Workshop onFormal Methods, pages 59–70, October 1998. Porto Alegre, Brazil.

[14] P. Borba and A. Sampaio. Basic Laws of ROOL: an Object-Oriented Language. In Revista deINFORMATICA TEORICA e APLICADA, volume 7, pages 49–68. Instituto de Informatica- UFRGS, sep 2000.

[15] P. Borba and A. Sampaio. The basic laws of ROOL. Technical report,Centro de Informatica, Universidade Federal de Pernambuco, Brazil, 2000.http://www.cin.ufpe.br/∼lmf/coop/papers.

[16] P. Borba, A. Sampaio, A. Cavalcanti, and M. Cornelio. Algebraic Reasoning for Object-Oriented Programming. Science of Computer Programming, (52):53–100, 2004.

[17] P. Borba, A. Sampaio, and M. Cornelio. A refinement algebra for object-oriented programming.In Luca Cardelli, editor, European Conference on Object-oriented Programming, ECOOP’2003,volume 2743 of Lecture Notes in Computer Science, pages 257–282, Darmstadt, Germany, July2003. Springer-Verlag.

[18] P. Bottoni, F. Parisi-Presicce, and G. Taentzer. Coordinated Distributed Diagram Trans-formation for Software Evolution. Eletronic Notes in Theoretical Computer Science, 72(4),2003.

[19] M. Broy, E. Denert, K. Renzel, and M. Schmidt. Software architectures and design patternsin business applications. Technical Report TUM-I9746, Technische Univeritat Munchen, 1997.

[20] A. L. C. Cavalcanti. A Refinement Calculus for Z. PhD thesis, Oxford University ComputingLaboratory, Oxford - UK, 1997. Technical Monograph TM-PRG-123.

[21] A. L. C. Cavalcanti and D. Naumann. A weakest precondition semantics for an object-orientedlanguage of refinement. In FM’99 - Formal Methods, volume 1709 of Lecture Notes in ComputerScience, pages 1439–1459, 1999.

[22] A. L. C. Cavalcanti and D. Naumann. A Weakest Precondition Semantics for an Object-oriented Language of Refinement. Technical Report CS 9903, Stevens Institute of Technology,sep 1999.

[23] A. L. C. Cavalcanti and D. Naumann. Forward Simulation for Data Refinement of Classes.In L.-H. Eriksson and P. Lindsay, editors, FME 2002: Formal Methods - Getting IT Right,volume 2391 of Lecture Notes in Computer Science, pages 471—490. Springer-Verlag, 2002.

[24] A. L. C. Cavalcanti and D. A. Naumann. A Weakest Precondition Semantics for Refinement ofObject-oriented Programs. IEEE Transactions on Software Engineering, 26(8):713–728, 2000.

BIBLIOGRAPHY 299

[25] A. L. C. Cavalcanti and D. A. Naumann. Foward Simulation for Data Refinement of Classes.In L. Eriksson and P. A. Lindsay, editor, FME 2002: Formal Methods - Getting IT Right,volume 2391, pages 471–490. Springer-Verlag, 2002.

[26] A. L. C. Cavalcanti, A. Sampaio, and J. C. P. Woodcock. An Inconsistency in Procedures,Parameters, and Substitution in the Refinement Calculus. Science of Computer Programming,33(1):87–96, 1999.

[27] A. L. C. Cavalcanti, A. C. A. Sampaio, and J. C. P. Woodcock. Procedures and Recursion inthe Refinement Calculus. Journal of the Brazilian Computer Society, 5(1):1–15, 1998.

[28] M. O. Cinneide. Automated Application of Design Patterns: A Refactoring Approach. PhDthesis, Department of Computer Science, Trinity College, Dublin, 2000.

[29] M. O. Cinneide and P. Nixon. A methodology for the automated introduction of designpatterns. In H. Yang and L. White, editors, Proceedings International Conference on SoftwareMaintenance, pages 463–472, Oxford, sept 1999. IEEE Press.

[30] P. Coad. Object-Oriented Patterns. Communications of the ACM, 9(35):152–159, 1992.

[31] M. Cornelio, A. Cavalcanti, and A. Sampaio. Program Development in ROOL. Technicalreport, Centro de Informatica - UFPE, aug 2001. http://www.cin.ufpe.br/∼mlc2.

[32] M. Cornelio, A. Cavalcanti, and A. Sampaio. Refactoring by Transformation. In J. Derrick,E. Boiten, J. Woodcock, and J. von Wright, editors, REFINE’2002, volume 70 of EletronicNotes in Theoretical Computer Science, 2002.

[33] M. Cornelio, A. Cavalcanti, A. Sampaio, and P. Borba. Proving the Basic Laws of ROOL ina Weakest Precondition Semantics. Technical report, Centro de Informatica - UFPE, 2000.http://www.cin.ufpe.br/∼lmf/coop/papers.

[34] E. W. Dijkstra. A Discipline of Programming. Prentice-Hall, 1976.

[35] A. Duran, A. Cavalcanti, and A. Sampaio. Refinement algebra for formal bytecode generation.In ICFEM 2002 - 4th International Conference on Formal Engineering Methods, volume 2495,pages 347–358, Shanghai, China, October 2002. Lecture Notes in Computer Science, Springer-Verlag.

[36] A. Duran, A. Cavalcanti, and A. Sampaio. A strategy for compiling classes, inheritance,and dynamic binding. In FME 2003 - International Symposium of Formal Methods Europe,volume 2805, pages 301–320, Pisa, Italy, September 2003. Lecture Notes in Computer Science,Springer-Verlag.

[37] Eclipse.org. Eclipse. Available on-line http://www.eclipse.org/. Last accessed in June, 2004.

300 BIBLIOGRAPHY

[38] A. Eden. Formal specification of object-oriented design. In International Conference on Mul-tidisciplinary Design in Engineering, November 2001.

[39] A. Eden, Y. Hirshfeld, and A. Yehudai. LePUS - A Declarative Pattern Specification Language.Technical Report 326/98, Department of Computer Science, Tel Aviv University, 1998.

[40] E. Gamma et al. Design Patterns: Abstraction and Reuse of Object-Oriented Design. InECOOP’93, volume 707 of Lecture Notes in Computer Science, pages 406–431, 1993.

[41] A. Flores, L. Reynoso, and R. Moore. A Formal Model of Object-Oriented Design and GoFPatterns. Technical report, UNU-IIST, July 2000.

[42] M. Fowler. Refactoring: Improving the Design of Existing Code. Addison-Wesley, 1999.

[43] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: elements of reusableobject-oriented software. Addison-Wesley Professional Computing Series. Addison-Wesley, July1994.

[44] R. Gheyi and P. Borba. Refactoring Alloy Specification. In A. Cavalcanti and P. Machado,editors, 6th Brazilian Workshop on Formal Methods, pages 166—181, Campina Grande—Paraıba, Brasil, 2003.

[45] W. G. Griswold. Program Restructuring as an Aid to Software Maintenance. PhD thesis,University of Washington, 1991.

[46] C.A.R. Hoare et al. Laws of programming. Communications of the ACM, 30(8):672–686,August 1987.

[47] D. Jackson. Alloy: A Lightweight Object Modelling Notation. ACM Transactions on SoftwareEngineering and Methodology (TOSEM), 11:256–290, 2002.

[48] M. Munro K. Bennett, B. Cornelius and D. Robson. Software maintenance. In John McDermid,editor, Software Engineers’ Book Reference, chapter 20, pages 1–18. Butterworth-Heinemann,1991.

[49] S. Kent. An Axiomatic Semantics for VMD++: OO Aspects. Technical Report AfroditeReport AFRO/IC/SK/SEM-OO/V2, Imperial College of Science, Technology and Medicine,January 1993.

[50] G. Kniesel and H. Koch. Static Composition of Refactorings. Science of Computer Program-ming, 2004. To appear.

[51] R. Komondoor and S. Horwitz. Semantics-Preserving Procedure Extraction. In ConferenceRecord of the 27th ACM Symposium on Principles of Programming Languages (POPL), Jan-uary 2000.

BIBLIOGRAPHY 301

[52] A. Lakhotia and J.-C. Deprez. Restructuring programs by tucking statements into functions.Information and Software Technology, 40(11-12):677–690, 1998.

[53] K. Lano, S. Goldsack, and J. Bicarregui. Formalising Design Patterns. In RBCS-FACS North-ern Formal Methods Workshop, 1996.

[54] K. R. M. Leino. Recursive Object Types in a Logic of Object-Oriented Programs. In ChrisHankin, editor, 7th European Symposium on Programming, number 1381 in LNCS, 1998.

[55] K. Lieberherr and I. Holland. Assuring Good Style for Object-Oriented Programs. IEEESoftware, pages 38–48, September 1989.

[56] K. J. Lieberherr, I. Holland, and A. J. Riel. Object-Oriented Programming: An ObjectiveSense of Style. In SIGPLAN Notices , number 11, pages 323–334, September 1988.

[57] B. O. Lira, A. L. C. Cavalcanti, and A. C. A. Sampaio. Automation of a Normal FormReduction Strategy for Object-Oriented Programming. In Proceeding of the 5th BrazilianWorkshop on Formal Methods, 2002.

[58] S. R. L. Meira and A. L. C. Cavalcanti. Modular Object-Oriented Z Specifications. In ProfC. J. van Rijsbergen, editor, Workshop on Computing Series, pages 173–192, Oxford - UK,December 1990. Springer-Verlag.

[59] S. R. L. Meira and A. L. C. Cavalcanti. The MooZ Specification Language. Technical report,Universidade Federal de Pernambuco, Departamento de Informatica, Recife - PE, 1992.

[60] T. Mens. A Formal Foundation for Object-Oriented Software Evolution. PhD thesis, VrijeUniversiteit Brussel, Belgimu, 1999.

[61] T. Mens, S. Demeyer, and D. Janssens. Formalising Behaviour Preserving Program Trans-formations. In Graph Transformations, volume 2505 of Lecture Notes in Computer Science,pages 286–301, 2002.

[62] B. Meyer. Object-Oriented Software Construction. Prentide-Hall, second edition, 1997.

[63] A. Mikhajlova and E. Sekerinski. Class Refinement and Interface Refinement in Object-Oriented Programs. In FME’97: Industrial Benefits of Formal Methods. Springer-Verlag,1997.

[64] C. C. Morgan. Programming from Specifications. Prentice Hall, second edition, 1994.

[65] C. C. Morgan, K. Robinson, and P. H. B. Gardiner. On the Refinement Calculus. TechnicalMonograph TM-PRG-70, Oxford University Computing Laboratory, Oxford - UK, October1988.

302 BIBLIOGRAPHY

[66] J. M. Morris. A Theoretical Basis for Stepwise Refinement and the Programming Calculus.Science of Computer Programming, (9):286–306, 1987.

[67] M. Oliveira and A. Cavalcanti. Tatics of refinement. In XIV Simposio Brasileiro de Engenhariade Software, pages 117–132, Joao Pessoa-PB, October 2000.

[68] M. V. M. Oliveira, A. L. C. Cavalcanti, and J. C. P. Woodcock. ArcAngel: a tactic languagefor refinement. Formal Aspects of Computing, 15(1):28–47, August 2003. The full version ofthis work can be found in the Masters Thesis by M Oliveira.

[69] W. Opdyke. Refactoring Object-Oriented Frameworks. PhD thesis, University of Illinois atUrbana-Champaign, 1992.

[70] J. Philipps and B. Rumpe. Roots of Refactoring. In Proc. 10th OOPSLA Workshop onBehavioral Semantics: Back to Basics, Florida–USA, October 2001.

[71] I. Porres. Model Refactorings as Rule-Based Update Transformations. Technical Report 525,TUCS Turku Center for Computer Science, Abo Akademi University, April 2003.

[72] G. A. Rose R. Duke, P. King and G. Smith. The Object-Z Specification Language: Version 1.Technical Report 91-1, Department of Computer Science, University of Queensland, SoftwareVerification Center, April 1991.

[73] D. Roberts, J. Brant, and R. Johnson. A Refactoring Toll for Samlltalk. Theory and Practiceof Object Systems, 3(4), 1997.

[74] D. B. Roberts. Practical Analysis for Refactoring. PhD thesis, University of Illinois an Urbana-Champaign, 1999.

[75] A. Sampaio. An Algebraic Approach to Compiler Design, volume 4. World Scientific, 1997.

[76] M. Shaw and D. Garlan. Software architecture: perspectives on an emerging discipline.Prentice-Hall, 1996.

[77] G. Snelting and F. Tip. Reengineering Class Hierarchies Using Concept Analysis. In Proc.Foundations of Software Engineering (FSE-6), SIGSOFT Software Engineering Notes, vol-ume 23, pages 99–110, 1998.

[78] J. M. Spivey. Understanding Z: A specification language and its formal semantics. CambridgeUniversity Press, 1988.

[79] J. M. Spivey. The Z Notation: a reference manual. C. A. Hoare Series Editor. Prentice HallInternational, 2nd edition, 1992.

BIBLIOGRAPHY 303

[80] G. Sunye, D. Pollet, T. LeTraon, and J.-M. Jezequel. Refactoring UML Models. In M. Gogollaand C. Kobryn, editors, UML 2001 - The Unified Modeling Language, volume 2185 of LectureNotes in Computer Science, pages 134–148, 2001.

[81] S. Thompson and C. Reinke. Refactoring Functional Programs. Technical report, ComputingLaboratory – University of Kent, 2001.

[82] S. Thompson and C. Reinke. A Case Study in Refactoring Functional Programs. In 7thBrazilian Symposium on Programming Languages, pages 1–16, Ouro Preto - MG - Brazil, May2003.

[83] F. Tip. A Survey of Program Slicing Techniques. Journal of Programming Languages, 3(3):121–189, 1995.

[84] F. Tip, A. Kiezun, and D. D. Baumer. Refactoring for generalization using type constraints. InProceedings of the 18th ACM SIGPLAN Conference on Object-Oriented Programing, Systems,Languages, and Applications, pages 13–26. ACM Press, 2003.

[85] L. Tokuda and D. Batory. Evolving Object-Oriented Designs with Refactoring. Journal ofAutomated Software Engineering, (8):89–120, 2001.

[86] L. A. Tokuda. Evolving Object-Oriented Designs with Refactoring. PhD thesis, Departmentof Computer Sciences, University of Texas at Austin, September 1999.

[87] M. Utting. An Object-Oriented Refinement Calculus with Modular Reasoning. PhD thesis,University of New South Wales – Kensington – Australia, 1992.

[88] E. Viana and P. Borba. Integrating Java with Relational Databases. III Simposio Brasileirode Linguagens de Programacao, pages 77–91, May 1999. In Portuguese.

[89] J. Woodcock and J. Davies. Using Z - Specification, Refinement and Proof. C. A. R. HoareSeries Editor. Prentice-Hall International, 1996.

Index

Laws

Classes

attribute elimination, 214

change angelic variable type, 221

change attribute type, 215

change result parameter type, 218

change superclass: from an empty classto immediate superclass, 224

change superclass: from object to anyclass, 223

change value parameter type, 218

change variable type, 220

change visibility: from private to public,214

change visibility: from protected to pub-lic, 214

class elimination, 213

eliminate super, 219

eliminate cast of expressions, 220

eliminate cast of method call, 220

introduce class invariant, 224

introduce method redefinition, 216

introduce trivial cast in expressions, 220

is test false, 221

is test true, 221

method call elimination, 219

method elimination, 217

move attribute to superclass, 215

move original method to superclass, 217

move redefined method to superclass, 216

new subclass, 222

new superclass, 221

Commands

:= identity, 199

:= -CB right dist, 202

:= skip, 199

:= symmetry, 199

; -:= combination, 202

; assoc, 201

;- abort left zero, 201

;- if left dist, 202

;- if selection, 202

;- miracle left zero, 201

;- skip unit, 201

alternation absorb assumption, 206

assignment seq comp exp substitution,208

assumption advance command, 207

assumption before or after command, 206

assumption distribution, 207

assumption guard, 206

assumption intro, 207

avar- := initial value, 204

avar-; dist, 204

avar elim, 203

avar- := final value, 204

avar- if dist, 204

avar-; left dist, 204

avar rename, 203

avar-; right dist, 204

avar symmetry, 203

avar - var relationship, 204

INDEX 305

command refinement-class refinement, 38,209

if abort unity, 200

if - ∧ distrib, 200

if elim, 200

if false unity, 200

if gc elim, 201

if gc intro, 201

if identical guarded commands, 205

if - ∨ distrib1, 200

if - ∨ distrib2, 200

if symmetry, 199

if true guard, 199

if true guard ref, 201

innocuous assumption-reading, 206

innocuous assumption-writing, 206

iteration guards, 205

new assumption, 207

order independent assignment, 207

pcom absorb assumption, 206

pcom elimination-res, 209

pcom elimination-val, 208

pcom merge, 209

rec fixed point, 201

repeated assignment, 207

var-; dist, 203

var- := initial value, 203

var- avar refinement, 205

var block absorb assumption, 206

var block - res, 208

var block - val, 208

var dec separation, 208

var elim, 202

var- := final value, 203

var- if dist, 203

var-; left dist, 203

var rename, 202

var-; right dist, 203

var symmetry, 202weakening guards, 205

Data refinement and simulationData refinement—variable blocks with ini-

tialisation, 35, 211private attribute-coupling invariant, 34,

225superclass attribute-coupling invariant,

34, 225Morgan

absorb coercion, 210assignment, 210augment assignment, 210augment guards, 210augment specification, 210diminish assignment, 210diminish specification, 210merge assumptions, 211merge coercions, 211remove assumption, 211simple specification, 211strengthen postcondition, 211weaken precondition, 211

Lemmas

Eliminate super and Trivial Methods inHierarchy, 194

Eliminate super in Hierarchy, 193method call elimination-self, 187pcom result-argument, 197pcom value-argument, 196Program cast elimination, 196Pull Down Method in the Whole Hierar-

chy, 190Pull Up Method in the Whole Hierarchy,

189Self Non-Null Non-Error, 194Type changes in program, 195

306 INDEX

List of Refactorings

4.1 〈Extract/Inline Method〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434.2 〈Move Method〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484.3 〈Move Attribute〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544.4 〈Pull Up/Push Down Method〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 624.5 〈Replace Parameter with Method〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664.6 〈Extract Class〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724.7 〈Clientship Elimination〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764.8 〈Delegation Elimination〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814.9 〈Inline Class〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824.10 〈Self Encapsulate Field〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.11 〈Decompose Conditional〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854.12 〈Introduce Explaining Variable〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864.13 〈Consolidate Conditional Expressions〉 . . . . . . . . . . . . . . . . . . . . . . . . . . 864.14 〈Consolidate Duplicate Conditional Fragments〉 . . . . . . . . . . . . . . . . . . . . . 874.15 〈Substitute Algorithm〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885.1 〈Change clientship: from subclass to superclass〉 . . . . . . . . . . . . . . . . . . . . 935.2 〈Pull Up/Push Down Field〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 985.3 〈Extract Superclass〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1025.4 〈Collapse Hierarchy - Superclass〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065.5 〈Collapse Hierarchy - Subclass〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1115.6 〈Rename Method〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1155.7 〈Parameterise Method〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1205.8 〈Encapsulate Field〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1245.9 〈Add/Remove Parameter〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1295.10 〈Separate Query from Modifier〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1305.11 〈Encapsulate Downcast〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1316.1 〈Interface Clientship〉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138