[go: up one dir, main page]

0% found this document useful (0 votes)
35 views119 pages

PPL Unit - II

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views119 pages

PPL Unit - II

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 119

Principles of Programming Languages

Unit - II
Names, Bindings, Scopes, Data types, Expressions,
Statements, and Control Structures
Names,
Bindings,
Scopes,
Data
types,
Expression
s,
What you will
Learn
➔ Fundamental semantic issues of
variables
➔ Describing the nature of names and
special words in programming
languages
➔ The attributes of variables, including
type, address, and value
What you will
Learn(Contd…)
➔ Important concepts of binding and binding times
➔ The different possible binding times for variable
attributes
and how they define four different categories of
variables
➔ Two very different scoping rules for names, static
and dynamic
➔ The concept of a referencing environment of a
statement
What do you mean by
Functional & Imperative
Programming
Example for Imperative Programming
● Start
● Turn on your shoes size 9 1/2.
● Make room in your pocket to keep an array[7]
of keys.
● Put the keys in the room for the keys in the
pocket.
● Enter garage.
● Open garage.
● Enter Car.

... and so on and on ...


● Put the milk in the refrigerator.
● Stop.
Source: oop - What is difference between functional and imperative programming languages? -
Example for Declarative Programming
● Milk is a healthy drink, unless you have problems digesting
lactose.
● Usually, one stores milk in a refrigerator.
● A refrigerator is a box that keeps the things in it cool.
● A store is a place where items are sold.
● By "selling" we mean the exchange of things for money.
● Also, the exchange of money for things is called "buying".

... and so on and on ...


● Make sure we have milk in the refrigerator
Source: oop - What is difference between functional and imperative programming languages? -
Source: Functional programming vs. imperative programming - LINQ to XML - .NET |
Microsoft Learn
Names, Bindings, and Scopes
The architecture’s two primary components are its memory, which
stores both instructions and data, and its processor, which provides
operations for modifying the contents of the memory.

A variable can be characterized by a collection of properties, or


attributes, the most important of which is type, a fundamental concept in
programming languages.

Designing the data types of a language requires that a variety of


issues be considered.

Among the most important of these issues are the scope and
lifetime of variables
Names, Bindings, and Scopes
Functional programming languages allow expressions to be named.

These named expressions appear like assignments to variable names in


imperative languages, but are fundamentally different in that they cannot
be changed.

They are like the named constants of the imperative languages.

Pure functional languages do not have variables that are like those of the
imperative languages. However, many functional languages do include
such variables.
Design Issues

The following are the primary design issues for names:


• Are names case sensitive?
• Are the special words of the language reserved words or
keywords?
• Maximum length?
•Are connector characters allowed?
The earliest programming languages used single-
character names.
This notation was natural because early programming
was primarily mathematical, and mathematicians have
long used single-character names for unknowns in
their formal notations.
Fortran I broke with the tradition of the single-character
name, allowing up to six characters in its names.
Name Forms
A name is a string of characters used to identify some entity in a program

Fortran 95+ allows up to 31 characters in its names.

C99 has no length limitation on its internal names

Names in Java, C#, and Ada have no length limit, and all characters in
them are significant.

C++ does not specify a length limit on names, although


implementors sometimes do
Name Forms
Names in most programming languages have the same form: a letter
followed by a string consisting of letters, digits, and underscore characters (
_ ).

Although the use of underscore characters to form names was widely


used in the 1970s and 1980s, that practice is now far less popular.

In the C-based languages, it has to a large extent been replaced by


the so-called camel notation, in which all of the words of a multiple-word
name except the first are capitalized, as in myStack

All variable names in PHP must begin with a dollar sign.


Name Forms
Perl, the special character at the beginning of a variable’s name, $, @, or
%,
specifies its type

In Ruby, special characters at the beginning of a variable’s name, @


or @@, indicate that the variable is an instance or a class variable,
respectively

C-based languages, uppercase and lowercase letters in names are


distinct; that is, names in these languages are case sensitive.

For example, the following three names are distinct in C++: rose,
ROSE, and Rose.
Name Forms
In Java and C#, the problem cannot be escaped because many of the
predefined names include both uppercase and lowercase letters.

For example, the Java method for converting a string to an integer


value is parseInt, and spellings such as ParseInt and parseint are
not recognized.

This is a problem of writability rather than readability, because the need


to remember specific case usage makes it more difficult to write
correct programs.

It is a kind of intolerance on the part of the language designer, which


is enforced by the compiler
Special Words
Special words in programming languages are used to make
programs more readable by naming actions to be performed.
They also are used to separate the syntactic parts of statements
and programs.
In most languages, special words are classified as reserved words,
which means they cannot be redefined by programmers, but in some
they are only keywords, which means they can be redefined.
A keyword is a word of a programming language that is special only in
certain contexts.
Special Words
Fortran is the only remaining widely used language whose special
words are keywords.

In Fortran, the word Integer, when found at the beginning of a statement


and followed by a name, is considered a keyword that indicates the
statement is a declarative statement. However, if the word Integer is
followed by the assignment operator, it is considered a variable name.

These two uses are illustrated in the following:

Integer Apple

Integer = 4
Special Words
A reserved word is a special word of a programming language that
cannot be used as a name.

As a language design choice, reserved words are better than keywords


because the ability to redefine keywords can be confusing.

For example, in Fortran, one could have the following statements:

Integer Real

Real Integer
Special Words
There is one potential problem with reserved words: If the language
includes a large number of reserved words, the user may have difficulty
making up names that are not reserved.

The best example of this is COBOL, which has 300 reserved words.

Unfortunately, some of the most commonly chosen names by


programmers are in the list of reserved words—for example, LENGTH,
BOTTOM, DESTINATION, and COUNT.

In program code examples in this book, reserved words are


presented in boldface
Variable
s
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 - Variable names are the most common names in programs
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
Variables
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

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
Variables
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
The address of a variable is sometimes called its
l-value, A variable’s value is sometimes called its
r-value
Aliases - Example if variables named total and sum are aliases, any
change to the value of total also changes the value of sum and vice
versa. A reader of the program must always remember that total and
sum are different names for the same memory cell.
Binding

A binding is an association between an attribute


and an entity, such as between a variable and its
type or value, or between an operation and a
symbol.
The time at which a binding takes place is
called binding time
Binding

Binding and binding times are prominent


concepts in the semantics of programming
languages.
Bindings can take place at language design
time, language implementation time, compile
time, load time, link time, or run time
Binding

For example, the asterisk symbol (*) is usually


bound to the multiplication operation at language
design time.
A data type, such as int in C, is bound to a
range of possible values at language
implementation time.
At compile time, a variable in a Java program is
bound to a particular data type.
Binding

A variable may be bound to a storage cell when


the program is loaded into memory.
That same binding does not happen until run time
in some cases, as with variables declared in Java
methods.
A call to a library subprogram is bound to the
subprogram code at link time
Bindin
g
Consider the following Java assignment
statement:
count = count + 5;
Some of the bindings and their binding times
for the parts of this assignment statement
are as follows:
Binding

The type of count is bound at compile time.


The set of possible values of count is bound at compiler
design time.
The meaning of the operator symbol + is bound at compile
time, when the types of its operands have been
determined.
The internal representation of the literal 5 is bound at
compiler design time.
Bindin
g
A complete understanding of the binding times for the
attributes of program entities is a prerequisite for
understanding the semantics of a programming
language.
For example, to understand what a subprogram
does, one must understand how the actual parameters
in a call are bound to the formal parameters in its
definition.
To determine the current value of a variable, it
Static Binding & Dynamic Binding

A binding is static if it first occurs before


run time begins and remains unchanged
throughout program execution.
If the binding first occurs during run time or
can change in the course of program
execution, it is called dynamic.
Type Bindings

Before a variable can be referenced in a program, it


must be bound to a data type.
The two important aspects of this binding are how the
type is specified and when the binding takes place.
Types can be specified statically through some form of
explicit or implicit declaration.
Binding

An explicit declaration is a statement in a


program that lists variable names and
specifies that they are a particular type.
An implicit declaration is a means of
associating variables with types through
default conventions, rather than declaration
statements
Static Type Binding
Consider the following declarations:

var sum = 0;
var total = 0.0;
var name =
"Fred";
The types of
sum, total,
and name are
int, float, and
string,
respectively.
Dynamic Type Binding

In Python, Ruby, JavaScript, and PHP, type binding is


dynamic.
For example, a JavaScript script may contain the
following statement:
list = [10.2, 3.5];
If the statement
list = 47;
Storage Bindings and Lifetime

The memory cell to which a variable is bound


somehow must be taken from a pool of available
memory. This process is called allocation.
Deallocation is the process of placing a memory cell
that has been unbound from a variable back into the
pool of available memory
The lifetime of a variable is the time during
which the variable is bound to a specific
memory location.
Categories of Variables

These categories are named, according to their


lifetimes

static,
stack-dynamic,
explicit heap-dynamic, and
implicit heap-dynamic.
Scope of the Variables

One of the important factors in understanding variables is scope.


The scope of a variable is the range of statements in which the
variable is visible.
A variable is visible in a statement if it can be referenced
in that statement
A clear understanding of these rules for a language is therefore
essential to the ability to write or read programs in that language.
Scope of the Variables
A variable is local in a program unit or block if it is declared there.

The nonlocal variables of a program unit or block are those that are
visible within the program unit or block but are not declared there.

Global variables are a special category of nonlocal variables.

The lifetime of that variable is the period of time beginning when the
method is entered and ending when execution of the method
terminates.

The referencing environment of a statement is the collection of all


variables that are visible in the statement.
Scope of the Variables

A named constant is a variable that is bound to a value only once.


Named constants are useful as aids to readability and
program reliability.
Readability can be improved
for example, by using the name pi instead of the constant
3.14159265. Another important use of named constants is to
parameterize a program
Data Types

A data type defines a collection of data objects and a set


of predefined operations on those values
A descriptor is the collection of the attributes of a variable
The word object is often associated with the value
of a variable and the space it occupies
One design issue for all data types: What operations
are defined and how are they specified?
Data Types

The two most common structured data types in the


imperative languages are arrays and records, although
the popularity of associative arrays has increased
significantly in recent years.
Lists have been a central part of functional
programming languages
Over the last decade, the increasing popularity of
functional programming has led to lists being added to
primarily imperative languages, such as Python and C#
Primitive Data
Types
Almost all programming languages provide a set of
primitive data types
Primitive data types: Those not defined in terms of other
data types
Some primitive data types are merely reflections
of the hardware
Others require only a little non-hardware support for
their implementation
Primitive Data Types

Integer
Floating Point
Complex
Decimal
Boolean Types
Character
Types
Primitive Data Types - Integer

The most common primitive numeric data type is


integer. Many computers now support several sizes
of integers. Example: Java includes four signed
integer sizes:
byte, short, int, and long
Example, C++ and C#, include unsigned integer types,
which are simply types for integer values without signs
Source:
https://stackoverflow.com/questions/13553707/what-does-signed-and-unsigned-values-
Primitive Data Types - Floating Point

Languages for scientific use support at least two


floating-point types (e.g., float and double)
Newer Machine Uses IEEE Floating-Point Standard 754
The float type is the standard size, usually being stored
in four bytes of memory.
The double type is provided for situations where larger
fractional parts and/or a larger range of exponents is
needed.
Source:
https://cdn.ttgtmedia.com/rms/onlineImages/server_side-java_primitive_types-f.p
Primitive Data Types - Floating Point

The collection of values that can be represented by a


floating-point type is defined in terms of precision
and range.
Precision is the accuracy of the fractional part of a
value, measured as the number of bits.
Range is a combination of the range of fractions and,
more important, the range of exponents
0.1 in decimal is 0.0001100110011 in binary.
Primitive Data Types - Complex

Some languages support a complex type, e.g., Fortran


and Python
Each value consists of two floats, the real part and the
imaginary part
Literal form (in Python): (7 + 3j),
where 7 is the real part and 3 is the imaginary part
Primitive Data Types - Decimal

For business applications


(money) Essential to COBOL
Decimal types are stored very much like character
strings, using binary codes for the decimal digits.
These representations are called Binary Coded Decimal
(BCD) Advantage: accuracy
Disadvantages: limited range, wastes memory
Source:
Primitive Data Types - Boolean

Simplest of all
Range of values: two elements, one for true and one for
false
Could be implemented as bits, but often as bytes
Boolean types are often used to represent switches or
flags in programs.
Advantage: readability
Primitive Data Types - Character

Stored as numeric codings


Most commonly used coding: ASCII
An alternative, 16-bit coding: Unicode Includes
characters from most natural languages
Originally used in Java
C# and JavaScript also support Unicode
Source:
Character String
Types
A character string type is one in which the values
consist of sequences of characters.
Character string constants are used to label output,
and the input and output of all kinds of data are often
done in terms of strings.
Design issues:
Is it a primitive type or just a special kind of
array? Should the length of strings be static
Character String Types
Operations
Typical operations:
Assignment and copying
Comparison (=, >, etc.)
Catenation
Substring reference
Pattern matching

Source:
Character String Type in Certain
Languages
C & C++ Not primitive, Use char arrays and a library of
functions that provide operations
SNOBOL4 (a string manipulation language) Primitive,
Many operations, including elaborate pattern
matching
Fortran and Python Primitive type with assignment and
several operations
Java Primitive via the String class
Perl, JavaScript, Ruby, and PHP Provide built-in
pattern matching, using regular expressions
User-Defined Ordinal
Types
An ordinal type is one in which the range of
possible values can be easily associated with
the set of positive integers.
In Java, for example, the primitive ordinal types
are
integer, char, and boolean.
There are two user-defined ordinal types that
have been supported by programming
languages: enumeration and subrange.
Enumeration
Type
An enumeration type is one in which all of the
possible values, which are named constants, are
provided, or enumerated, in the definition.
Enumeration types provide a way of defining and
grouping collections of named constants, which are
called enumeration constants.
The definition of a typical enumeration type is
shown in the following C# example:
enum days {Mon, Tue, Wed, Thu, Fri, Sat, Sun};
Source:
https://www.w3resource.com/c-
Subrange
Types
A subrange type is a contiguous subsequence of
an ordinal type.
For example, 12..14 is a subrange of integer
type.
Subrange types were introduced by Pascal and are
included in Ada.
There are no design issues that are specific to
subrange types.
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
In many languages, such as C, C++, Java, Ada, and C#,
all of the elements of an array are required to be of the
same type.
In these languages, pointers and references are
restricted to point to or reference a single type.
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?
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?
Record
Types
A record is an aggregate of data elements in which the
individual elements are identified by names and
accessed through offsets from the beginning of the
structure.
Design issues:

What is the syntactic form of references to


the field? Are elliptical references allowed
Union
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?
Tuple
Types
● A tuple is a data type that is similar to a record, except that
the elements are not named.
● Python’s tuples are closely related to its lists, except that
tuples are immutable.
● A tuple is created by assigning a tuple literal.
● Example: myTuple = (3, 5.8, ‘apple’)
● The elements of a tuple need not be of the same type
● The elements of a tuple can be referenced with indexing in
brackets
● Example: myTuple[1]
● This references the first element of the tuple, because tuple
indexing begins at 1.
Tuple
Types
● Tuples can be catenated with the plus (+)
operator.
● They can be deleted with the del statement
● Example: val myTuple = (3, 5.8, ‘apple’);
● The syntax of a tuple element access is a
follows:
● #1 (myTuple);
● This reference the first element of the tuple
● Example:

let tup = (3, 5, 7);;


List
Types
Lists were first supported in the first functional
programming language, LISP.
They have always been part of the functional languages,
but in recent years they have found their way into some
imperative languages.
Lists in Scheme and Common LISP are delimited by
parentheses and the elements are not separated by any
punctuation.
Example (A B C D)
List Nested (A (B C)
List D)
List
Types
The fundamental list operations in Scheme are two functions
that take lists apart and two that build lists.
CAR function returns the first element of its list parameter.
Example (CAR ‘(A B C))
The quote before the parameter list is to prevent the
interpreter from considering the list a call to the A function
with the parameters B and C, in which case it would
interpret it. This call to CAR returns A
Example (CDR ‘(A B C))
The CDR function returns its parameter list minus its first
element
List
Types (CONS ‘A ‘(B C))
Example
This call returns the new list (A
B C) Example (LIST ‘A ‘B ‘(C D))
This call returns the new list (A B
(C D)) Example 3 :: [5, 7, 9]
This returns the new list: [3, 5, 7,
9]
Example [5, 7.3, 9]
The elements of a list must be of the same type, the
List
Types other functions hd(head), tl(tail)
Example
hd [5, 7, 9] is 5
tl [5, 7, 9] is [7, 9]
Example myList = [3, 5.8, “grape”]
x = myList[1] This statement assigns 5.8 to x. The
elements of a list are indexed starting at zero. List elements
also can be updated by assignment. A list element can be
deleted with del.
Example del myList[1] This statement
Pointer and Reference
Types
A pointer type is one in which the variables have a range of
values that consists of memory addresses and a special value,
nil.
Pointers are designed for two distinct kinds of uses.
First, pointers provide some of the power of indirect
addressing, which is frequently used in assembly language
programming.
Second, pointers provide a way to manage dynamic storage.
A pointer can be used to access a location in an area where
storage is dynamically allocated called a heap.
Pointer and Reference
Typesoften do not have identifiers associated with them and
They
thus can be referenced only by pointer or reference type
variables.
Variables without names are called anonymous variables.
Pointers, unlike arrays and records, are not structured
types, although they are defined using a type operator (* in
C and C++ and access in Ada).
Variables that are dynamically allocated from the heap are
called
heap dynamic variables.
Design Issues with Pointers

The primary design issues particular to pointers are the


following:
• What are the scope and lifetime of a pointer variable?
•What is the lifetime of a heap-dynamic variable (the value a
pointer references)?
•Are pointers restricted as to the type of value to which they
can point?
•Are pointers used for dynamic storage management,
indirect addressing, or both?
•Should the language support pointer types, reference types,
Reference Type

A reference type variable is similar to a pointer,


with one important and fundamental difference:
A pointer refers to an address in memory, while a
reference refers to an object or a value in memory.
As a result, although it is natural to perform
arithmetic on addresses, it is not sensible to do
arithmetic on references.
Type
Checking
Type checking is the activity of ensuring that the operands of
an operator are of compatible types.
A compatible type is one that either is legal for the
operator or is allowed under language rules to be
implicitly converted by compiler-generated code (or the
interpreter) to a legal type. This automatic conversion is
called a coercion.
A type error is the application of an operator to an
operand of an inappropriate type.
Dynamic type binding requires type checking at run time,
Strong
Typing
One of the ideas in language design that became prominent
in the so-called structured-programming revolution of the
1970s was strong typing.
Strong typing is widely acknowledged as being a highly valuable
language characteristic.
A programming language is strongly typed if type errors are
always detected. This requires that the types of all operands
can be determined, either at compile time or at run time.
The importance of strong typing lies in its ability to detect all
misuses of variables that result in type errors.
Type Equivalence

The idea of type compatibility was defined when the issue of


type checking was introduced.
The compatibility rules dictate the types of operands
that are acceptable for each of the operators and
thereby specify the possible type errors of the
language.
The rules are called compatibility because in some cases
the type of an operand can be implicitly converted by
the compiler or run-time system to make it acceptable to
Expressions

Expressions are the fundamental means of


specifying computations in a programming
language.
It is crucial for a programmer to understand both the syntax
and semantics of expressions of the language being used.
To understand expression evaluation, it is necessary to
be familiar with the orders of operator and operand
evaluation.
The operator evaluation order of expressions is dictated
Arithmetic Expressions

Automatic evaluation of arithmetic expressions similar to


those found in mathematics, science, and engineering
was one of the primary goals of the first high-level
programming languages.
In programming languages, arithmetic expressions
consist of operators, operands, parentheses, and function
calls.
An operator can be unary, meaning it has a single
operand, binary, meaning it has two operands, or
Source:
Primary Design Issues for Arithmetic
Expressions
• What are the operator precedence rules?
• What are the operator associativity rules?
• What is the order of operand evaluation?
• Are there restrictions on operand evaluation side
effects?
• Does the language allow user-defined operator
overloading?
• What type mixing is allowed in expressions?
Operator Evaluation Order - Precedence

The value of an expression depends at least in part on


the order of evaluation of the operators in the expression.
Consider the following expression:
a+b*c
Suppose the variables a, b, and c have the values 3, 4,
and 5, respectively. If evaluated left to right (the addition
first and then the multiplication), the result is 35.
If evaluated right to left, the result is 23.
Operator Precedence
Rules
The operator precedence rules for expression evaluation
partially define the order in which the operators of different
precedence levels are evaluated
The operator precedence rules of the common
imperative languages are nearly all the same, because
they are based on those of mathematics.
In these languages, exponentiation has the highest
precedence (when it is provided by the language), followed
by multiplication and division on the same level, followed by
binary addition and subtraction on the same level.
Example

In all of the common imperative languages, the unary


minus operator can appear in an expression either at the
beginning or anywhere inside the expression, as long as it
is parenthesized to prevent it from being next to another
operator.
For example,
a + (- b) * c is legal,
but a + - b * c usually is not.
Associativi
ty
The precedence rules say nothing about the order of
evaluation of the operators
When an expression contains two adjacent 2 occurrences
of operators with the same level of precedence, the
question of which operator is evaluated first is answered by
the associativity rules of the language.
An operator can have either left or right associativity,
meaning that when there are two adjacent operators with
the same precedence, the left operator is evaluated first
or the right operator is evaluated first, respectively.
Associativi
ty
Consider the following expression:
a-b+c-d
If the addition and subtraction operators have the same level of
precedence, as they do in programming languages, the
precedence rules say nothing about the order of evaluation
of the operators in this expression.
Associativity in common languages is left to right, except that the
exponentiation operator (when provided) sometimes associates
right to left
Associativi
ty
In the Java expression
a-b+c
the left operator is evaluated first.
Exponentiation in Fortran and Ruby is right associative, so in
the expression
A ** B ** C
the right operator is evaluated first.
In Visual Basic, the exponentiation operator, ^, is left
associative.
Associativity
Associativity
In APL, all operators have the same level of precedence. Thus, the order
of evaluation of operators in APL expressions is determined entirely by
the associativity rule, which is right to left for all operators.

For example, in the

expression A × B + C

the addition operator is evaluated first, followed by the multiplication


operator (× is the APL multiplication operator).

If A were 3, B were 4, and C were 5, then the value of this APL


expression would be 27.
Parenthese
s
Programmers can alter the precedence and associativity
rules by placing parentheses in expressions.
A parenthesized part of an expression has
precedence over its adjacent unparenthesized parts.
For example, although multiplication has precedence
over addition, in the expression
(A + B) * C
the addition will be evaluated first.
Ruby
Expressions
Ruby is a pure object-oriented language, which means, among
other things, that every data value, including literals, is an
object.
Ruby supports the collection of arithmetic and logic operations
that are included in the C-based languages.
What sets Ruby apart from the C-based languages in the area
of expressions is that all of the arithmetic, relational, and
assignment operators, as well as array indexing, shifts, and
bitwise logic operators, are implemented as methods.
For example, the expression a + b is a call to the + method of
the object referenced by a, passing the object referenced by b
Expressions in
Lisp
As is the case with Ruby, all arithmetic and logic operations in
Lisp are performed by subprograms.
But in Lisp, the subprograms must be explicitly called.
For example, to specify the C expression a + b * c in Lisp,
one must write the following expression.
When a list is interpreted as code in Lisp, the first
element is the function name and others are
parameters to the function.
(+ a (* b c))
In this expression, + and * are the names of functions.
Conditional
Expressions
if-then-else statements can be used to perform a conditional
expression assignment.

For example, consider


if (count == 0)
average = 0;
else
average = sum / count;
In the C-based languages, this code can be specified more
conveniently in an assignment statement using a conditional
expression, which has the following form:

expression_1 ? expression_2 : expression_3


Conditional Expressions

Where expression_1 is interpreted as a Boolean expression.


If expression_1 evaluates to true, the value of the whole
expression is the value of expression_2; otherwise, it is the
value of expression_3.
For example, the effect of the example if-then-else can be
achieved with the following assignment statement, using a
conditional expression:
average = (count == 0) ? 0 : sum / count;
Operand Evaluation Order

A less commonly discussed design characteristic of expressions is


the order of evaluation of operands.
Variables in expressions are evaluated by fetching their values from
memory.
Constants are sometimes evaluated the same way.
In other cases, a constant may be part of the machine
language instruction and not require a memory fetch.
If an operand is a parenthesized expression, all of the
operators it contains must be evaluated before its value can be
Side Effects

A side effect of a function, naturally called a functional side


effect, occurs when the function changes either one of its
parameters or a global variable.
Consider the following
expression: a + fun(a)
If fun does not have the side effect of changing a, then the
order of evaluation of the two operands, a and fun(a), has
no effect on the value of the expression. However, if fun
changes a, there is an effect.
Side
Effects
Consider the following situation: fun returns 10 and
changes the value of its parameter to 20.
Suppose we have the following:
a = 10;
b = a + fun(a);
Then, if the value of a is fetched first (in the expression
evaluation process), its value is 10 and the value of the
expression is 20. But if the second operand is evaluated
first, then the value of the first operand is 20 and the value
of the expression is 30.
Side
Effects
The following C program illustrates the same problem when a
function changes a global variable that appears in an
expression:
int a = 5;
int fun1() {
a = 17;
return
3;
} /* end of fun1 */
void main() {
a = a + fun1();
}
The value computed for a in main depends on the order of
Overloaded
Operators
Arithmetic operators are often used for more than one
purpose.
For example, + usually is used to specify integer
addition and floating-point addition.
Some languages: Java, for example - also use it for
string catenation.
This multiple use of an operator is called operator overloading
and is generally thought to be acceptable, as long as neither
readability nor reliability suffers
Type
Conversions
Type conversions are either narrowing or widening.
A narrowing conversion converts a value to a type that
cannot store even approximations of all of the values of the
original type.
For example, converting a double to a float in Java is a
narrowing conversion, because the range of double is much
larger than that of float.
A widening conversion converts a value to a type that can
include at least approximations of all of the values of the
original type.
Relational
Expressions
A relational operator is an operator that
compares the values of its two operands.
A relational expression has two operands and
one relational operator.
The value of a relational expression is Boolean,
except when Boolean is not a type included in
the language.
The relational operators are often
Relational
Expressions
The operation that determines the truth or falsehood of a
relational expression depends on the operand types.
It can be simple, as for integer operands, or complex, as for
character string operands.
Typically, the types of the operands that can be used for
relational operators are numeric types, strings, and
enumeration types.
The relational operators always have lower precedence
than the arithmetic operators, so that in expressions
such as
a+1>2*b
Boolean Expressions

Boolean expressions consist of Boolean variables,


Boolean constants, relational expressions, and Boolean
operators.
The operators usually include those for the AND, OR,
and NOT
operations, and sometimes for exclusive OR and
equivalence.
Boolean operators usually take only Boolean operands
(Boolean variables, Boolean literals, or relational expressions)
Precedence in C Based Languages
Short-Circuit
Evaluation
A short-circuit evaluation of an expression is one in which the
result is determined without evaluating all of the operands
and/or operators.

For example, the value of the arithmetic


expression (13 * a) * (b / 13 - 1)
is independent of the value of (b / 13 - 1) if a is 0, because
0 * x = 0 for any x. So, when a is 0, there is no need to
evaluate (b / 13 - 1) or perform the second multiplication.
However, in arithmetic expressions, this shortcut is not
easily detected during execution, so it is never taken.
Short-Circuit
Evaluation
The value of the Boolean expression
(a >= 0) && (b < 10)
is independent of the second relational expression if a < 0,
because the expression (FALSE && (b < 10)) is FALSE for all
values of b.
So, when a is less than zero, there is no need to evaluate
b, the constant 10, the second relational expression, or
the && operation.
Unlike the case of arithmetic expressions, this shortcut
easily can be discovered during execution.
Assignment Statements

Nearly all programming languages currently being


used
use the equal sign for the assignment operator.
All of these must use something different from an
equal sign for the equality relational operator to
avoid confusion with their assignment operator.
Example:
B = A; // Assign operand A to the B
Assignment
Statements
ALGOL 60 pioneered the use of := as the assignment
operator, which avoids the confusion of assignment with
equality.
Ada also uses this assignment operator.
The design choices of how assignments are used in a
language have varied widely.
In some languages, such as Fortran and Ada, an
assignment can appear only as a stand-alone statement,
and the destination is restricted to a single variable.
There are, however, many alternatives.
Assignment Statement Examples
Conditional Targets

Perl allows conditional targets on assignment

statements. For example,

($flag ? $count1 : $count2) = 0;

which is
equivalent to if
($flag) {
$count1 = 0;
} else {
$count2 = 0;
Compound Assignment Operators

A compound assignment operator is a shorthand method


of specifying a commonly needed form of assignment.
The form of assignment that can be abbreviated with
this technique has the destination variable also
appearing as the first operand in the expression on
the right side, as in
a=a+b
Compound Assignment
Operators
Compound assignment operators were introduced by
ALGOL 68, were later adopted in a slightly different form
by C, and are part of the other C-based languages, as
well as Perl, JavaScript, Python, and Ruby.
The syntax of these assignment operators is the
catenation of the desired binary operator to the =
operator.
For example,
sum += value;
is equivalent to
sum = sum + value;
Unary Assignment Operators

The C-based languages, Perl, and JavaScript include two


special unary arithmetic operators that are actually
abbreviated assignments.
They combine increment and decrement operations with
assignment.
The operators ++ for increment and -- for decrement can be used
either in expressions or to form stand-alone single-operator
assignment statements.
They can appear either as prefix operators, meaning that they
precede the operands, or as postfix operators, meaning that
Unary Assignment Operators
Example
In the assignment statement
sum = ++ count;
the value of count is incremented by 1 and then assigned to sum. This
operation could also be stated as
count = count + 1;
sum = count;
If the same
operator is used
as a postfix
operator, as in
sum = count ++;
the assignment of the value of count to sum occurs first;
then count is incremented. The effect is the same as that of
Multiple
Assignments
Several recent programming languages, including Perl and
Ruby provide multiple-target, multiple-source assignment
statements.
For example, in Perl one can write
($first, $second, $third) = (20, 40, 60);
The semantics is that 20 is assigned to $first, 40 is
assigned to
$second, and 60 is assigned to $third. If the values of two
variables must be interchanged, this can be done with a
single assignment, as with
Mixed-Mode Assignment

Assignment statements also are mixed mode.


C, C++, and Perl use coercion rules for mixed-mode
assignment that are similar to those they use for mixed-mode
expressions
an int value can be assigned to a float variable, but not vice
versa
If an integer literal, which the compiler by default assigns the type
int, is assigned to a char, byte, or short variable and the literal is in
the range of the type of the variable, the int value is coerced to the
type of the variable in a narrowing conversion

You might also like