Principles of Programming Languages: M.Archana
Principles of Programming Languages: M.Archana
Principles of Programming Languages: M.Archana
Programming
Languages
M.ARCHANA
CONTENTS
1
UNIT IV. ABSTRACT DATA TYPES
4.1 Abstract -data types [Abstraction & Encapsulation]
4.2 Introduction to Data Abstraction,Design Issues
4.3 Language Examples
4.4 C++ Parameterized Abstract Data Types
4.5 Data Types
4.6 Object-Oriented Programming in Smalltalk
4.7 Object-Oriented Programming in C++
4.8 Object-Oriented Programming in Java
4.9 Object-Oriented Programming in C#
4.10 Object-Oriented Programming in Ada 95
2
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
UNIT-1
Preliminary Concepts
Background
Frankly, we didn‘t have the vaguest idea how the thing [FORTRAN language and
compiler] would work out in detail. …We struck out simply to optimize the
object program, the running time, because most people at that time believed
you couldn‘t do that kind of thing. They believed that machined-coded programs
would be so inefficient that it would be impractical for many applications.
John Backus, unexpected successes are common – the browser is another
example of an unexpected success
3
1.2 Language Evaluation Criteria – CO1, CO2
Readability : the ease with which programs can be read and understood
Writability : the ease with which a language can be used to create programs
Reliability : conformance to specifications (i.e., performs to its specifications)
Cost : the ultimate total cost
Readability
Overall simplicity
– A manageable set of features and constructs
– Few feature multiplicity (means of doing the same operation)
– Minimal operator overloading
Orthogonality
– A relatively small set of primitive constructs can be combined in a relatively
small number of ways
– Every possible combination is legal
Control statements
– The presence of well-known control structures (e.g., while statement)
Data types and structures
– The presence of adequate facilities for defining data structures
Syntax considerations
– Identifier forms: flexible composition
– Special words and methods of forming compound statements
– Form and meaning: self-descriptive constructs, meaningful keywords
Writability
Simplicity and Orthogonality
– Few constructs, a small number of primitives, a small set of rules for
combining them
Support for abstraction
– The ability to define and use complex structures or operations in ways that
allow details to be ignored
Expressivity
– A set of relatively convenient ways of specifying operations
– Example: the inclusion of for statement in many modern languages
Reliability
Type checking
– Testing for type errors
Exception handling
– Intercept run-time errors and take corrective measures
Aliasing
– Presence of two or more distinct referencing methods for the same memory
location
Readability and writability
– A language that does not support “natural” ways of expressing an algorithm
will necessarily use “unnatural” approaches, and hence reduced reliability
Cost
Training programmers to use language
Writing programs (closeness to particular applications)
Compiling programs
Executing programs
4
Language implementation system: availability of free compilers
Reliability: poor reliability leads to high costs
Maintaining programs
Others
Portability
– The ease with which programs can be moved from one implementation to
another
Generality
– The applicability to a wide range of applications
Well-definedness
– The completeness and precision of the language‘s official definition
5
1.3 Influences on Language Design - CO3
Computer Architecture
– Languages are developed around the prevalent computer architecture,
known as the von Neumann architecture
Programming Methodologies
– New software development methodologies (e.g., object-oriented software
development) led to new programming paradigms and by extension, new
programming languages
Computer Architecture
Well-known computer architecture: Von Neumann
Imperative languages, most dominant, because of von Neumann computers
– Data and programs stored in memory
– Memory is separate from CPU
– Instructions and data are piped from memory to CPU
– Basis for imperative languages
Variables model memory cells
Assignment statements model piping
Iteration is efficient
Programming Methodologies
1950s and early 1960s: Simple applications; worry about machine efficiency
Late 1960s: People efficiency became important; readability, better control
structures
– structured programming
– top-down design and step-wise refinement
Late 1970s: Process-oriented to data-oriented
– data abstraction
Middle 1980s: Object-oriented programming
– Data abstraction + inheritance + polymorphism
6
1.4 Language Categories – CO1
Imperative
– Central features are variables, assignment statements, and iteration
– Examples: C, Pascal
Functional
– Main means of making computations is by applying functions to given
parameters
– Examples: LISP, Scheme
Logic
– Rule-based (rules are specified in no particular order)
– Example: Prolog
Object-oriented
– Data abstraction, inheritance, late binding
– Examples: Java, C++
Markup
– New; not a programming per se, but used to specify the layout of information
in Web documents
– Examples: XHTML, XML
Pure Interpretation
No translation
Easier implementation of programs (run-time errors can easily and immediately
displayed)
Slower execution (10 to 100 times slower than compiled programs)
Often requires more space
Becoming rare on high-level languages
8
Significantly comeback with some latest web scripting languages (e.g.,
JavaScript)
9
Syntax and Semantics
Introduction
Syntax: the form or structure of the expressions, statements, and program
units
Semantics: the meaning of the expressions, statements, and program units
Syntax and semantics provide a language‘s definition
– Users of a language definition
– Other language designers
– Implementers
– Programmers (the users of the language)
Parse Tree
A hierarchical representation of a derivation
An example derivation Figure 2.1 Parse Tree
<program><stmts>
<stmt>
<var>=<expr>
a=<expr>
a=<term>+<term>
a=<var>+<term>
a=b+<term>
a=b+const
Derivation
Every string of symbols in the derivation is a sentential form
A sentence is a sentential form that has only terminal symbols
A leftmost derivation is one in which the leftmost nonterminal in each sentential
form is the one that is expanded
A derivation may be neither leftmost nor rightmost
Ambiguity in Grammars
A grammar is ambiguous iff it generates a sentential form that has two or more
distinct parse trees
An Unambiguous Expression Grammar
If we use the parse tree to indicate precedence levels of the operators, we cannot
have ambiguity
<expr> → <expr> - <term>|<term>
<term> → <term> / const|const
11
Figure 2.2 An Ambiguous Expression Grammar Figure 2.3 An Unambiguous Expression
Grammar
Definition
An attribute grammar is a context-free grammar G = (S, N, T, P) with the
following additions:
– For each grammar symbol x there is a set A(x) of attribute values
12
– Each rule has a set of functions that define certain attributes of the
nonterminals in the rule
– Each rule has a (possibly empty) set of predicates to check for attribute
consistency
– Let X0 X1 ... Xn be a rule
– Functions of the form S(X0) = f(A(X1), ... , A(Xn)) define synthesized attributes
– Functions of the form I(Xj) = f(A(X0), ... , A(Xn)), for i <= j <= n, define
inherited attributes
– Initially, there are intrinsic attributes on the leaves
Example
Syntax
<assign> → <var> = <expr>
<expr> → <var> + <var> | <var>
<var> → A | B | C
actual_type: synthesized for <var> and <expr>
expected_type: inherited for <expr>
Syntax rule :<expr> → <var>[1] + <var>[2]
Semantic rules :<expr>.actual_type → <var>[1].actual_type
Predicate :<var>[1].actual_type == <var>[2].actual_type
<expr>.expected_type == <expr>.actual_type
Syntax rule :<var> → id
Semantic rule :<var>.actual_type lookup (<var>.string)
How are attribute values computed?
– If all attributes were inherited, the tree could be decorated in top-down order.
– If all attributes were synthesized, the tree could be decorated in bottom-up
order.
– In many cases, both kinds of attributes are used, and it is some combination
of top-down and bottom-up that must be used.
<expr>.expected_type inherited from parent
<var>[1].actual_type lookup (A)
<var>[2].actual_type lookup (B)
<var>[1].actual_type =? <var>[2].actual_type
<expr>.actual_type <var>[1].actual_type
<expr>.actual_type =? <expr>.expected_type
13
Operational Semantics
A better alternative: A complete computer simulation
The process:
– Build a translator (translates source code to the machine code of an idealized
computer)
– Build a simulator for the idealized computer
Evaluation of operational semantics:
– Good if used informally (language manuals, etc.)
– Extremely complex if used formally (e.g., VDL), it was used for describing
semantics of PL/I.
Axiomatic Semantics
– Based on formal logic (predicate calculus)
– Original purpose: formal program verification
– Approach: Define axioms or inference rules for each statement type in the
language (to allow transformations of expressions to other expressions)
– The expressions are called assertions
Axiomatic Semantics
An assertion before a statement (a precondition) states the relationships and
constraints among variables that are true at that point in execution
An assertion following a statement is a postcondition
A weakest precondition is the least restrictive precondition that will guarantee
the postcondition
Pre-post form: {P} statement {Q}
An example: a = b + 1 {a > 1}
One possible precondition: {b > 10}
Weakest precondition: {b > 0}
Program proof process: The postcondition for the whole program is the desired
result. Work back through the program to the first statement. If the
precondition on the first statement is the same as the program spec, the
program is correct.
An axiom for assignment statements
(x = E):
{Qx->E} x = E {Q}
An inference rule for sequences
– For a sequence S1;S2:
– {P1} S1 {P2}
– {P2} S2 {P3}
An inference rule for logical pretest loops
For the loop construct:
{P} while B do S end {Q}
Characteristics of the loop invariant
I must meet the following conditions:
– P => I (the loop invariant must be true initially)
– {I} B {I} (evaluation of the Boolean must not change the validity of I)
– {I and B} S {I} (I is not changed by executing the body of the loop)
– (I and (not B)) => Q (if I is true and B is false, Q is implied)
– The loop terminates (this can be difficult to prove)
The loop invariant I is a weakened version of the loop postcondition, and it is
also a precondition.
14
I must be weak enough to be satisfied prior to the beginning of the loop, but
when combined with the loop exit condition, it must be strong enough to force
the truth of the postcondition.
Denotational Semantics
– Based on recursive function theory
– The most abstract semantics description method
– Originally developed by Scott and Strachey (1970)
– The process of building a denotational spec for a language (not necessarily
easy):
– Define a mathematical object for each language entity
– Define a function that maps instances of the language entities onto instances
of the corresponding mathematical objects
– The meaning of language constructs are defined by only the values of the
program's variables
– The difference between denotational and operational semantics: In
operational semantics, the state changes are defined by coded algorithms; in
denotational semantics, they are defined by rigorous mathematical functions
– The state of a program is the values of all its current variables
s = {<i1, v1>, <i2, v2>, …, <in, vn>}
– Let VARMAP be a function that, when given a variable name and a state,
returns the current value of the variable
VARMAP(ij, s) = vj
Decimal Numbers
– The following denotational semantics description maps decimal numbers as
strings of symbols into numeric values
<dec_num> → 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
| <dec_num> (0 | 1 | 2 | 3 | 4 |5 | 6 | 7 | 8 | 9)
Mdec('0') = 0, Mdec ('1') = 1, …, Mdec ('9') = 9
Mdec (<dec_num> '0') = 10 * Mdec (<dec_num>)
Mdec (<dec_num> '1’) = 10 * Mdec (<dec_num>) + 1
…
Mdec (<dec_num> '9') = 10 * Mdec (<dec_num>) + 9
Expressions
Map expressions onto Z {error}
We assume expressions are decimal numbers, variables, or binary expressions
having one arithmetic operator and two operands, each of which can be an
expression
Assignment Statements
– Maps state sets to state sets
Logical Pretest Loops
– Maps state sets to state sets
15
The meaning of the loop is the value of the program variables after the
statements in the loop have been executed the prescribed number of times,
assuming there have been no errors
In essence, the loop has been converted from iteration to recursion, where the
recursive control is mathematically defined by other recursive state mapping
functions
Recursion, when compared to iteration, is easier to describe with mathematical
rigor
Evaluation of denotational semantics
– Can be used to prove the correctness of programs
– Provides a rigorous way to think about programs
– Can be an aid to language design
– Has been used in compiler generation systems
– Because of its complexity, they are of little use to language users
Summary
BNF and context-free grammars are equivalent meta-languages
– Well-suited for describing the syntax of programming languages
An attribute grammar is a descriptive formalism that can describe both the
syntax and the semantics of a language
Three primary methods of semantics description
– Operation, axiomatic, denotational
16
UNIT-2
Data Types and Variables
Introduction
A data type defines a collection of data objects and a set of predefined
operations on those objects
A descriptor is the collection of the attributes of a variable
An object represents an instance of a user-defined (abstract data) type
One design issue for all data types: What operations are defined and how are
they specified?
Enumeration Types
All possible values, which are named constants, are provided in the definition
C# example
enum days {mon, tue, wed, thu, fri, sat, sun};
Design issues
– Is an enumeration constant allowed to appear in more than one type
definition, and if so, how is the type of an occurrence of that constant
checked?
– Are enumeration values coerced to integer?
– Any other type coerced to an enumeration type?
Subrange Types
An ordered contiguous subsequence of an ordinal type
– Example: 12..18 is a subrange of integer type
Ada‘s design
type Days is (mon, tue, wed, thu, fri, sat, sun);
subtype Weekdays is Days range mon..fri;
subtype Index is Integer range 1..100;
Day1: Days;
Day2: Weekday;
Day2 := Day1;
Subrange Evaluation
Aid to readability
– Make it clear to the readers that variables of subrange can store only certain
range of values
Reliability
– Assigning a value to a subrange variable that is outside the specified range is
detected as an error
Implementation
Enumeration types are implemented as integers
Subrange types are implemented like the parent types with code inserted (by the
compiler) to restrict assignments to subrange variables
19
Array Types
An array is an aggregate of homogeneous data elements in which an individual
element is identified by its position in the aggregate, relative to the first element.
Array Design Issues
What types are legal for subscripts?
Are subscripting expressions in element references range checked?
When are subscript ranges bound?
When does allocation take place?
What is the maximum number of subscripts?
Can array objects be initialized?
Are any kind of slices supported?
Array Indexing
Indexing (or subscripting) is a mapping from indices to elements
array_name (index_value_list)an element
Index Syntax
– FORTRAN, PL/I, Ada use parentheses
Ada explicitly uses parentheses to show uniformity between array references
and function calls because both are mappings
– Most other languages use brackets
Arrays Index (Subscript) Types
FORTRAN, C: integer only
Ada: integer or enumeration (includes Boolean and char)
Java: integer types only
Index range checking
– C, C++, Perl, and Fortran do not specify range checking
– Java, ML, C# specify range checking
– In Ada, the default is to require range checking, but it can be turned off
Subscript Binding and Array Categories
Static: subscript ranges are statically bound and storage allocation is static
(before run-time)
– Advantage: efficiency (no dynamic allocation)
Fixed stack-dynamic: subscript ranges are statically bound, but the allocation is
done at declaration time
– Advantage: space efficiency
Stack-dynamic: subscript ranges are dynamically bound and the storage
allocation is dynamic (done at run-time)
– Advantage: flexibility (the size of an array need not be known until the array
is to be used)
Fixed heap-dynamic: similar to fixed stack-dynamic: storage binding is dynamic
but fixed after allocation (i.e., binding is done when requested and storage is
allocated from heap, not stack)
Heap-dynamic: binding of subscript ranges and storage allocation is dynamic
and can change any number of times
– Advantage: flexibility (arrays can grow or shrink during program execution)
C and C++ arrays that include static modifier are static
C and C++ arrays without static modifier are fixed stack-dynamic
C and C++ provide fixed heap-dynamic arrays
C# includes a second array class ArrayList that provides fixed heap-dynamic
Perl, JavaScript, Python, and Ruby support heap-dynamic arrays
20
Array Initialization
Some language allow initialization at the time of storage allocation
– C, C++, Java, C# example
int list [] = {4, 5, 7, 83}
– Character strings in C and C++
char name [] = “freddie”;
– Arrays of strings in C and C++
char *names [] = {“Bob”, “Jake”, “Joe”};
– Java initialization of String objects
String[] names = {“Bob”, “Jake”, “Joe”};
Heterogeneous Arrays
A heterogeneous array is one in which the elements need not be of the same
type
Supported by Perl, Python, JavaScript, and Ruby
Arrays Operations
APL provides the most powerful array processing operations for vectors and
matrixes as well as unary operators (for example, to reverse column elements)
Ada allows array assignment but also catenation
Python‘s array assignments, but they are only reference changes. Python also
supports array catenation and element membership operations
Ruby also provides array catenation
Fortran provides elemental operations because they are between pairs of array
elements
– For example, + operator between two arrays results in an array of the sums
of the element pairs of the two arrays
Rectangular and Jagged Arrays
A rectangular array is a multi-dimensioned array in which all of the rows have
the same number of elements and all columns have the same number of
elements
A jagged matrix has rows with varying number of elements
– Possible when multi-dimensioned arrays actually appear as arrays of arrays
C, C++, and Java support jagged arrays
Fortran, Ada, and C# support rectangular arrays (C# also supports jagged
arrays)
Slices
A slice is some substructure of an array; nothing more than a referencing
mechanism
Slices are only useful in languages that have array operations
Implementation of Arrays
Access function maps subscript expressions to an address in the array
Access function for single-dimensioned arrays:
address(list[k]) = address (list[lower_bound])+((k-lower_bound) * element_size)
21
Accessing Multi-dimensioned Arrays Figure 3.4 Locating an Element
in a Multi-dimensioned Array
Two common ways:
– Row major order (by rows) – used in most
languages
– Column major order (by columns) – used in
Fortran
Compile-Time Descriptors
Associative Arrays
An associative array is an unordered collection of data elements that are
indexed by an equal number of values called keys
– User-defined keys must be stored
Design issues:
– What is the form of references to elements?
– Is the size static or dynamic?
Associative Arrays in Perl
Names begin with %; literals are delimited by parentheses
%hi_temps = ("Mon" => 77, "Tue" => 79, ―Wed‖ => 65, …);
Subscripting is done using braces and keys
$hi_temps{"Wed"} = 83;
Elements can be removed with delete
delete $hi_temps{"Tue"};
Unions Types
A union is a type whose variables are allowed to store different type values at
different times during execution
Design issues
– Should type checking be required?
– Should unions be embedded in records?
23
Ada Union Types Ada Union Type Illustrated
type Shape is (Circle, Triangle, Rectangle);
type Colors is (Red, Green, Blue);
type Figure (Form: Shape) is record
Filled: Boolean;
Color: Colors;
case Form is
when Circle => Diameter: Float;
when Triangle =>Leftside, Rightside: Integer;
Angle: Float;
when Rectangle => Side1, Side2: Integer;
end case;
end record; Figure 3.8 A Discriminated Union of
Three Shape Variables
Evaluation of Unions
Free unions are unsafe
– Do not allow type checking
Java and C# do not support unions
– Reflective of growing concerns for safety in programming language
Ada‘s descriminated unions are safe
Variable-Size Cells
All the difficulties of single-size cells plus more
Required by most programming languages
If mark-sweep is used, additional problems occur
– The initial setting of the indicators of all cells in the heap is difficult
– The marking process in nontrivial
– Maintaining the list of available space is another source of overhead
26
2.4 Names – CO2
Design issues for names:
– Maximum length?
– Are connector characters allowed?
– Are names case sensitive?
– Are special words reserved words or keywords?
Length
– If too short, they cannot be connotative
– Language examples:
o FORTRAN I: maximum 6
o COBOL: maximum 30
o FORTRAN 90 and ANSI C: maximum 31
o Ada and Java: no limit, and all are significant
o C++: no limit, but implementors often impose one
Connectors
– Pascal, Modula-2, and FORTRAN 77 don't allow
– Others do
Case sensitivity
– Disadvantage: readability (names that look alike are different)
o worse in C++ and Java because predefined names are mixed case (e.g.,
IndexOutOfBoundsException)
– C, C++, and Java names are case sensitive
– The names in other languages are not
Special words
– An aid to readability; used to delimit or separate statement clauses
– Def: A keyword is a word that is special only in certain contexts
o i.e. in Fortran:
– Real VarName (Real is data type followed with a name, therefore Real is
a keyword)
– Real = 3.4 (Real is a variable)
– Disadvantage: poor readability
– Def: A reserved word is a special word that cannot be used as a user-defined
name
Variables – CO2
A variable is an abstraction of a memory cell
Variables can be characterized as a sextuple of attributes:
(name, address, value, type, lifetime, and scope)
Name - not all variables have them (anonymous)
Address - the memory address with which it is associated (also called l-value)
– A variable may have different addresses at different times during execution
– A variable may have different addresses at different places in a program
– If two variable names can be used to access the same memory location, they
are called aliases
– Aliases are harmful to readability (program readers must remember all of
them)
How aliases can be created:
– Pointers, reference variables, C and C++ unions
– Some of the original justifications for aliases are no longer valid; e.g.,
memory reuse in FORTRAN
– Replace them with dynamic allocation
27
Type - determines the range of values of variables and the set of operations that
are defined for values of that type; in the case of floating point, type also
determines the Precision
Value - the contents of the location with which the variable is associated
Abstract memory cell - the physical cell or collection of cells associated with a
variable
29
Type Compatibility
Advantage of strong typing: allows the detection of the misuses of variables that
result in type errors
Language examples:
– FORTRAN 77 is not: parameters, EQUIVALENCE
– Pascal is not: variant records
– C and C++ are not: parameter type checking can be avoided; unions are not
type checked
– Ada is, almost (UNCHECKED CONVERSION is loophole)
(Java is similar)
Coercion rules strongly affect strong typing--they can weaken it considerably
(C++ versus Ada)
Although Java has just half the assignment coercions of C++, its strong typing
is still far less effective than that of Ada
30
Named Constants
Def: A named constant is a variable that is bound to a value only when it is
bound to storage
Advantages: readability and modifiability
Used to parameterize programs
The binding of values to named constants can be either static (called manifest
constants) or dynamic
Languages:
– Pascal: literals only
– FORTRAN 90: constant-valued expressions
– Ada, C++, and Java: expressions of any kind
Variable Initialization
Def: The binding of a variable to a value at the time it is bound to storage is
called initialization
Initialization is often done on the declaration statement e.g., Java int sum = 0
Summary
The data types of a language are a large part of what determines that language‘s
style and usefulness
The primitive data types of most imperative languages include numeric,
character, and Boolean types
The user-defined enumeration and subrange types are convenient and add to
the readability and reliability of programs
Arrays and records are included in most languages
Pointers are used for addressing flexibility and to control dynamic storage
management
Case sensitivity and the relationship of names to special words represent design
issues of names
Variables are characterized by the sextuples: name, address, value, type,
lifetime, scope
Binding is the association of attributes with program entities
Scalar variables are categorized as: static, stack dynamic, explicit heap
dynamic, implicit heap dynamic
Strong typing means detecting all type errors
31
Expressions and Statements & Control Structures
Introduction
Expressions are the fundamental means of specifying computations in a
programming language.
To understand expression evaluation, need to be familiar with the orders of
operator and operand evaluation.
Essence of imperative languages is dominant role of assignment statements
Arithmetic Expressions.
Arithmetic evaluation was one of the motivations for the development of the first
programming languages.
Conditional Expressions
32
Conditional Expressions (ternary operator ?:) available in C-based languages.
An example: (C, C++)
average = (count == 0)? 0 : sum/count
Evaluates as if written like
if (count == 0)
average = 0
else
average = sum /count
Operand Evaluation Order
Operand evaluation order as follows.
Variables: fetch the value from memory.
Constants: sometimes a fetch from memory; sometimes the constant is in the
machine language instruction.
Parenthesized expressions: evaluate all operands and operators first.
The most interesting case is when an operand is a function call.
Potentials for Side Effects Functional side effects: when a function changes a two-
way parameter or a non-local variable
Problem with functional side effects: When a function referenced in an
expression alters another operand of the expression;
e.g., for a parameter change:
a = 10;
/* assume that fun changes its parameter */
b = a + fun(a);
Two possible solutions to the functional side effects problem: Write the language
definition to disallow functional side effects.
No two-way parameters in functions
No non-local references in functions
Advantage: it works!
Disadvantages: inflexibility of one-way parameters and lack of non-local references
– Write the language definition to demand that operand evaluation order be fixed.
Disadvantage: limits some compiler optimizations
– Java requires that operands appear to be evaluated in left-to-right order.
Overloaded Operators
Use of an operator for more than one purpose is called operator overloading.
Some are common (e.g., + for int and float)
Some are potential trouble (e.g., * in C and C++)
Problems:
Loss of compiler error detection (omission of an operand should be a detectable
error)
Some loss of readability
Can be avoided by introduction of new symbols (e.g., Pascal‘s div for integer
division)
C++, Ada, Fortran 95, and C# allow user-defined overloaded operators
Potential problems:
Users can define nonsense operations.
Readability may suffer, even when the operators make sense.
33
Type Conversions
A narrowing conversion is one that converts an object to a type that cannot
include all of the values of the original type.
e.g., float to int
A widening conversion is one in which an object is converted to a type that can
include at least approximations to all of the values of the original type.
e.g., int to float
Mixed Mode
A mixed-mode expression is one that has operands of different types
A coercion is an implicit type conversion
Disadvantage of coercions:
– They decrease in the type error detection ability of the compiler
In most languages, all numeric types are coerced in expressions, using widening
conversions.
In Ada, there are virtually no coercions in expressions
Explicit Type Conversions called as casting in C-based languages.
Examples:-
C: (int)angle, Ada: Float (Sum)
– Note that Ada’s syntax is similar to that of function calls
Errors in Expressions causes
Inherent limitations of arithmetic e.g., division by zero
Limitations of computer arithmetic e.g., overflow
Often ignored by the run-time system
Assignment as an Expression
In C, C++, and Java, the assignment statement produces a result and can be
used as operands.
while ((ch = getchar())!= EOF){…}
ch = getchar() is carried out; the result (assigned to ch) is used as a conditional
value for the while statement
List Assignments
Perl and Ruby support list assignments
e.g., ($first, $second, $third) = (20, 30, 40);
35
Mixed-Mode Assignment
Assignment statements can also be mixed-mode, for example
int a, b;
float c;
c = a / b;
– In Fortran, C, and C++, any numeric type value can be assigned to any numeric
type variable.
– In Java, only widening assignment coercions are done.
– In Ada, there is no assignment coercion.
37
default clause is for unrepresented values (if there is no default, the whole
statement does nothing)
C#
– Differs from C in that it has a static semantics rule that disallows the
implicit execution of more than one segment
– Each selectable segment must end with an unconditional branch (goto or
break)
Ada
case expression is
when choice list => stmt_sequence;
…
when choice list => stmt_sequence;
when others => stmt_sequence;]
end case;
More reliable than C‘s switch (once a stmt_sequence execution is completed, control is
passed to the first statement after the case statement
Ada design choices:
1. Expression can be any ordinal type
2. Segments can be single or compound
3. Only one segment can be executed per execution of the construct
4. Unrepresented values are not allowed
Constant List Forms:
1. A list of constants
2. Can include:
- Subranges
- Boolean OR operators (|)
Iterative Statements
The repeated execution of a statement or compound statement is accomplished
either by iteration or recursion
General design issues for iteration control statements:
1. How is iteration controlled?
2. Where is the control mechanism in the loop?
Counter-Controlled Loops
A counting iterative statement has a loop variable, and a means of specifying
the initial and terminal, and stepsize values
Design Issues:
What are the type and scope of the loop variable?
What is the value of the loop variable at loop termination?
Should it be legal for the loop variable or loop parameters to be changed in the
loop body, and if so, does the change affect loop control?
Should the loop parameters be evaluated only once, or once for every iteration?
38
Iterative Statements: Examples
FORTRAN 95 syntax
DO label var = start, finish [, stepsize]
Stepsize can be any value but zero
Parameters can be expressions
Design choices:
1. Loop variable must be INTEGER
2. Loop variable always has its last value
3. The loop variable cannot be changed in the loop, but the parameters can; because
they are evaluated only once, it does not affect loop control
4. Loop parameters are evaluated only once
FORTRAN 95 : a second form:
[name:] Do variable = initial, terminal [,stepsize]
…
End Do [name]
– Cannot branch into either of Fortran‘s Do statements
Ada
for var in [reverse] discrete_range loop ...
end loop
Design choices:
– Type of the loop variable is that of the discrete range (A discrete range is a
sub-range of an integer or enumeration type).
– Loop variable does not exist outside the loop
– The loop variable cannot be changed in the loop, but the discrete range can;
it does not affect loop control
– The discrete range is evaluated just once
– Cannot branch into the loop body
C-based languages
for ([expr_1] ; [expr_2] ; [expr_3]) statement
– The expressions can be whole statements, or even statement sequences,
with the statements separated by commas
– The value of a multiple-statement expression is the value of the last
statement in the expression
– If the second expression is absent, it is an infinite loop
Design choices:
– There is no explicit loop variable
– Everything can be changed in the loop
– The first expression is evaluated once, but the other two are evaluated with
each iteration
C++ differs from C in two ways:
– The control expression can also be Boolean
– The initial expression can include variable definitions (scope is from the
definition to the end of the loop body)
Java and C#
– Differs from C++ in that the control expression must be Boolean
– Iterative Statements: Logically-Controlled Loops
– Repetition control is based on a Boolean expression
Design issues:
– Pretest or posttest?
– Should the logically controlled loop be a special case of the counting loop
statement or a separate statement?
39
Iterative Statements: Logically-Controlled Loops: Examples
C and C++ have both pretest and posttest forms, in which the control
expression can be arithmetic:
while (ctrl_expr) do
loop body loop body
while (ctrl_expr)
Java is like C and C++, except the control expression must be Boolean (and the
body can only be entered at the beginning -- Java has no goto
Iterative Statements: Logically-Controlled Loops: Examples
Ada has a pretest version, but no posttest
FORTRAN 95 has neither
Perl and Ruby have two pretest logical loops, while and until. Perl also has two
posttest loops
40
Guarded Commands
Designed by Dijkstra
Purpose: to support a new programming methodology that supported
verification (correctness) during development
Basis for two linguistic mechanisms for concurrent programming (in CSP and
Ada)
Basic Idea: if the order of evaluation is not important, the program should not
specify one
Selection Guarded Command
•Form
if <Boolean exp> -> <statement>
[] <Boolean exp> -> <statement>
...
[] <Boolean exp> -> <statement>
fi
Semantics: when construct is reached,
Evaluate all Boolean expressions
If more than one are true, choose one non-deterministically
If none are true, it is a runtime error
Summary
Expressions
Operator precedence and associativity
Operator overloading
Mixed-type expressions
Various forms of assignment
Variety of statement-level structures
Choice of control statements beyond selection and logical pretest loops is a
trade-off between language size and writability
Functional and logic programming languages are quite different control
structures
41
UNIT-3
Subprograms and Blocks
Introduction
Two fundamental abstraction facilities
– Process abstraction
Emphasized from early days
– Data abstraction
Emphasized in the1980s
Scope Example
MAIN
- declaration of x
SUB1
- declaration of x -
...
call SUB2
...
SUB2
...
- reference to x -
...
...
call SUB1
…
Static scoping
– Reference to x is to MAIN's x
Dynamic scoping
– Reference to x is to SUB1's x
Evaluation of Dynamic Scoping:
– Advantage: convenience
– Disadvantage: poor readability
The value of the actual parameter is used to initialize the corresponding formal
parameter
– Normally implemented by copying
– Can be implemented by transmitting an access path but not recommended
(enforcing write protection is not easy)
– When copies are used, additional storage is required
– Storage and copy operations can be costly
45
Pass-by-Reference (Inout Mode)
Pass an access path
Also called pass-by-sharing
Passing process is efficient (no copying and no duplicated storage)
Disadvantages
– Slower accesses (compared to pass-by-value) to formal parameters
– Potentials for un-wanted side effects
– Un-wanted aliases (access broadened)
Pass-by-Name (Inout Mode)
By textual substitution
Formals are bound to an access method at the time of the call, but actual
binding to a value or address takes place at the time of a reference or
assignment
Allows flexibility in late binding
Implementing Parameter-Passing Methods
In most language parameter communication takes place thru the run-time
stack
Pass-by-reference are the simplest to implement; only an address is placed in
the stack
A subtle but fatal error can occur with pass-by-reference and pass-by-value
result: a formal parameter corresponding to a constant can mistakenly be
changed
Parameter Passing Methods of Major Languages
Fortran
– Always used the inout semantics model
– Before Fortran 77: pass-by-reference
– Fortran 77 and later: scalar variables are often passed by value-result
C
– Pass-by-value
– Pass-by-reference is achieved by using pointers as parameters
C++
– A special pointer type called reference type for pass-by-reference
Java
– All parameters are passed are passed by value
– Object parameters are passed by reference
Ada
– Three semantics modes of parameter transmission: in, out, in out; in is the
default mode
– Formal parameters declared out can be assigned but not referenced; those
declared in can be referenced but not assigned; in out parameters can be
referenced and assigned
C#
– Default method: pass-by-value
– Pass-by-reference is specified by preceding both a formal parameter and its
actual parameter with ref
PHP: very similar to C#
Perl: all actual parameters are implicitly placed in a predefined array named @_
Type Checking Parameters
Considered very important for reliability
FORTRAN 77 and original C: none
Pascal, FORTRAN 90, Java, and Ada: it is always required
46
ANSI C and C++: choice is made by the user
– Prototypes
Relatively new languages Perl, JavaScript, and PHP do not require type checking
Multidimensional Arrays as Parameters
If a multidimensional array is passed to a subprogram and the subprogram is
separately compiled, the compiler needs to know the declared size of that array
to build the storage mapping function
Multidimensional Arrays as Parameters: C and C++
Programmer is required to include the declared sizes of all but the first
subscript in the actual parameter
Disallows writing flexible subprograms
Solution: pass a pointer to the array and the sizes of the dimensions as other
parameters; the user must include the storage mapping function in terms of the
size parameters
Multidimensional Arrays as Parameters: Pascal and Ada
Pascal
– Not a problem; declared size is part of the array‘s type
Ada
– Constrained arrays - like Pascal
– Unconstrained arrays - declared size is part of the object declaration
Multidimensional Arrays as Parameters: Fortran
Formal parameter that are arrays have a declaration after the header
– For single-dimension arrays, the subscript is irrelevant
– For multi-dimensional arrays, the subscripts allow the storage-mapping
function
Multidimensional Arrays as Parameters: Java and C#
Similar to Ada
Arrays are objects; they are all single-dimensioned, but the elements can be
arrays
Each array inherits a named constant (length in Java, Length in C#) that is set
to the length of the array when the array object is created
Figure 5.2 Possible Execution Controls Figure 5.3 Possible Execution Controls
49
UNIT-4
Abstract Data Types
50
– The representation of the abstract type appears in a part of the specification
called the private part
More restricted form with limited private types
– Private types have built-in operations for assignment and comparison
– Limited private types have NO built-in operations
Reasons for the public/private spec package:
1. The compiler must be able to see the representation after seeing only the
spec package (it cannot see the private part)
2. Clients must see the type name, but not the representation (they also
cannot see the private part)
Having part of the implementation details (the representation) in the spec
package and part (the method bodies) in the body package is not good
52
Language Examples: C#
Based on C++ and Java
Adds two access modifiers, internal and protected internal
All class instances are heap dynamic
Default constructors are available for all classes
Garbage collection is used for most heap objects, so destructors are rarely used
structs are lightweight classes that do not support inheritance
Common solution to need for access to data members: accessor methods(getter
and setter)
C# provides properties as a way of implementing getters and setters without
requiring explicit method calls
C# Property Example
public class Weather {
public int DegreeDays { //** DegreeDays is a property
get {return degreeDays;}
set {
if(value < 0 || value > 30)
Console.WriteLine("Value is out of range: {0}", value);
else degreeDays = value;}
}
private int degreeDays;
...
}
...
Weather w = new Weather();
int degreeDaysToday, oldDegreeDays;
...
w.DegreeDays = degreeDaysToday;
...
oldDegreeDays = w.DegreeDays;
54
Inheritance addresses both of the above concerns--reuse ADTs after minor
changes and define classes in a hierarchy
Object-Oriented Concepts
ADTs are usually called classes
Class instances are called objects
A class that inherits is a derived class or a subclass
The class from which another class inherits is a parent class or superclass
Subprograms that define operations on objects are called methods
Calls to methods are called messages
The entire collection of methods of an object is called its message protocol or
message interface
Messages have two parts--a method name and the destination object
In the simplest case, a class inherits all of the entities of its parent
Inheritance can be complicated by access controls to encapsulated entities
– A class can hide entities from its subclasses
– A class can hide entities from its clients
– A class can also hide entities for its clients while allowing its subclasses to
see them
Besides inheriting methods as is, a class can modify an inherited method
– The new one overrides the inherited one
– The method in the parent is overriden
There are two kinds of variables in a class:
– Class variables - one/class
– Instance variables - one/object
There are two kinds of methods in a class:
– Class methods – accept messages to the class
– Instance methods – accept messages to objects
Single vs. Multiple Inheritance
One disadvantage of inheritance for reuse:
– Creates interdependencies among classes that complicate maintenance
Dynamic Binding
A polymorphic variable can be defined in a class that is able to reference (or
point to) objects of the class and objects of any of its descendants
When a class hierarchy includes classes that override methods and such
methods are called through a polymorphic variable, the binding to the correct
method will be dynamic
Allows software systems to be more easily extended during both development
and maintenance
Dynamic Binding Concepts
An abstract method is one that does not include a definition (it only defines a
protocol)
An abstract class is one that includes at least one virtual method
An abstract class cannot be instantiated
Concurrency
Concurrency can occur at four levels:
– Machine instruction level
– High-level language statement level
– Unit level
– Program level
Because there are no language issues in instruction- and program-level
concurrency, they are not addressed here
61
Multiprocessor Architectures
Late 1950s - one general-purpose processor and one or more special purpose
processors for input and output operations
Early 1960s - multiple complete processors, used for program-level concurrency
Mid-1960s - multiple partial processors, used for instruction-level concurrency
Single-Instruction Multiple-Data (SIMD) machines
Multiple-Instruction Multiple-Data (MIMD) machines
– Independent processors that can be synchronized (unit-level concurrency)
Categories of Concurrency
A thread of control in a program is the sequence of program points reached as
control flows through the program
Categories of Concurrency:
– Physical concurrency - Multiple independent processors (multiple threads of
control)
– Logical concurrency - The appearance of physical concurrency is presented by
time-sharing one processor (software can be designed as if there were
multiple threads of control)
Coroutines (quasi-concurrency) have a single thread of control
Motivations for Studying Concurrency
Involves a different way of designing software that can be very useful— many
real-world situations involve concurrency
Multiprocessor computers capable of physical concurrency are now widely used
Subprogram-Level Concurrency
A task or process is a program unit that can be in concurrent execution with
other program units
Tasks differ from ordinary subprograms in that:
– A task may be implicitly started
– When a program unit starts the execution of a task, it is not necessarily
suspended
– When a task‘s execution is completed, control may not return to the caller
Tasks usually work together
Two General Categories of Tasks
Heavyweight tasks execute in their own address space
Lightweight tasks all run in the same address space
A task is disjoint if it does not communicate with or affect the execution of any
other task in the program in any way
Task Synchronization
A mechanism that controls the order in which tasks execute
Two kinds of synchronization
– Cooperation synchronization
– Competition synchronization
Task communication is necessary for synchronization, provided by:
– Shared nonlocal variables
– Parameters
– Message passing
Kinds of synchronization
Cooperation: Task A must wait for task B to complete some specific activity
before task A can continue its execution, e.g., the producer-consumer problem
62
Competition: Two or more tasks must use some resource that cannot be
simultaneously used, e.g., a shared counter
– Competition is usually provided by mutually exclusive access (approaches
are discussed later)
–
Semaphores
Dijkstra - 1965
A semaphore is a data structure consisting of a counter and a queue for storing
task descriptors
Semaphores can be used to implement guards on the code that accesses shared
data structures
Semaphores have only two operations, wait and release (originally called P and
V by Dijkstra)
63
Semaphores can be used to provide both competition and cooperation
synchronization
Cooperation Synchronization with Semaphores
Example: A shared buffer
The buffer is implemented as an ADT with the operations DEPOSIT and FETCH
as the only ways to access the buffer
Use two semaphores for cooperation: emptyspots and fullspots
The semaphore counters are used to store the numbers of empty spots and full
spots in the buffer
DEPOSIT must first check emptyspots to see if there is room in the buffer
If there is room, the counter of emptyspots is decremented and the value is
inserted
If there is no room, the caller is stored in the queue of emptyspots
When DEPOSIT is finished, it must increment the counter of fullspots
FETCH must first check fullspots to see if there is a value
– If there is a full spot, the counter of fullspots is decremented and the value is
removed
– If there are no values in the buffer, the caller must be placed in the queue of
fullspots
– When FETCH is finished, it increments the counter of emptyspots
The operations of FETCH and DEPOSIT on the semaphores are accomplished
through two semaphore operations named wait and release
64
Producer Consumer Code
task consumer;
loop
wait (fullspots);{wait till not empty}}
FETCH(VALUE);
release(emptyspots); {increase empty}
-- consume VALUE –-
end loop;
end consumer;
Competition Synchronization with Semaphores
A third semaphore, named access, is used to control access (competition
synchronization)
– The counter of access will only have the values 0 and 1
– Such a semaphore is called a binary semaphore
Note that wait and release must be atomic!
Producer Consumer Code
semaphore access, fullspots, emptyspots;
access.count = 0;
fullstops.count = 0;
emptyspots.count = BUFLEN;
task producer;
loop
-- produce VALUE –-
wait(emptyspots); {wait for space}
wait(access); {wait for access)
DEPOSIT(VALUE);
release(access); {relinquish access}
release(fullspots); {increase filled}
end loop;
end producer;
Monitors
Ada, Java, C#
The idea: encapsulate the shared data and its operations to restrict access
A monitor is an abstract data type for shared data
Competition Synchronization
Shared data is resident in the monitor (rather than in the client units)
All access resident in the monitor
65
–Monitor implementation guarantee synchronized access by allowing only one
access at a time
– Calls to monitor procedures are implicitly queued if the monitor is busy at
the time of the call
Cooperation Synchronization
Cooperation between processes is still a programming task
– Programmer must guarantee that a shared buffer does not experience
underflow or overflow
Message Passing
Message passing is a general model for concurrency
– It can model both semaphores and monitors
– It is not just for competition synchronization
Central idea: task communication is like seeing a doctor--most of the time she
waits for you or you wait for her, but when you are both ready, you get together,
or rendezvous
Message Passing Rendezvous
To support concurrent tasks with message passing, a language needs:
– A mechanism to allow a task to indicate when it is willing to accept messages
– A way to remember who is waiting to have its message accepted and some
“fair” way of choosing the next message
When a sender task‘s message is accepted by a receiver task, the actual
message transmission is called a rendezvous
66
Task Body
The body task describes the action that takes place when a rendezvous occurs
A task that sends a message is suspended while waiting for the message to be
accepted and during the rendezvous
Entry points in the spec are described with accept clauses in the body accept
entry_name (formal parameters) do
…
end entry_name
67
Figure 6.4 Graphical Representation of a Rendezvous
68
Cooperation Synchronization with Message Passing
Provided by Guarded accept clauses
when not Full(Buffer) =>
accept Deposit (New_Value) do
An accept clause with a with a when clause is either open or closed
– A clause whose guard is true is called open
– A clause whose guard is false is called closed
– A clause without a guard is always open
Binary Semaphores
For situations where the data to which access is to be controlled is NOT
encapsulated in a task
task Binary_Semaphore is
entry Wait;
entry release;
end Binary_Semaphore;
task body Binary_Semaphore is
begin
loop
accept Wait;
accept Release;
end loop;
end Binary_Semaphore;
Concurrency in Ada 95
Ada 95 includes Ada 83 features for concurrency, plus two new features
– Protected objects: A more efficient way of implementing shared data to allow
access to a shared data structure to be done without rendezvous
– Asynchronous communication
Asynchronous Communication
Provided through asynchronous select structures
An asynchronous select has two triggering alternatives, an entry clause or a
delay
– The entry clause is triggered when sent a message
– The delay clause is triggered when its time limit is reached
70
Evaluation of the Ada
Message passing model of concurrency is powerful and general
Protected objects are a better way to provide synchronized shared data
In the absence of distributed processors, the choice between monitors and tasks
with message passing is somewhat a matter of taste
For distributed systems, message passing is a better model for concurrency
Java Threads
The concurrent units in Java are methods named run
– A run method code can be in concurrent execution with other such methods
– The process in which the run methods execute is called a thread
Class myThread extends Thread{
public void run () {…}
}
…
Thread myTh = new MyThread ();
myTh.start();
Thread Priorities
A thread‘s default priority is the same as the thread that create it
– If main creates a thread, its default priority is NORM_PRIORITY
Threads defined two other priority constants, MAX_PRIORITY and
MIN_PRIORITY
The priority of a thread can be changed with the methods setPriority
71
The notify method is called to tell one waiting thread that the event it was
waiting has happened
The notifyAll method awakens all of the threads on the object‘s wait list
C# Threads
Loosely based on Java but there are significant differences
Basic thread operations
– Any method can run in its own thread
– A thread is created by creating a Thread object
– Creating a thread does not start its concurrent execution; it must be
requested through the Start method
– A thread can be made to wait for another thread to finish with Join
– A thread can be suspended with Sleep
– A thread can be terminated with Abort
Synchronizing Threads
Three ways to synchronize C# threads
– The Interlocked class
Used when the only operations that need to be synchronized are incrementing
or decrementing of an integer
– The lock statement
Used to mark a critical section of code in a thread lock (expression) {… }
– The Monitor class
Provides four methods that can be used to provide more sophisticated
synchronization
C#’s Concurrency Evaluation
An advance over Java threads, e.g., any method can run its own thread
Thread termination is cleaner than in Java
Synchronization is more sophisticated
Statement-Level Concurrency
Objective: Provide a mechanism that the programmer can use to inform
compiler of ways it can map the program onto multiprocessor architecture
Minimize communication among processors and the memories of the other
processors
High-Performance Fortran
A collection of extensions that allow the programmer to provide information to
the compiler to help it optimize code for multiprocessor computers
Specify the number of processors, the distribution of data over the memories of
those processors, and the alignment of data
Primary HPF Specifications
Number of processors
!HPF$ PROCESSORS procs (n)
Distribution of data
!HPF$ DISTRIBUTE (kind) ONTO procs :: identifier_list
– kind can be BLOCK (distribute data to processors in blocks) or
CYCLIC (distribute data to processors one element at a time)
72
Relate the distribution of one array with that of another
ALIGN array1_element WITH array2_element
Statement-Level Concurrency Example
REAL list_1(1000), list_2(1000)
INTEGER list_3(500), list_4(501)
!HPF$ PROCESSORS proc (10)
!HPF$ DISTRIBUTE (BLOCK) ONTO procs ::
list_1, list_2
!HPF$ ALIGN list_1(index) WITH
list_4 (index+1)
…
list_1 (index) = list_2(index)
list_3(index) = list_4(index+1)
FORALL statement is used to specify a list of statements that may be executed
concurrently
FORALL (index = 1:1000)
list_1(index) = list_2(index)
Specifies that all 1,000 RHSs of the assignments can be evaluated before any
assignment takes place
Summary
Concurrent execution can be at the instruction, statement, or subprogram level
Physical concurrency: when multiple processors are used to execute concurrent
units
Logical concurrency: concurrent united are executed on a single processor
Two primary facilities to support subprogram concurrency: competition
synchronization and cooperation synchronization
Mechanisms: semaphores, monitors, rendezvous, threads
High-Performance Fortran provides statements for specifying how data is to be
distributed over the memory units connected to multiple processors
73
Exception Handling & Logic Programming Language
Design Issues
How are user-defined exceptions specified?
Should there be default exception handlers for programs that do not provide
their own?
Can built-in exceptions be explicitly raised?
Are hardware-detectable errors treated as exceptions that can be handled?
Are there any built-in exceptions?
How can exceptions be disabled, if at all?
How and where exception handlers specified and what are their scope?
How is an exception occurrence bound to an exception handler?
Can information about the exception be passed to the handler?
Where does execution continue, if at all, after an exception handler completes
its execution? (continuation vs. resumption)
Is some form of finalization provided?
74
Figure 7.1 Exception Handling Control Flow
Throwing Exceptions
Exceptions are all raised explicitly by the statement: throw [expression];
The brackets are metasymbols
A throw without an operand can only appear in a handler; when it appears, it
simply re-raises the exception, which is then handled elsewhere
The type of the expression disambiguates the intended handler
Unhandled Exceptions
An unhandled exception is propagated to the caller of the function in which it is
raised
This propagation continues to the main function
Continuation
After a handler completes its execution, control flows to the first statement after
the last handler in the sequence of handlers of which it is an element
Other design choices
76
– All exceptions are user-defined
– Exceptions are neither specified nor declared
– Functions can list the exceptions they may raise
– Without a specification, a function can raise any exception (the throw clause)
Evaluation
It is odd that exceptions are not named and that hardware- and system
software-detectable exceptions cannot be handled
Binding exceptions to handlers through the type of the parameter certainly does
not promote readability
77
Other Design Choices
A method cannot declare more exceptions in its throws clause than the method
it overrides
A method that calls a method that lists a particular checked exception in its
throws clause has three alternatives for dealing with that exception:
– Catch and handle the exception
– Catch the exception and throw an exception that is listed in its own throws
clause
– Declare it in its throws clause and do not handle it
The finally Clause
Can appear at the end of a try construct
Form:
finally {..}
Purpose: To specify code that is to be executed, regardless of what happens in
the try construct
Example
A try construct with a finally clause can be used outside exception handling
try {
for (index = 0; index < 100; index++) {
…
if (…) {
return;
} //** end of if
} //** end of try clause
finally {
…
} //** end of try construct
Assertions
Statements in the program declaring a boolean expression regarding the current
state of the computation
When evaluated to true nothing happens
When evaluated to false an AssertionError exception is thrown
Can be disabled during runtime without program modification or recompilation
Two forms
– assert condition;
– assert condition: expression;
Evaluation
The types of exceptions makes more sense than in the case of C++
The throws clause is better than that of C++ (The throw clause in C++ says little
to the programmer)
The finally clause is often useful
The Java interpreter throws a variety of exceptions that can be handled by user
programs
Summary of Exception Handling
Ada provides extensive exception-handling facilities with a comprehensive set of
built-in exceptions.
C++ includes no predefined exceptions. Exceptions are bound to handlers by
connecting the type of expression in the throw statement to that of the formal
parameter of the catch function
Java exceptions are similar to C++ exceptions except that a Java exception must
be a descendant of the Throwable class. Additionally Java includes a finally
clause
78
4.14 Logic Programming Introduction CO4
Logic programming languages, sometimes called declarative programming
languages
Express programs in a form of symbolic logic
Use a logical inferencing process to produce results
Declarative rather that procedural:
– Only specification of results are stated (not detailed procedures for producing
them)
Proposition
A logical statement that may or may not be true
– Consists of objects and relationships of objects to each other
Symbolic Logic
Logic which can be used for the basic needs of formal logic:
– Express propositions
– Express relationships between propositions
– Describe how new propositions can be inferred from other propositions
Particular form of symbolic logic used for logic programming called predicate
calculus
Object Representation
Objects in propositions are represented by simple terms: either constants or
variables
Constant: a symbol that represents an object
Variable: a symbol that can represent different objects at different times
– Different from variables in imperative languages
Compound Terms
Atomic propositions consist of compound terms
Compound term: one element of a mathematical relation, written like a
mathematical function
– Mathematical function is a mapping
– Can be written as a table
Forms of a Proposition
Propositions can be stated in two forms:
– Fact: proposition is assumed to be true
– Query: truth of proposition is to be determined
Compound proposition:
– Have two or more atomic propositions
– Propositions are connected by operators
79
Logical Operators
Name Symbol Example Meaning
Negation a a not b
Conjunction ab a and b
Disjunction ab a or b
Equivalence ab a is equivalent to b
ab a implies b
Implication
ab b implies a
Quantifiers
Name Example Meaning
universal X.P For all X, P is true
existential X.P There exists a value of X such that P is true
Clausal Form
Too many ways to state the same thing
Use a standard form for propositions
Clausal form:
– B1 B2 … Bn A1 A2 … Am
– means if all the As are true, then at least one B is true
Antecedent: right side
Consequent: left side
Predicate Calculus and Proving Theorems
A use of propositions is to discover new theorems that can be inferred from
known axioms and theorems
Resolution: an inference principle that allows inferred propositions to be
computed from given propositions
Resolution
Unification: finding values for variables in propositions that allows matching
process to succeed
Instantiation: assigning temporary values to variables to allow unification to
succeed
After instantiating a variable with a value, if matching fails, may need to
backtrack and instantiate with a different value
Theorem Proving
Basis for logic programming
When propositions used for resolution, only restricted form can be used
Horn clause - can have only two forms
– Headed: single atomic proposition on left side
– Headless: empty left side (used to state facts)
Most propositions can be stated as Horn clauses
trace.
likes(jake,X),
likes(darcie,X).
List Structures
Other basic data structure (besides atomic propositions we have already seen):
list
List is a sequence of any number of elements
Elements can be atoms, atomic propositions, or other terms (including other
lists)
[apple, prune, grape, kumquat]
[] (empty list)
[X | Y] (head X and tail Y)
Append Example
append([], List, List).
append([Head | List_1], List_2, [Head | List_3]) :-
append (List_1, List_2, List_3).
Reverse Example
reverse([], []).
reverse([Head | Tail], List) :-
reverse (Tail, Result),
append (Result, [Head], List).
Deficiencies of Prolog
Resolution order control
The closed-world assumption
The negation problem
Intrinsic limitations
83
UNIT-5
Functional Programming Languages & Scripting Language
Mathematical Functions
A mathematical function is a mapping of members of one set, called the domain
set, to another set, called the range set
A lambda expression specifies the parameter(s) and the mapping of a function in
the following form
(x) x * x * x
for the function cube (x) = x * x * x
Lambda Expressions
Lambda expressions describe nameless functions
Lambda expressions are applied to parameter(s) by placing the parameter(s)
after the expression
e.g., ((x) x * x * x)(2)
which evaluates to 8
Functional Forms
A higher-order function, or functional form, is one that either takes functions as
parameters or yields a function as its result, or both
Function Composition
A functional form that takes two functions as parameters and yields a function
whose value is the first actual parameter function applied to the application of
the second
Form: h f ° g
which means h(x)f(g(x))
For f (x)x + 2 and g (x)3 * x,
hf ° g yields (3 * x)+ 2
Apply-to-all
A functional form that takes a single function as a parameter and yields a list of
values obtained by applying the given function to each element of a list of
parameters
Form:
For h (x) x * x
(h, (2, 3, 4)) yields (4, 9, 16)
5.3 ML – CO5
A static-scoped functional language with syntax that is closer to Pascal than to
LISP
Uses type declarations, but also does type inferencing to determine the types of
undeclared variables
It is strongly typed (whereas Scheme is essentially typeless) and has no type
coercions
Includes exception handling and a module facility for implementing abstract
data types
Includes lists and list operations
ML Specifics
Function declaration form:
fun name (parameters) = body;
e.g., fun cube (x : int) = x * x * x;
– The type could be attached to return value, as in
fun cube (x) : int = x * x * x;
– With no type specified, it would default to
int (the default for numeric values)
– User-defined overloaded functions are not allowed, so if we wanted a cube
function for real parameters, it would need to have a different name
– There are no type coercions in ML
ML selection
if expression then then_expression
else else_expression
85
where the first expression must evaluate to a Boolean value
Pattern matching is used to allow a function to operate on different parameter
forms
fun fact(0) = 1
| fact(n : int) : int =n * fact(n – 1)
Lists
Literal lists are specified in brackets
[3, 5, 7]
[] is the empty list
CONS is the binary infix operator, ::
4 :: [3, 5, 7], which evaluates to [4, 3, 5, 7]
CAR is the unary operator hd
CDR is the unary operator tl
fun length([]) = 0
| length(h :: t) = 1 + length(t);
fun append([], lis2) = lis2
| append(h :: t, lis2) = h :: append(t, lis2);
The val statement binds a name to a value (similar to DEFINE in Scheme)
val distance = time * speed;
– As is the case with DEFINE, val is nothing like an assignment statement in
an imperative language
sub n
| n < 10 = 0
| n > 100 = 2
| otherwise = 1
square x = x * x
- Works for any numeric type of x
Lists
List notation: Put elements in brackets
e.g., directions = ["north", "south", "east", "west"]
Length: #
e.g., #directions is 4
Arithmetic series with the .. operator
e.g., [2, 4..10] is [2, 4, 6, 8, 10]
Catenation is with ++
e.g., [1, 3] ++ [5, 7] results in [1, 3, 5, 7]
86
CONS, CAR, CDR via the colon operator (as in Prolog)
e.g., 1:[3, 5, 7] results in [1, 3, 5, 7]
Factorial Revisited
product [] = 1
product (a:x) = a * product x
fact n = product [1..n]
List Comprehension
Set notation
List of the squares of the first 20 positive integers: [n * n | n ← [1..20]]
All of the factors of its given parameter:
factors n = [i | i ← [1..n div 2],
n mod i == 0]
Quicksort
sort [] = []
sort (a:x) =
sort [b | b ← x; b <= a] ++
[a] ++
sort [b | b ← x; b > a]
Lazy Evaluation
A language is strict if it requires all actual parameters to be fully evaluated
A language is nonstrict if it does not have the strict requirement
Nonstrict languages are more efficient and allow some interesting capabilities
– infinite lists
Lazy evaluation - Only compute those values that are necessary
Positive numbers
positives = [0..]
Determining if 16 is a square number
member [] b = False
member(a:x) b=(a == b)||member x b
squares = [n * n | n ← [0..]]
member squares 16
Member Revisited
The member function could be written as:
member [] b = False
member(a:x) b=(a == b)||member x b
However, this would only work if the parameter to squares was a perfect square;
if not, it will keep generating them forever. The following version will always
work:
member2 (m:x) n
| m < n = member2 x n
| m == n = True
| otherwise = False
87
Comparing Functional and Imperative Languages
Imperative Languages:
– Efficient execution
– Complex semantics
– Complex syntax
– Concurrency is programmer designed
Functional Languages:
– Simple semantics
– Simple syntax
– Inefficient execution
– Programs can automatically be made concurrent
Pragmatics
A software system often consists of a number of subsystems controlled or
connected by a script. Scripting is a paradigm characterized by:
Use of scripts to glue subsystems together.
Rapid development and evolution of scripts.
Modest efficiency requirements.
Very high-level functionality in application-specific areas.
Key Concepts
The following concepts are characteristic of scripting languages:
Very high-level string processing.
Very high-level graphical user interface support.
Dynamic typing.
88
Values and Types
PYTHON has a limited repertoire of primitive types: integer, real, and complex
numbers.
It has no specific character type; single-character strings are used instead. Its
boolean values (named False and True) are just small integers.
PYTHON has a rich repertoire of composite types: tuples, strings, lists,
dictionaries and objects. A PYTHON list is a heterogeneous sequence of values.
A dictionary (sometimes called an associative array) is a heterogeneous mapping
from keys to values, where the keys are distinct immutable values.
The following code illustrates tuple construction:
date = 1998, "Nov", 19
Now date[0] yields 1998, date[1] yields ‘‘Nov’’, and date[2] yields 19.
89
PYTHON supports break, continue, and return sequencers. It also supports
exceptions, which are objects of a subclass of Exception, and which can carry
values.
The following code computes the Greatest Common Divisor of two integers, m
and n:
p, q = m, n
while p % q != 0:
p, q = q, p % q
gcd = q
Note the elegance of simultaneous assignment.
Note also that indentation is required to indicate the extent of the loop body.
The following code sums the numeric components of a list row, ignoring any
nonnumeric components:
sum = 0.0
for x in row:
if isinstance(x, (int, float)):
sum += x
PYTHON Exceptions
The following code prompts the user to enter a numeric literal, and stores the
corresponding real number in num:
while True:
try:
response = raw_input("Enter a numeric literal: ")
num = float(response)
break
except ValueError:
print "Your response was ill-formed."
This while-command keeps prompting until the user enters a well-formed
numeric literal. The library procedure raw_input(...) displays the given prompt
and returns the user’s response as a string. The type conversion
‘‘float(response)’’ attempts to convert the response to a real number. If this type
conversion is possible, the following break sequencer terminates the loop. If not,
the type conversion throws a ValueError exception, control is transferred to the
ValueError exception handler, which displays a warning message, and finally
the loop is iterated again.
90
Procedural Abstraction
PYTHON supports function procedures and proper procedures.
The only difference is that a function procedure returns a value, while a proper
procedure returns nothing.
Since PYTHON is dynamically typed, a procedure definition states the name but
not the type of each formal parameter. The corresponding argument may be of
different types on different calls to the procedure.
PYTHON Procedures
The following function procedure returns the greatest common divisor of its two
arguments:
def gcd (m, n):
p, q = m, n
while p % q != 0:
p, q = q, p % q
return q
Here p and q are local variables.
The following proper procedure takes a date represented by a triple and prints
that date in ISO format (e.g., ‘‘2000-01-01’’):
def print_date (date):
y, m, d = date
if m = "Jan":
m=1
elif m = "Feb":
m=2
...
elif m = "Dec":
m = 12
print "%04d-%02d-%02d" % (y, m, d)
Here y, m, and d are local variables.
91
PYTHON procedure with a variable number of arguments
The following proper procedure accepts any number of arguments, and prints
them one per line:
def printall (*args):
for arg in args:
print arg
The notation ‘‘*args’’ declares that args will refer to a tuple of arguments.
All of the following procedure calls work successfully:
printall(name)
printall(name, address)
printall(name, address, zipcode)
Data Abstraction
PYTHON has three different constructs relevant to data abstraction: packages,
modules, and classes.
Modules and classes support encapsulation, using a naming convention to
distinguish between public and private components.
A package is simply a group of modules. A module is a group of components
that may be variables, procedures, and classes.
These components may be imported for use by any other module. All
components of a module are public, except those whose identifiers start with ‘‘_’’
which are private.
A class is a group of components that may be class variables, class methods,
and instance methods. A procedure defined in a class declaration acts as an
instance method if its first formal parameter is named self and refers to an
object of the class being declared. Otherwise the procedure acts as a class
method.
To achieve the effect of a constructor, we usually equip each class with an
initialization method named ‘‘__init__’’; this method is automatically called when
an object of the class is constructed. Instance variables are named using the
usual ‘‘.’’ Notation (as in self.attr), and they may be initialized by the
initialization method or by any other method. All components of a class are
public, except those whose identifiers start with ‘‘__’’, which are private.
PYTHON Class
Consider the following class:
class Person:
def __init__ (self, sname, fname, gender, birth):
self.__surname = sname
self.__forename = fname
self.__female = (gender == "F" or gender == "f")
self.__birth = birth
def get_surname (self):
return self.__surname
def change_surname (self, sname):
self.__surname = sname
def print_details (self):
print self.__forename + " " + self.__surname
This class is equipped with an initialization method and three other instance
methods, each of which has a self parameter and perhaps some other
parameters. In the following code:
dw = Person("Watt", "David", "M", 1946)
92
the object construction on the right first creates an object of class Person; it
then passes the above arguments, together with a reference to the newly created
object, to the initialization method. The latter initializes the object’s instance
variables, which are named __surname, __forename, __female, and __birth (and
thus are all private).
PYTHON supports multiple inheritance: a class may designate any number of
superclasses. Ambiguous references to class components are resolved by
searching the superclasses in the order in which they are named in the class
declaration.
PYTHON’s support for object-oriented programming is developing but is not yet
mature. The use of the ‘‘__’’ naming convention to indicate privacy is clumsy and
error-prone; class components are public by default. Still more seriously,
variable components can be created (and deleted) at any time, by any method
and even by application code.
Separate Compilation
PYTHON modules are compiled separately. Each module must explicitly import
every other module on which it depends. Each module’s source code is stored in
a text file.
For example, a module named widget is stored in a file named widget.py. When
that module is first imported, it is compiled and its object code is stored in a file
named widget.pyc.
Whenever the module is subsequently imported, it is recompiled only if the
source code has been edited in the meantime. Compilation is completely
automatic.
The PYTHON compiler does not reject code that refers to undeclared identifiers.
Such code simply fails if and when it is executed.
Module Library
PYTHON is equipped with a very rich module library, which supports string
handling, markup, mathematics and cryptography, multimedia, GUIs, operating
system services, Internet services, compilation, and so on.
Unlike older scripting languages, PYTHON does not have built-in high-level
string processing or GUI support. Instead, the PYTHON module library provides
such functionality. For example, the re library module provides powerful string
matching facilities using regular expressions.
93