Apppl
Apppl
Programming
Languages
Assignment No-1
Topics:
1. Modules
2. Module Types and Classes
3. Binding of Referencing Environments
Submitted by,
Aparna.J.S
S7 IT
Roll No:06
MODULES
A major challenge in the construction of any large body of software is how to
divide the
effort among programmers in such a way that work can proceed on multiple
fronts
simultaneously. This modularization of effort depends critically on the notion
of information hiding, which makes objects and algorithms invisible, whenever
possible, to portions of the system that do not need them. Properly
modularized code reduces the “cognitive load”on the programmer by
minimizing the amount of information required to understand any given
portion of the system. In a well-designed program the interfaces between
modules are as “narrow” (i.e., simple) as possible, and any design decision
that is likely to change ishidden inside a single module. This latter point is
crucial, since maintenance (bug fixes and enhancement) consumes much more
programmer time than does initial construction for most commercial
software.In addition to reducing cognitive load, information hiding reduces
the risk of name conflicts: with fewer visible names, there is less chance that a
newly introduced name will be the same as one already in use. It also
safeguards the integrity of data abstractions: any attempt to access objects
outside of the subroutine(s) to which they belong will cause the compiler to
issue an “undefined symbol” error message. Finally, it helps to
compartmentalize run-time errors: if a variable takeson an unexpected value,
we can generally be sure that the code that modified it is in the variable’s
scope.
Modules as Abstractions
A module allows a collection of objects—subroutines, variables, types, and
so
on—to be encapsulated in such a way that objects inside are visible to each
other,
but objects on the inside are not visible on the outside unless explicitly
exported, and
(in many languages) objects outside are not visible on the inside unless
explicitly
imported. Note that these rules affect only the visibility of objects; they do not
affect
their lifetime.
Modules as Managers
Modules facilitate the construction of abstractions by allowing data to be
made private to the subroutinesthat use them.The manager idiom requires
additional subroutines to create/initialize and possibly destroy stack instances,
and it requires that every subroutine (push, pop,create) take an extra
parameter, tospecify the stack in question. Clu adopts the position that every
module (“cluster”)is the manager for a type. Data declared in the cluster
(other than static variables insubroutines) are automatically the
representation of the managed type, and there are special language features
to export an opaque version of the representation to users of the type.
Object Orientation
As an extension of the module-as-type approach to data abstraction, many
languages now provide a class construct for object-oriented
programming.To first approximation, classes can be thought of as module
types that have been augmented with an inheritance mechanism.
Inheritance allows new classes to be defined as extensions or refinements
of existing classes. Inheritance facilitates a programming style in which all or
most operations are thought of as belonging to objects, and in which new
objects can inherit most of their operations from existing objects, without
the need to rewrite code. Classes have their roots in Simula-67. They are
the central innovation of object-oriented languages such as Smalltalk, Eiffel,
C++, Java, and C#. They are also fundamental to several scripting languages,
notably Python and Ruby.
Module types and classes (ignoring issues related to inheritance) require only
simple changes to the scope rules defined for modules in the previous
subsection.Every instance A of a module type or class (e.g., every stack) has a
separate copy of the module or class’s variables. These variables are then
visible when executing one of A’s operations. They may also be indirectly
visible to the operations of some other instance B if A is passed as a
parameter to one of those operations. This rule makes it possible in most
object-oriented languages to construct binary (or moreary) operations that
can manipulate the variables of more than one instance of a class. In C++, for
example, we could create an operation that determines which of two stacks
contains a larger number of elements:
class stack {
...
bool deeper_than(stack other) { // function declaration
return (top > other.top);
}
...
}
...
if (A.deeper_than(B)) ...
BINDING OF REFERENCE
ENVIRONMENTS
Static scope rules specify that the referencing environment depends on the
lexical nesting of program blocks in which names are declared. Dynamic scope
rules specify that the referencing environment depends on the order in which
declarations are encountered at run time.
Subroutine Closure
Deep binding is implemented by creating an explicit representation of a
referencing environment (generally the one in which the subroutine would
execute if called at the present time) and bundling it together with a reference
to the subroutine. The bundle as a whole is referred to as a closure. Usually
the subroutine itself can be represented in the closure by a pointer to its code.
In a language with dynamic scoping, the representation of the referencing
environment depends on whether the language implementation uses an
association list or a central reference table for run-time lookup of names.
The referencing environment in a closure will be non trivial only when passing
a nested subroutine. This means that the implementation of first-class
subroutines is trivial in a language without nested subroutines. At the same
time, it means that a programmer working in such a language is missing
a useful feature: the ability to pass a subroutine with context. In object-
oriented languages, there is an alternative way to achieve a similar effect: we
can encapsulate our subroutine as a method of a simple object, and let the
object’s fields hold context for the method.
interface IntFunc {
public int call(int i);
}
class PlusX implements IntFunc {
final int x;
PlusX(int n
){x=n;}
public int call(int i) { retur
ni+x;}
}
...
IntFunc f = new PlusX(2);
System.out.println(f.call(3)); // prints 5
class int_func {
public:
virtual int operator()(int i) = 0;
};
class plus_x : public int_func {
const int x;
public:
plus_x(int n) : x(n) { }
virtual int operator()(int i) { retur
ni+x;}
};
...
plus_x f(2);
cout << f(3) << "\n";
// prints 5
Delegates in C#: