PPL Unit-3
PPL Unit-3
PART-1
3.1.1 FUNDAMENTALS OF SUBPROGRAMS
Basic definition:
A subprogram is collection of statements which are designed to perform
particular task. Subprogram can be reused to save memory space and
coding time is known as a subprogram.
Advantages of Subprograms:
a. Readability
b. Abstraction
c. Code reusability
There are two type of subprograms: 1. Function 2. Procedures.
Subprogram contain two parts. First part contains subprogram header and
subprogram body or subprogram definition.
Subprogram header which is the first part of the definition, it specifies
the type of the subprogram, name of the subprogram and also specifies if
any parameters.
Consider the following header examples:
def adder (parameters)
The above statement is the header of a Python subprogram named
adder. Ruby subprogram headers also begin with def.
procedure adder (parameters)
The above statement is the header of a Ada subprogram named adder.
subroutine adder (parameters)
The above statement is the header of a Fortran subroutine named
adder.
The header of a JavaScript subprogram begins with function. In C, the
header of a function named adder might be as follows:
void adder (parameters)
The reserved word void in this header indicates that the subprogram does
not return a value.
Advantages of Procedures:
1. The implementation of certain piece of code can be separated out
from the main implementation. Suitable names used for such
procedure represents its purpose as well. For instance - If we call
swap(a,b) function in the main implementation then it will indicate
interchanging of the values a and b.
2. Writing a separate procedure allows to hide Implementation details.
The main procedure looks abstract with simply the call to the
procedures.
3. Procedures can be used to partition a program into smaller modules.
These modules are useful to maintain a large and complex code.
4. Finding errors from a large complex program becomes simplified when
procedures or functions are written.
5. The modifications can be made in the program without affecting rest
of the programming code.
6. There are some standard procedures which are the part of standard
library. For example - sqrt function in C is used for finding the square
root of the number.
Functions: Functions structurally resemble procedures but are semantically
modeled on mathematical functions. Functions are called by appearances of
their names in expressions, along with the required actual parameters. The
value produced by a function’s execution is returned to the calling function.
function body or function definition contain logic to perform particular task.
Syntax according to C-language
If the function contain return type then that function definition should
contain return keyword.
A single function can return only one value.
return(10); return(a); return(‘a’); return(a, b)
first three statements are correct but forth statement is wrong.
Example of function in Pascal
Nested Subprograms:
The idea of nesting subprograms originated with Algol 60. The
motivation was to be able to create a hierarchy of both logic and
scopes.
Writing one subprogram definition in another subprogram definition is
called nested subprogram.
C, C++, Java does not allow nested sub programs
JavaScript, python, Ruby support nested subprograms.
Example:
Void add()
{
Void sub() //
{
------
------
}
}
3.1.4 PARAMETER PASSING METHODS
Parameter-passing methods are the ways in which parameters are
transmitted to and/or from called subprograms. First, we focus on the
different semantics models of parameter-passing methods. Then, we discuss
the various implementation models invented by language designers for
these semantics models.
Semantics Models of Parameter Passing:
Formal parameters are characterized by one of three distinct semantics
models:
(1)They can receive data from the corresponding actual parameter
(2)They can transmit data to the actual parameter
(3)they can do both.
These models are called in mode, out mode, and inout mode,
respectively.
There are two conceptual models of how data transfers take place in
parameter transmission: Either an actual value is copied (to the caller, to the
called, or both ways), or an access path is transmitted. Most commonly, the
access path is a simple pointer or reference. The three semantics models of
parameter passing when values are copied is shown in below.
If, at the end of the execution of Fixer, the formal parameter x is assigned to
its corresponding actual parameter first, then the value of the actual
parameter a in the caller will be 35. If y is assigned first, then the value of
the actual parameter a in the caller will be 17.
Pass-by-Value-Result:
Pass-by-value-result is an implementation model for inout-mode
parameters in which actual values are copied. It is in effect a
combination of pass-by-value and pass-by-result. The value of the
actual parameter is used to initialize the corresponding formal
parameter, which then acts as a local variable. At subprogram
termination, the value of the formal parameter is transmitted back to
the actual parameter.
Pass-by-value-result is sometimes called pass-by-copy, because the
actual parameter is copied to the formal parameter at subprogram
entry and then copied back at subprogram termination.
The advantage of pass-by-value-reference is that the passing process
itself is efficient, in terms of both time and space. Duplicate space is
not required, nor is any copying required.
Pass-by-value-result shares with pass-by-value and pass-by-result the
disadvantages of requiring multiple storage for parameters and time
for copying values. The advantages of pass-by-value-result are relative
to pass-by-reference.
Consider the following example code
In this pass-by-value-result the variable a
corresponding parameter is x and b corresponding
parameter is y. Here a, b values are copies to x and y
parameters. When x is modified this modification is
not affected immediately to a parameter value. after
subprogram is executed formal parameter values are
affected to actual parameters.
a value is 4
b value is 2
Pass-by-Reference:
Pass-by-reference is a second implementation model for inout-mode
parameters. Rather than copying data values back and forth, however,
as in pass-by- value-result, the pass-by-reference method transmits an
access path, usually just an address, to the called subprogram.
Thus, the called subprogram is allowed to access the actual parameter
in the calling program unit. In effect, the actual parameter is shared
with the called subprogram.
The advantage of pass-by-reference is that the passing process itself is
efficient, in terms of both time and space. Duplicate space is not
required, nor is any copying required.
There are, however, several disadvantages to the pass-by-reference
method. First, access to the formal parameters will be slower than
pass-by-value parameters, because of the additional level of indirect
addressing that is required. Second, if only one-way communication to
the called subprogram is required, inadvertent and erroneous changes
may be made to the actual parameter. Another problem of pass-by-
reference is that aliases can be created.
Consider a C++ function that has two parameters that are to be
passed by reference
void fun(int &first, int &second)
If the call to fun happens to pass the same variable twice, as in
fun(total, total) then first and second in fun will be aliases.
Consider the following example code for understanding pass-by-
reference
a value is 4
b value is 2
Pass-by-Name:
Pass-by-name is an inout-mode parameter transmission method that
does not correspond to a single implementation model.
When parameters are passed by name, the actual parameter is, in
effect, textually substituted for the corresponding formal parameter in
all its occurrences in the subprogram. A pass-by- name formal
parameter is bound to an access method at the time of the
subprogram call, but the actual binding to a value or an address is
delayed until the formal parameter is assigned or referenced.
This procedure is treated like macro. The actual parameters can be
surrounded by parenthesis to preserve their integrity.
where Type is the parameter that specifies the type of data on which the
function will operate. This template function can be instantiated for any type
for which the operator > is defined.
Generic Methods in Java 5.0:
Support for generic types and methods was added to Java in Java 5.0. The
name of a generic class in Java 5.0 is specified by a name followed by one or
more type variables delimited by pointed brackets. For example,
generic_class<T>
where T is the type variable.
Java’s generic methods differ from the generic subprograms of C++ in
several important ways.
First, generic parameters must be classes—they cannot be primitive
types. This requirement disallows a generic method that mimics our
example in C++, in which the component types of arrays are generic and
can be primitives. In Java, the components of arrays (as opposed to
containers) cannot be generic.
Second, although Java generic methods can be instantiated any number
of times, only one copy of the code is built. The internal version of a
generic method, which is called a raw method, operates on Object class
objects. At the point where the generic value of a generic method is
returned, the compiler inserts a cast to the proper type.
Output:
The addition of Two vectors is …11 and 22.
3.1.11 CLOSURES:
A closure is a subprogram and the referencing environment where it
was defined. The referencing environment is needed if the subprogram
can be called from any arbitrary place in the program.
If a static-scoped programming language does not allow nested
subprograms, closures are not useful, so such languages do not
support them.
All of the variables in the referencing environment of a subprogram in
such a language (its local variables and the global variables) are
accessible, regardless of the place in the program where the
subprogram is called.
Nearly all functional programming languages, most scripting
languages, and at least one primarily imperative language, C#,
support closures. These languages are static-scoped, allow nested
subprograms, and allow subprograms to be passed as parameters.
Following is an example of a closure written in JavaScript:
The output of this code, assuming it was embedded in an HTML document
and displayed with a browser, is as follows:
Add 10 to 20: 30
Add 5 to 20: 25
In this example, the closure is the anonymous function defined inside
the makeAdder function, which makeAdder returns. The
variable x referenced in the closure function is bound to the parameter that
was sent to makeAdder.
3.1.12 COROUTINES:
A coroutine is a special kind of Subprogram. Coroutines control mechanism is
called as symmetric control model.
Coroutines Can have, multiple Entry point, which are controlled by the
coroutines them Selves. They also have the means to maintain their
status between activations
Coroutine have static local variables.
Secondary execution of a coroutines often begin at points other than
its beginning. Because of this, the invocation is called a resume rather
than a call.
For example
Sub co1()
{
………
resume co2();
………..
resume co3();
………
}
The first time co1 is resumed, its execution begins a first statement
and executes down to and including the resume of co2, which transfers
control to co2. Then the next time co1 is resumed, its execution begins
at the first statement after its call to co2.
When co1 is resumed the third time, its execution begins at the first
statement after its call to co3. Only one coroutine is actually in
execution at a given time. There may be only one processor, all the
coroutines are executed simultaneously (concurrently) by sharing
processor time this is called quasi-concurrency.
coroutines are created in an application by a program unit called the
Master units, which is not a coroutine when created, Coroutines
execute their initialization code and then returns control to that master
unit.
When all of a family of coroutines are constructed, the master program
resumes one of the coroutines, and the members of the family of
coroutines then resume each other in some order until their work is
completed.
If the execution of a coroutine reaches the end of its code section,
control is transferred to the master unit that created it. This is the
mechanism for ending execution of the collection of coroutines, when
that is desirable. In some programs, the coroutines run whenever the
computer is running.
For example, Suppose the game has four players who all use the same
strategy. Such a game can be simulated by having a master program
unit create a family of coroutines, each with a collection, or hand, of
cards. The master program could then start the simulation by resuming
one of the player coroutines, which, after it had played its turn, could
resume the next player coroutine, and so forth until the game ended.
Two possible execution control sequences for two coroutines without loops
PART-2
3.2.1 THE GENERAL SEMANTICS OF CALLS AND RETURNS
The subprogram call and return operations are together called subprogram
linkage. The implementation of subprograms must be based on the
semantics of the subprogram linkage of the language being implemented.
A subprogram call in a typical language has numerous actions associated
with it.
1. The call process must include the implementation of whatever
parameter-passing method is used.
2. Static local variables.
3. Execution status of calling program.
4. Transfer of controls.
5. Subprogram nesting.
The required actions of a subprogram return are less complicated than those
of a call. If the subprogram has parameters that are out mode or inout mode
and are implemented by copy, the first action of the return process is to
move the local values of the associated formal parameters to the actual
parameters. Next, it must deallocate the storage used for local variables and
restore the execution status of the calling program unit. Finally, control must
be returned to the calling program unit.
After placing the activation record on runtime stack, the stack pointer
will move to the size of the activation record. Which is represented
below.
Consider the following skeletal C function:
3.2.5 BLOCKS
Block is a specific group of instructions with user specified scope for
variables. For example-
{
int x;
x=a[0];
a[1]=x;
}
The lifetime of variable x begins when control enters the block. There are
two methods of implementing block. These are:
(1) Treat blocks as parameter-less subprograms that are always called from
the same location - Every block has an activation record, an instance is
created every time the block is executed
(2) Since the maximum storage required for a block can be statically
determined, this amount of space can be allocated after the local variables in
the activation record.
Blocks are treated as parameterless subprograms that are always
called from the same place in the program. Therefore, every block has
an activation record. An instance of its activation record is created
every time the block is executed.
The maximum amount of storage required for block variables at any
time during the execution of a program can be statically determined,
because blocks are entered and exited in strictly textual order.
For example, consider the following skeletal program:
Encapsulation:
The interface part of an Objective-C class is defined in a container
called an interface with the following general syntax:
The first and last lines, which begin with at signs (@), are directives.
The implementation of a class is packaged in a container naturally
named implementation, which has the following syntax:
C programs nearly always import a header file for input and output
functions, stdio.h. In Objective-C, a header file is usually imported that
has the prototypes of a variety of often required functions, including
those for input and output, as well as some needed data. This is done
with the following:
Information Hiding:
Objective-C uses the directives, @private and @public, to specify the access
levels of the instance variables in a class definition. These are used as the
reserved words public and private are used in C++. The difference is that
the default in Objective-C is protected, whereas it is private in C++.
Information Hiding:
Access control for methods in Ruby is dynamic, so access violations are
detected only during execution. The default method access is public,
but it can also be protected or private. There are two ways to specify
the access control, both of which use functions with the same names
as the access levels, private and public.
This resets the default access for subsequently defined methods in the
class. For example,
In Ruby, all data members of a class are private, and that cannot be
changed.
Ada:
Packages can also be generic, so we can construct generic, or
parameterized, abstract data types. The following package specification
describes the interface of a generic stack abstract data type with these
features:
declare
package Float_100_Stack is new Generic_Stack(100, Float);
use Float_100_Stack;
begin
push(45.8);
-------
end;
C++
C++ also supports parameterized abstract data types. Templates are
considered to be the generic abstract data type. In case of templates,
the data components can be of different types however, the operations
are the same.
Using class template, we can write a class whose members use
template parameters as types.
The complete program using class template is as given below.
Output:
a=20 b=10
c=20.5 d=10.5
e=y f=x
Java 5.0
Java 5.0 supports a form of parameterized abstract data types in which
the generic parameters must be classes.
The most common generic types are collection types, such
as LinkedList and ArrayList, which were in the Java class library before
support for generics was added.
Therefore, the collection types have always been able to store multiple
types (as long as they are classes). There were three issues with this:
1. First, every time an object was removed from the collection, it had
to be cast to the appropriate type.
2. Second, there was no error checking when elements were added to
the collection.
In Java 5.0, the collection classes, the most commonly used of which
is ArrayList, became a generic class.
Following is the generic class:
Encapsulation in C++:
C++ provides two different kinds of encapsulation—header and
implementation files can be defined as in C, or class headers and
definitions can be defined.
Because of the complex interplay of C++ templates and separate
compilation, the header files of C++ template libraries often include
complete definitions of resources, rather than just data declarations
and subprogram protocols; this is due in part to the use of the C linker
for C++ programs.
suppose we have an abstract data type for matrices and one for
vectors and need a multiplication operation between a vector and a
matrix. The multiplication code must have access to the data members
of both the vector and the matrix classes, but neither of those classes
is the natural home for the code.
Furthermore, regardless of which is chosen, access to the members of
the other is a problem. In C++, these kinds of situations can be
handled by allowing nonmember functions to be “friends” of a class.
Friend functions have access to the private entities of the class where
they are declared to be friends. For the matrix/vector multiplication
operation, one C++ solution is to define the operation outside both the
matrix and the vector classes but define it to be a friend of both.
Ada Packages:
Ada package specifications can include any number of data and
subprogram declarations in their public and private sections.
Therefore, they can include interfaces for any number of abstract data
types, as well as any other program resources.
So, the package is a multiple-type encapsulation construct. In Ada,
both the matrix and the vector types could be defined in a single Ada
package, which obviates the need for friend functions.
C# Assemblies:
C# includes a larger encapsulation construct than a class. The
construct is the one used by all of the .NET programming languages:
the assembly. Assemblies are built by .NET compilers. A .NET
application consists of one or more assemblies. An assembly is a
file that appears to application programs to be a single dynamic link
library (.dll) or an executable (.exe).
In .NET, the intermediate language is named Common Intermediate
Language (CIL). It is used by all .NET languages. Because its code is in
CIL, an assembly can be used on any architecture, device, or operating
system. When executed, the CIL is just-in-time compiled to native code
for the architecture on which it is resident.
Java Packages:
Java includes a naming encapsulation construct: the package. Packages can
contain more than one type9 definition, and the types in a package are
partial friends of one another. The resources defined in a file are specified to
be in a particular package with a package declaration, as in
package stkpkg;
The package declaration must appear as the first line of the file.
Java provides the import declaration, which allows shorter references to
type names defined in a package. For example, suppose the client includes
the following:
import stkpkg.myStack;
For example, if we wanted to import all of the types in stkpkg, we could use
the following:
import stkpkg.*;
Ada Packages:
Ada packages, which often are used to encapsulate libraries, are defined in
hierarchies, which correspond to the directory hierarchies in which they are
stored. packages also define namespaces. Visibility to a package from a
program unit is gained with the with clause. For example, the following
clause makes the resources and namespace of the
package Ada.Text_IO available.
with Ada.Text_IO;
Access to the names defined in the namespace of Ada.Text_IO must be
qualified. For example, the Put procedure from Ada.Text_IO must be
accessed as
Ada.Text_IO.Put
To access the names in Ada.Text_IO without qualification, the use clause can
be used, as in
use Ada.Text_IO;
With this clause, the Put procedure from Ada.Text_IO can be accessed simply
as Put. Ada’s use is similar to Java’s import.
Ruby Modules:
Ruby classes serve as namespace encapsulations, as do the classes of other
languages that support object-oriented programming. Ruby has an additional
naming encapsulation, called a module.
Modules typically define collections of methods and constants. Modules are
unlike classes in that they cannot be instantiated or subclassed and do not
define variables. Methods that are defined in a module include the module’s
name in their names. For example, consider the following skeletal module
definition:
Assuming the MyStuff module is stored in its own file, a program that wants
to use the constant and methods of MyStuff must first gain access to the
module. Consider the following code that uses our example module, MyStuff,
which is stored in the file named myStuffMod: