Programming Language Concepts

Carlo Ghezzi, Mehdi Jazayeri
3rd edition, ISBN 0-471-10426-4
 

Table of Contents

1 Introduction 1

1.1 Software development process 1
1.2 Languages and software development environments 4
1.3 Languages and software design methods 5
1.4 Languages and computer architecture 8
1.5 Programming language qualities 10
1.5.1 Languages and reliability 11
1.5.2 Languages and maintainability 12
1.5.3 Languages and efficiency 13
1.6 A brief historical perspective 14
1.6.1 Early high-level languages 17
1.6.2 Early schisms 18
1.6.3 Consolidation 19
1.6.4 The next leap forward 19
1.6.5 The experimental 70s 20
1.6.6 The 80s and object orientation 21
1.6.7 The current stage 22
1.7 A bird’s-eye view of programming language concepts 23
1.7.1 A simple program 23
1.7.2 Syntax and semantics 25
1.7.3 Semantic elements 25
1.7.3.1 Variables 25
1.7.3.2 Values and references 26
1.7.3.3 Expressions 27
1.7.4 Program organization 28
1.7.5 Program data and algorithms 30
1.7.5.1 Data 30
1.7.5.2 Computation 31
1.7.6 External environment 31
1.8 Bibliographic notes 31
1.9 Exercises 32

2 Syntax and semantics 33

2.1 Language definition 34
2.1.1 Syntax 34
2.1.1.1 Abstract syntax, concrete syntax, and pragmatics 38
2.1.2 Semantics 39
2.1.2.1 An introduction to formal semantics 40
2.2 Language processing 46
2.2.1 Interpretation 46
2.2.2 Translation 47
2.2.3 The concept of binding 49
2.3 Variables 50
2.3.1 Name and scope 51
2.3.2 Type 53
2.3.3 l-value 57
2.3.4 r-value 57
2.3.5 References and unnamed variables 59
2.4 Routines 61
2.4.1 Generic routines 66
2.5 Aliasing and overloading 67
2.6 An abstract semantic processor 69
2.7 Run-time structure 72
2.7.1 C1: A language with only simple statements 73
2.7.2 C2: Adding simple routines 74
2.7.3 C3: Supporting recursive functions 77
2.7.4 C4: Supporting block structure 82
2.7.4.1 Nesting via compound statements 83
2.7.4.2 Nesting via locally declared routines 86
2.7.5 C5: Toward more dynamic behaviors 90
2.7.5.1 Activation records whose size becomes known at unit activation 91
2.7.5.2 Fully dynamic data allocation 92
2.7.6 The structure of dynamic languages 93
2.7.6.1 Dynamic typing 94
2.7.6.2 Dynamic scoping 95
2.7.7 Parameter passing 97
2.7.7.1 Data parameters 97
2.7.7.2 Routine parameters 102
2.8 Bibliographic notes 106
2.9 Exercises 107

3 Structuring the data 111

3.1 Built-in types and primitive types 112
3.2 Data aggregates and type constructors 115
3.2.1 Cartesian product 115
3.2.2 Finite mapping 117
3.2.3 Union and discriminated union 120
3.2.4 Powerset 122
3.2.5 Sequence 123
3.2.6 Recursion 123
3.2.6.1 Insecurities of pointers 125
3.2.7 Compound values 127
3.3 User-defined types and abstract data types 128
3.3.1 Abstract data types in C++ 129
3.3.1.1 Constructors 130
3.3.1.2 Genericity 131
3.3.1.3 Destructors 132
3.3.2 Abstract data types in Eiffel 133
3.3.2.1 Generic abstract data types 136
3.4 Type systems 136
3.4.1 Static versus dynamic program checking 137
3.4.2 Strong typing and type checking 138
3.4.3 Type compatibility 139
3.4.4 Type conversions 142
3.4.5 Types and subtypes 144
3.4.6 Generic types 145
3.4.7 Summing up: Monomorphic versus polymorphic type systems 146
3.5 The type structure of representative languages 149
3.5.1 Pascal 149
3.5.2 C++ 151
3.5.3 Ada 153
3.6 Implementation models 160
3.6.1 Built-in primitive types and enumerations 160
3.6.2 Structured types 161
3.6.2.1 Cartesian product 162
3.6.2.2 Finite mapping 163
3.6.2.3 Union and discriminated union 164
3.6.2.4 Powerset 165
3.6.2.5 Sequence 166
3.6.2.6 Classes 166
3.6.2.7 Pointers and garbage collection 167
3.7 Bibliographic notes 169
3.8 Exercises 170

4 Structuring the computation 173

4.1 Expressions and statements 174
4.2 Conditional execution and iteration 179
4.2.1 Conditional execution 179
4.2.2 Iteration 182
4.3 Routines 186
4.3.1 Style issues: Side effects and aliasing 188
4.4 Exceptions 192
4.4.1 Exception handling in Ada 194
4.4.2 Exception handling in C++ 197
4.4.3 Exception handling in Java 200
4.4.4 Exception handling in Eiffel 201
4.4.5 Exception handling in ML 204
4.4.6 A comparative evaluation 205
4.5 Pattern matching 207
4.6 Nondeterminism and backtracking 210
4.7 Event-driven computations 212
4.8 Concurrent computations 213
4.8.1 Processes 218
4.8.2 Synchronization and communication 219
4.8.2.1 Semaphores 220
4.8.2.2 Monitors and signals 222
4.8.2.3 Rendezvous 225
4.8.2.4 Summing up 227
4.8.3 Implementation models 229
4.8.3.1 Semaphores 232
4.8.3.2 Monitors and signals 233
4.8.3.3 Rendezvous 234
4.9 Bibliographic notes 235
4.10 Exercises 236

5 Structuring the program 239

5.1 Software design methods 241
5.2 Concepts in support of modularity 242
5.2.1 Encapsulation, interface, and implementation 242
5.2.2 Separation of interface and implementation 244
5.2.3 Separate and independent compilation 247
5.2.4 Libraries of modules 248
5.3 Language features for programming in the large 249
5.3.1 Pascal 250
5.3.2 C 253
5.3.2.1 Encapsulation 253
5.3.2.2 Interface and implementation 253
5.3.2.3 Program organization 254
5.3.3 C++ 256
5.3.3.1 Encapsulation 256
5.3.3.2 Program organization 257
5.3.3.3 Grouping of units 259
5.3.4 Ada 262
5.3.4.1 Encapsulation 262
5.3.4.2 Interface and implementation 262
5.3.4.3 Program organization 263
5.3.4.4 Separate compilation 265
5.3.4.5 Adas private type 266
5.3.4.6 Grouping of units 268
5.3.5 ML 270
5.3.5.1 Encapsulation 270
5.3.5.2 Interface and implementation 272
5.3.6 Abstract data types, classes, and modules 274
5.4 Generic units 275
5.4.1 Generic data structures 275
5.4.2 Generic algorithms 276
5.4.3 Generic modules 279
5.4.4 Higher levels of genericity 279
5.5 Final remarks 281
5.6 Bibliographic notes 282
5.7 Exercises 282

6 Object-oriented languages 285

6.1 Concepts of object-oriented programming 287
6.1.1 Classes of objects 288
6.1.2 Inheritance 289
6.1.3 Polymorphism 290
6.1.4 Dynamic binding of calls to member functions 292
6.2 Inheritance and the type system 293
6.2.1 Subclasses versus subtypes 294
6.2.2 Strong typing and polymorphism 294
6.2.2.1 Type extension 295
6.2.2.2 Overriding of member functions 295
6.2.3 Inheritance hierarchies 299
6.2.3.1 Single and multiple inheritance 300
6.2.3.2 Implementation and interface inheritance 301
6.3 Object-oriented features in programming languages 302
6.3.1 C++ 302
6.3.1.1 Classes 303
6.3.1.2 Virtual functions and dynamic binding 304
6.3.1.3 Pure virtual functions for specification 305
6.3.1.4 Protected members 305
6.3.1.5 Overloading, polymorphism, and genericity 307
6.3.2 Ada 95 308
6.3.2.1 Tagged types 308
6.3.2.2 Dynamic dispatch through classwide programming 310
6.3.2.3 Abstract types and routines 311
6.3.3 Eiffel 311
6.3.3.1 Classes and object creation 311
6.3.3.2 Inheritance and redefinition 312
6.3.4 Smalltalk 313
6.3.4.1 Classes and inheritance 313
6.3.4.2 Variables and dynamic typing 315
6.3.4.3 The pervasive role of objects 315
6.3.4.4 The Smalltalk environment 317
6.3.5 Java 317
6.3.5.1 Classes and inheritance 318
6.3.5.2 Interface and inheritance 320
6.3.5.3 Abstract classes and abstract methods 321
6.3.5.4 Packages and programming in the large 322
6.3.5.5 Package access 322
6.3.5.6 Threads and synchronization 323
6.4 Final remarks 327
6.5 Bibliographic notes 327
6.6 Exercises 329

7 Functional programming languages 333

7.1 Characteristics of imperative languages 334
7.2 Mathematical and programming functions 335
7.3 Principles of functional programming 336
7.3.1 Values, bindings, and functions 337
7.3.2 Lambda calculus: A model of computation by functions 338
7.4 Representative functional languages 342
7.4.1 LISP 342
7.4.1.1 Data objects 343
7.4.1.2 Functions 343
7.4.1.3 Functional forms 346
7.4.1.4 LISP semantics 347
7.4.2 APL 347
7.4.2.1 Data objects 347
7.4.2.2 Functions 348
7.4.2.3 Functional forms 349
7.4.2.4 An APL program 351
7.4.3 ML 352
7.4.3.1 The list data object and its operations 353
7.4.3.2 Bindings, values, and types 353
7.4.3.3 Functions 354
7.4.3.4 Functional forms 355
7.4.3.5 Type system 356
7.4.3.6 Type inference 359
7.4.3.7 Modules 361
7.5 Functional programming in C++ 363
7.5.1 Functions as objects 364
7.5.2 Functional forms 364
7.5.3 Type inference 367
7.6 Final remarks 368
7.7 Bibliographic notes 368
7.8 Exercises 369

8 Logic and rule-based languages 371

8.1 "What" versus "how": Specification versus implementation 371
8.1.1 A first example 373
8.1.2 Another example 375
8.2 Principles of logic programming 377
8.2.1 Preliminaries: Facts, rules, queries, and deductions 377
8.2.2 An abstract interpretation algorithm 383
8.3 PROLOG 389
8.4 Functional programming versus logic programming 393
8.5 Rule-based languages 395
8.6 Bibliographic notes 398
8.7 Exercises 399

9 Languages in context 402

9.1 Execution context 403
9.2 Development context 405
9.3 Final remarks 406
9.4 Bibliographic notes 406

 Appendix: Language references 409

 Bibliography 411

 Index 419



Last modified: 3/February/1998, (Mehdi Jazayeri)