PPL Imp
PPL Imp
ANSWERS
Q1)What are the reasons for studying the concepts of Programming
Languages?
The programming language design and implementation is often regarded as largely or even
completely, a matter of opinion, with few, if any, organizing principles, and no generally
accepted facts. In research laboratories and industries dozens of languages are uses every day,
each with its adherents and detractors. Some would suggest that all programming languages
are equivalent, the only difference being a matter of personal interest. Yet can we really say
that the computer programming language Java is “better” (or “worse”) than C++? Is Scheme
“better” than Lisp? Is Machine level language “better” than either of them? It is still a question
that which programming language is better and why? So the study of principle of programming
language supports to better understand the basic logics of programming languages and its
adherents and detractors. It’s also supports to understand the programming languages
paradigms. The following is what we believe to be a compelling list of potential benefits of
studying principle of programming languages:
Historically, this has been the most popular way to evaluate language tests due to it’s
practical advantages: it’s often cheaper and easier to organise.
On the other hand, this method only enables evaluation of a candidates comprehension.
Moreover, it tends to validate knowledge rather than ability. While it may be useful in a
training context, for example to validate the achievements of a specific course, it will only
give a partial view of a candidate's ability to use a language to communicate and express
themselves.
Qualitative assessment
Qualitative evaluation, enables evaluation in situations which better reflect the actual use of a
language, for example to communicate and express oneself, both orally and in writing.
However, for practical reasons this is not the most commonly used way of assessing
candidates. Historically this method would involve candidates taking a listening, reading and
writing test and then also attending an interview with a teacher to assess their oral skills -
expensive and can be very complex to organise, especially when you need to evaluate a large
number of candidates quickly.
Secondly, the method used to complete qualitative evaluation needs to be very rigorous to
ensure objectivity and reliability. Interviews must be conducted in a structured manner,
assessment criteria defined precisely, and examiners must be trained and their judgment
regularly monitored.
The future of language assessment
The rise of new technology has opened the door to new ways of capturing data. It’s possible
to record oral samples and written responses from any computer with a microphone, or even
from a smartphone. Additionally, it’s far easier to present candidates with real-life situations
through the use of visuals and recordings.
Further, the anonymisation of candidates and Big Data technology makes it possible to set up
even more robust methods to guarantee the objectivity and reliability of evaluation.
Technology also enables the use of the skills of global examiners.
Q6) What are the syntactic structures or element that can be described
unity BNF notation?
In Backus-Naur Form (BNF), a notation used to formally describe the syntax of programming
languages and other formal languages, several syntactic structures or elements are commonly
used. BNF is composed of rules that define how sentences in a language can be constructed.
Here are the fundamental elements found in BNF notation:
1. Non-Terminals:
o Definition: Non-terminals represent syntactic categories or placeholders for
other syntactic structures.
o Format: Non-terminals are usually written in uppercase letters (e.g.,
<Statement> or <Expression>).
2. Terminals:
o Definition: Terminals represent actual symbols or tokens in the language,
such as keywords, operators, or literals.
o Format: Terminals are typically written in lowercase letters or enclosed in
quotation marks (e.g., if or "+").
3. Production Rules:
o Definition: Production rules define how non-terminals can be expanded into
sequences of terminals and/or other non-terminals.
o Format: Production rules are written in the form of <NonTerminal> ::= <Sequence
of Symbols>.
4. Alternatives (Choice):
o Definition: Alternatives indicate that a given non-terminal can be expanded in
multiple ways.
o Format: Alternatives are separated by the vertical bar ( |) symbol (e.g., <Expr>
::= <Term> | <Expr> "+" <Term>).
5. Optional Elements:
o Definition: Optional elements indicate that a certain part of the syntax may or
may not be present.
o Format: Enclosed in square brackets ([]) (e.g., <Statement> ::= "if" <Condition> [
"then" <Statement> ]).
6. Repetition (Zero or More):
o Definition: Repetition allows a certain element to be repeated zero or more
times.
o Format: Enclosed in curly braces ({}) or specified using an asterisk (*) (e.g.,
<List> ::= <Item> { "," <Item> }).
7. Grouping:
o Definition: Grouping is used to specify a sequence of elements that should be
treated as a single unit.
o Format: Enclosed in parentheses (()) (e.g., <Expression> ::= "(" <Term> ")").
8. Comments:
o Definition: Comments are used to provide explanatory notes within the BNF
notation.
o Format: Comments are often denoted by specific symbols or annotations,
depending on the BNF variant.
Q7) Give BNF notation for identifiers, for loop while loop, while loop in C.
Give the syntax graph.
+---------------------+
| while (<expr>) |
| | |
| V |
| +-----------------+ |
| | <statement> | |
| +-----------------+ |
+---------------------+
Parse : It means to resolve (a sentence) into its component parts and describe their
syntactic roles or simply it is an act of parsing a string or a text.
Tree: A tree may be a widely used abstract data type that simulates a hierarchical tree
structure, with a root value and sub-trees of youngsters with a parent node,
represented as a group of linked nodes.
Parse Tree:
S -> sAB
A -> a
B -> b
The input string is “sab”, then the Parse Tree is:
S -> AB
A -> c/aA
B -> d/bB
It helps in making syntax analysis by reflecting the syntax of the input language.
It uses an in-memory representation of the input with a structure that conforms to the
grammar.
The advantages of using parse trees rather than semantic actions: you’ll make multiple
passes over the info without having to re-parse the input.
Attribute grammars are a formalism for specifying the semantics of programming languages.
They extend context-free grammars by associating attributes with the grammar symbols and
defining rules for computing attribute values. Attribute grammars play a crucial role in formal
language definition, compiler construction, and program analysis.
The notation used to describe attribute grammars is often similar to Backus-Naur Form
(BNF). In the context of attribute grammars, the symbols are annotated with attributes, and
semantic rules are associated with the production rules of the grammar.
Operational semantics:
This says that the meaning of a language construct is specified by the computation it induces.
It is of interest how the effect of a computation is produced. My understanding of this is that
this basically describes the meaning of all the operations involved in a program (from the
most basic to the most complex).
Examples:
etc.
Denotational semantics:
This says that meanins are modelled by mathematical objects that represent the effect of
executing the constructs. It is of interest only the effect of a computation, not how it is
produced. My understanding of this is basically mathematical functions, which take
something as an input, do some computation (which you don't care about) and produce a
result, which you care about. Since denotational means the main meaning, I take this as: the
name of your function should constrain the possible interpretations of what it does, ideally to
be exact.
Examples:
sort(iterable): should pretty much do what it says, take an unordered iterable as its input and
return it ordered.
min(iterable): should take an array return the smallest value (you don't care how it does it)
max(iterable): should take an array return the largest value (you don't care how it does it)
etc.
Axiomatic semantics:
Some properties of the effect of executing the constructs are expressed as assertions. Some
aspects of the executions may be ignored. My understanding of this is that it's related to
boolean algebra and logic.
Examples:
expr1 and expr2: if expr1 is False then the entire boolean expression is False and it short-
circuits and expr2 is not evaluated
if expr1:
elif expr2:
elif expr3:
else:
The effect is the result of executing the above construct and you assert its value based on
whichever boolean expression yield true, the rest of them being ignored.
UNIT - II
Q1)What are the design issues for names? Explain it?
– 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
Type Coercion:
Type coercion, also known as type conversion, is the process of converting a value from one
data type to another. It involves changing the type of a data element, typically to make it
compatible with the operations or expectations of a particular operation or context. Type
coercion can be implicit, where the conversion is automatically done by the programming
language, or explicit, where the programmer explicitly specifies the conversion.
Implicit Type Coercion: Implicit type coercion happens automatically by the programming
language without the need for explicit instructions from the programmer. It often occurs in
situations where values of one type are used in a context that expects a different type. The
language automatically performs the necessary conversion.
javascript
var num = 5; // num is implicitly of type number
var str = "Hello"; // str is implicitly of type string
var result = num + str; // JavaScript will implicitly convert num to a string and perform concatenation
console.log(result); // Output: "5Hello"
In this example, the addition operation involves a number and a string. JavaScript implicitly
converts the number to a string and concatenates them.
Explicit Type Coercion: Explicit type coercion is when the programmer explicitly specifies
the conversion from one type to another using casting or conversion functions provided by
the language.
python
num_str = "123"
num_int = int(num_str) # Explicitly converting a string to an integer using the int() function
print(num_int) # Output: 123
In programming languages, types define the kind of data that a variable can hold and the
operations that can be performed on that data. Types can be broadly categorized into
primitive types and user-defined types.
1. Primitive Types:
o Numeric Types: Integers (e.g., int), floating-point numbers (e.g., float), etc.
o Text Type: String (e.g., str).
o Boolean Type: Boolean values (True or False).
2. User-Defined Types:
o Classes and Objects: In object-oriented programming, developers can define
their own types using classes.
3. Composite Types:
o Arrays, Lists, Tuples: Collections of elements with a specific structure.
4. Special Types:
o Null/Undefined: A special type representing the absence of a value.
o Function Types: In languages that support first-class functions, functions can
be treated as types.
Understanding and managing types is crucial for writing correct and efficient programs. Type
coercion, whether implicit or explicit, helps handle situations where values of different types
need to interact. However, developers should be aware of potential issues and unintended
consequences that may arise from automatic type coercion.
Named constants are identifiers associated with fixed values in a program, and they provide a
way to assign a meaningful name to a constant value. Designing named constants involves
making decisions about how to declare, use, and manage these constants in a programming
language. Here are some design issues related to named constants:
UNIT-III
Q1.Discuss about generic subprogram in Ada.
In Ada, a generic subprogram is a powerful feature that allows you to define a parameterized
subprogram, which can be instantiated with different types or values. This enables the
creation of flexible and reusable code that can work with a variety of data types and
structures. Ada provides both generic procedures and generic functions.
Generic Procedures:
Syntax:
generic
procedure Procedure_Name (Generic_Parameters);
Example:
generic
type Element_Type is private;
procedure Swap (A, B: in out Element_Type);
In this example, Swap is a generic procedure that can be instantiated with different types
(Element_Type). The is private clause ensures that the actual type is hidden from the
users of the generic package.
Instantiation:
package Integer_Swap is new Swap (Element_Type => Integer);
Generic Functions:
Syntax:
generic
function Function_Name (Generic_Parameters) return Result_Type;
Example:
generic
type Element_Type is private;
function Max (A, B: Element_Type) return Element_Type;
In this example, Max is a generic function that can be instantiated with different types
(Element_Type). The is private clause ensures that the actual type is hidden from the
users of the generic package.
Instantiation:
Generic Package:
You can also use generic packages to encapsulate a collection of related generic procedures
or functions.
Syntax:
generic
package Package_Name is
-- Specification of generic procedures or functions
end Package_Name;
Example:
generic
type Element_Type is private;
package Sorting is
procedure Sort (Array: in out Element_Type_Array);
end Sorting;
Instantiation:
1. Reusability: Generic subprograms allow you to write reusable code that can work
with various data types without duplicating the implementation.
2. Abstraction: The generic subprogram hides the details of the actual data types,
providing a level of abstraction that enhances code readability and maintainability.
3. Flexibility: Developers can instantiate generic subprograms with different types or
values based on the specific requirements of their applications.
4. Type Safety: The use of generics in Ada retains type safety, as the compiler ensures
that the instantiated types adhere to the rules specified in the generic definition.
5. Modularity: Generic subprograms promote modularity by separating the generic
algorithm or functionality from the specific data types it operates on.
In summary, Ada's support for generic subprograms enhances the language's flexibility,
reusability, and abstraction capabilities, making it a valuable feature for building robust and
adaptable software.
Abstract Data Types (ADTs) are a programming concept that encapsulates data structures and
the operations performed on them into a single unit. ADTs provide an abstraction by defining
a set of operations without specifying the internal details of how these operations are
implemented. This separation of concerns helps in organizing and structuring code,
enhancing modularity, and facilitating a clear distinction between the interface and the
implementation.
1. Stack:
Description: A stack is a Last-In, First-Out (LIFO) data structure, where elements are
added and removed from the same end, typically called the "top."
Operations:
o Push(item): Adds an item to the top of the stack.
o Pop(): Removes and returns the item from the top of the stack.
o Peek(): Returns the item at the top without removing it.
Example:
python
stack = Stack()
stack.push(10)
stack.push(20)
print(stack.pop()) # Output: 20
2. Queue:
java
Queue<String> queue = new Queue<>();
queue.enqueue("Alice");
queue.enqueue("Bob");
System.out.println(queue.dequeue()); // Output: "Alice"
3. List:
c++
List myList = createList();
insert(myList, 1, 10);
insert(myList, 2, 20);
delete(myList, 1);
5. Set:
javascript
Set mySet = new Set();
mySet.add(10);
mySet.add(20);
mySet.remove(10);
6. Graph:
java
Graph myGraph = new Graph();
myGraph.addNode("A");
myGraph.addNode("B");
myGraph.addEdge("A", "B");
These examples illustrate the concept of Abstract Data Types by providing a clear interface
for performing operations on various data structures while abstracting away the internal
details of their implementations. The choice of an ADT depends on the specific requirements
of a problem or application.
It seems like your question might be referring to two different concepts: "naming" and
"encapsulation." I'll explain both concepts separately:
Naming:
Naming refers to the process of assigning a name or identifier to a variable, function, class,
or any other entity in a programming language. It plays a crucial role in code readability,
maintainability, and communication among developers. Consistent and meaningful naming
conventions are essential for creating code that is easy to understand and work with.
1. Descriptive Names: Choose names that clearly convey the purpose or meaning of the
entity. Avoid overly generic names.
2. Consistency: Follow consistent naming conventions throughout your codebase. This
includes the use of camelCase, snake_case, or any other convention depending on the
language or coding standards.
3. Avoid Ambiguity: Names should be unambiguous, and their meaning should be clear
without the need for additional comments or explanations.
4. Use Pronounceable Names: Choose names that are easy to pronounce and
remember, making communication about the code more straightforward.
5. Avoid Single-Letter Names: Except for loop counters or other well-understood
cases, using single-letter names can be cryptic and should be avoided.
Encapsulation:
1. Public and Private Access Modifiers: Encapsulation often involves using access
modifiers to control the visibility of members (attributes and methods) within a class.
Public members are accessible from outside the class, while private members are only
accessible within the class itself.
2. Information Hiding: Encapsulation allows you to hide the internal implementation
details of an object and only expose a well-defined interface. This helps in preventing
unintended interference and allows for easier maintenance.
3. Getter and Setter Methods: Instead of directly accessing or modifying the attributes
of an object, encapsulation encourages the use of getter and setter methods to ensure
controlled access and modification.
4. Data Integrity: Encapsulation helps maintain data integrity by enforcing certain
constraints on how data can be accessed or modified. This is achieved through
encapsulating data and providing controlled interfaces for interactions.
In summary, while naming focuses on giving meaningful names to entities in your code,
encapsulation is a design principle that involves bundling data and methods together to
control access and hide implementation details. Both concepts contribute to writing clean,
readable, and maintainable code.
Q9.Explain about the dynamic scoping.
1. Variable Lookup:
o When a variable is referenced, the interpreter or compiler looks for the
variable in the current scope.
o If the variable is not found in the current scope, the search continues in the
calling function or procedure that invoked the current one.
o This process continues until the variable is found or until the global scope is
reached.
2. Scope Determination at Runtime:
o The determination of a variable's scope happens dynamically during program
execution.
o The scope of a variable is determined by the calling sequence of procedures or
functions.
3. Example:
o Let's consider a simple example in a hypothetical language with dynamic
scoping:
python
3.
o procedure Outer() is
o x = 10
o call Inner()
o end procedure
o
o procedure Inner() is
o print(x)
o end procedure
o
o call Outer()
o
o In dynamic scoping, the Inner procedure, when called from Outer, would
access the variable x from the scope of Outer. The scope is determined by the
calling sequence, so Inner looks for x in the scope of the calling function
(Outer).
Advantages:
Disadvantages:
Most modern programming languages, such as Python and Java, use static scoping
rather than dynamic scoping. Static scoping is considered more predictable and helps
catch errors at compile-time, providing better code maintainability.
However, some programming languages, like Emacs Lisp, support dynamic scoping
or allow a combination of both dynamic and lexical scoping.
While dynamic scoping has its advantages in certain scenarios, it's essential to carefully
consider its implications and potential drawbacks, especially in terms of code readability,
predictability, and debugging ease.
n programming languages, a block is a group of statements that are enclosed within curly
braces {}. Blocks serve as a way to group multiple statements into a single compound
statement. The use of blocks is fundamental for controlling the scope of variables, organizing
code, and defining the boundaries of control flow structures. Here are some key aspects of
blocks:
1. Syntax:
In many programming languages, a block is defined using curly braces {}. The syntax
typically looks like this:
python
{
statement1;
statement2;
// ...
statementN;
}
The statements within the block are indented for readability, although indentation is
not always a strict requirement in all languages.
2. Scope:
A block defines a scope for variables. Variables declared within a block are usually
only accessible within that block and its nested blocks.
The concept of scope is crucial for avoiding naming conflicts and managing the
lifetime of variables.
Blocks are often associated with control flow structures like conditionals ( if, else),
loops (for, while), and functions/methods. These structures use blocks to group
statements and define their execution boundaries.
python
if condition:
# Block of statements for true branch
statement1;
statement2;
else:
# Block of statements for false branch
statement3;
statement4;
4. Function/Method Bodies:
java
void myFunction() {
// Block of statements
statement1;
statement2;
}
5. Local Variables:
Variables declared within a block are considered local to that block. They are
typically not accessible outside the block or in nested blocks with the same variable
name.
python
def myFunction():
x = 10 # Local variable within the function block
print(x)
6. Error Handling:
Blocks are often used in error-handling mechanisms, such as try, catch, and
finally blocks in languages like Python or Java.
python
try:
# Block of statements that may raise an exception
statement1;
statement2;
except SomeException as e:
# Block of statements to handle the exception
handle_exception(e);
finally:
# Block of statements that will be executed regardless of whether
an exception occurs
cleanup_resources();
7. Lexical Scoping:
Blocks are closely related to the concept of lexical scoping, where the scope of a
variable is determined by its location in the source code. Lexical scoping helps in
creating predictable and understandable code.
8. Encapsulation:
UNIT-IV
Q1.Discuss oop supported in small talk.
Support for OOP in Smalltalk – CO4
Smalltalk is a pure OOP language
– Everything is an object
– All objects have local memory
– All computation is through objects sending messages to objects
– None of the appearances of imperative languages
– All objected are allocated from the heap
– All deallocation is implicit
Type Checking and Polymorphism
– All binding of messages to methods is dynamic
The process is to search the object to which the message is sent for the
method;
if not found, search the superclass, etc. up to the system class which has no
superclass
– The only type checking in Smalltalk is dynamic and the only type error
occurs when a message is sent to an object that has no matching method
Inheritance
– A Smalltalk subclass inherits all of the instance variables, instance methods,
and class methods of its superclass
– All subclasses are subtypes (nothing can be hidden)
– All inheritance is implementation inheritance
– No multiple inheritance
Evaluation of Smalltalk
– The syntax of the language is simple and regular
– Good example of power provided by a small language
– Slow compared with conventional compiled imperative languages
– Dynamic binding allows type errors to go undetected until run time
– Introduced the graphical user interface
– Greatest impact: advancement of OOP
4.7 Support for OOP in C++ - CO4
General Characteristics:
– Evolved from C and SIMULA 67
– Among the most widely used OOP languages
– Mixed typing system
– Constructors and destructors
– Elaborate access controls to class entities
Inheritance
– A class need not be the subclass of any class
– Access controls for members are
– Private (visible only in the class and friends) (disallows subclasses from being
subtypes)
58
– Public (visible in subclasses and clients)
– Protected (visible in the class and in subclasses, but not clients)
In addition, the subclassing process can be declared with access controls
(private or public), which define potential changes in access by subclasses
– Private derivation - inherited public and protected members are private in
the subclasses
– Public derivation public and protected members are also public and
protected in subclasses
Inheritance Example in C++
class base_class {
private:
int a;
float x;
protected:
int b;
float y;
public:
int c;
float z;
};
class subclass_1 : public base_class { … };
// In this one, b and y are protected and
// c and z are public
class subclass_2 : private base_class { … };
// In this one, b, y, c, and z are private,
// and no derived class has access to any
// member of base_class
A member that is not accessible in a subclass (because of private derivation)
can
be declared to be visible there using the scope resolution operator (::), e.g.,
class subclass_3 : private base_class {
base_class :: c;
…
}
One motivation for using private derivation
– A class provides members that must be visible, so they are defined to be
public members; a derived class adds some new members, but does not want
its clients to see the members of the parent class, even though they had to be
public in the parent class definition
Multiple inheritance is supported
– If there are two inherited members with the same name, they can both be
referenced using the scope resolution operator
Dynamic Binding
– A method can be defined to be virtual, which means that they can be called
through polymorphic variables and dynamically bound to messages
– A pure virtual function has no definition at all
– A class that has at least one pure virtual function is an abstract class
Evaluation
– C++ provides extensive access controls (unlike Smalltalk)
– C++ provides multiple inheritance
– In C++, the programmer must decide at design time which methods will be
statically bound and which must be dynamically bound
Static binding is faster!
– Smalltalk type checking is dynamic (flexible, but somewhat unsafe)
– Because of interpretation and dynamic binding, Smalltalk is ~10 times
slower than C++
59
4.8 Support for OOP in Java – CO4
Because of its close relationship to C++, focus is on the differences from that
language
General Characteristics
– All data are objects except the primitive types
– All primitive types have wrapper classes that store one data value
– All objects are heap-dynamic, are referenced through reference variables,
and most are allocated with new
– A finalize method is implicitly called when the garbage collector is about to
reclaim the storage occupied by the object
Inheritance
– Single inheritance supported only, but there is an abstract class category
that provides some of the benefits of multiple inheritance (interface)
– An interface can include only method declarations and named constants,
e.g.,
public interface Comparable {
public int comparedTo (Object b);}
– Methods can be final (cannot be overriden)
Dynamic Binding
– In Java, all messages are dynamically bound to methods, unless the method
is final (i.e., it cannot be overriden, therefore dynamic binding serves no
purpose)
– Static binding is also used if the methods is static or private both of which
disallow overriding
Several varieties of nested classes
All are hidden from all classes in their package, except for the nesting class
Nested classes can be anonymous
A local nested class is defined in a method of its nesting class
– No access specifier is used
Evaluation
– Design decisions to support OOP are similar to C++
– No support for procedural programming
– No parentless classes
– Dynamic binding is used as “normal” way to bind method calls to method
definitions
– Uses interfaces to provide a simple form of support for multiple inheritance
4.9 Support for OOP in C# -CO4
General characteristics
– Support for OOP similar to Java
– Includes both classes and structs
– Classes are similar to Java‘s classes
– structs are less powerful stack-dynamic constructs (e.g., no inheritance)
Inheritance
– Uses the syntax of C++ for defining classes
– A method inherited from parent class can be replaced in the derived class by
marking its definition with new
– The parent class version can still be called explicitly with the prefix base:
base.Draw()
Dynamic binding
– To allow dynamic binding of method calls to methods:
60
The base class method is marked virtual
The corresponding methods in derived classes are marked override
– Abstract methods are marked abstract and must be implemented in all
subclasses
– All C# classes are ultimately derived from a single root class, Object
Nested Classes
– A C# class that is directly nested in a nesting class behaves like a Java static
nested class
– C# does not support nested classes that behave like the non-static classes of
Java
Evaluation
– C# is the most recently designed C-based OO language
– The differences between C#‘s and Java‘s support for OOP are relatively minor
4.10 Support for OOP in Ada 95 – CO4
General Characteristics
– OOP was one of the most important extensions to Ada 83
– Encapsulation container is a package that defines a tagged type
– A tagged type is one in which every object includes a tag to indicate during
execution its type (the tags are internal)
– Tagged types can be either private types or records
– No constructors or destructors are implicitly called
Inheritance
– Subclasses can be derived from tagged types
– New entities are added to the inherited entities by placing them in a record
definition
– All subclasses are subtypes
– No support for multiple inheritance
A comparable effect can be achieved using generic classes
Example of a Tagged Type
Package Person_Pkg is
type Person is tagged private;
procedure Display(P : in out Person);
private
type Person is tagged
record
Name : String(1..30);
Address : String(1..30);
Age : Integer;
end record;
end Person_Pkg;
with Person_Pkg; use Person_Pkg;
package Student_Pkg is
type Student is new Person with
record
Grade_Point_Average : Float;
Grade_Level : Integer;
end record;
procedure Display (St: in Student);
end Student_Pkg;
// Note: Display is being overridden from Person_Pkg
Dynamic Binding
– Dynamic binding is done using polymorphic variables called classwide types
For the tagged type Prtdon, the classwide type is Person‘ class
– Other bindings are static
61
– Any method may be dynamically bound
– Purely abstract base types can be defined in Ada 95 by including the
reserved word abstract
Evaluation
– Ada offers complete support for OOP
– C++ offers better form of inheritance than Ada
– Ada includes no initialization of objects (e.g., constructors)
– Dynamic binding in C-based OOP languages is restricted to pointers and/or
references to objects; Ada has no such restriction and is thus more
orthogonal
Scheduler
Providing synchronization requires a mechanism for delaying task execution
Task execution control is maintained by a program called the scheduler, which
maps task execution onto available processors
Task Execution States
New - created but not yet started
Ready - ready to run but not currently running (no available processor)
Running
Blocked - has been running, but cannot now continue (usually waiting for some
event to occur)
Dead - no longer active in any sense
Liveness and Deadlock
Liveness is a characteristic that a program unit may or may not have
– In sequential code, it means the unit will eventually complete its execution
In a concurrent environment, a task can easily lose its liveness
If all tasks in a concurrent environment lose their liveness, it is called deadlock
Design Issues for Concurrency
Competition and cooperation synchronization
Controlling task scheduling
How and when tasks start and end execution
How and when are tasks created
Methods of Providing Synchronization
Semaphores
Monitors
Message Passing
Q4.Define a task. What are the different states of task?
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
Example of a Task Body
task body Task_Example is
begin
loop
accept Entry_1 (Item: in Float) do
...
end Entry_1;
end loop;
end Task_Example;
Ada Message Passing Semantics
The task executes to the top of the accept clause and waits for a message
During execution of the accept clause, the sender is suspended
accept parameters can transmit information in either or both directions
Every accept clause has an associated queue to store waiting messages
Figure 6.3 Rendezvous Time Lines
Message Passing: Server/Actor Tasks
A task that has accept clauses, but no other code is called a server task (the
example above is a server task)
A task without accept clauses is called an actor task
– An actor task can send messages to other tasks
– Note: A sender must know the entry name of the receiver, but not vice versa
(asymmetric)
68
Figure 6.4 Graphical Representation of a Rendezvous
Example: Actor Task
task Water_Monitor; -- specificationtask body body Water_Monitor is -- body
begin
loop
if Water_Level > Max_Level
then Sound_Alarm;
end if;
delay 1.0; -- No further execution
-- for at least 1 second
end loop;
end Water_Monitor;
Multiple Entry Points
Tasks can have more than one entry point
– The specification task has an entry clause for each
– The task body has an accept clause for each entry clause, placed in a select
clause, which is in a loop
A Task with Multiple Entries
task body Teller is
loop
select
accept Drive_Up(formal params) do
...
end Drive_Up;
...
or
accept Walk_Up(formal params) do
...
end Walk_Up;
...
end select;
end loop;
end Teller;
Semantics of Tasks with Multiple accept Clauses
If exactly one entry queue is nonempty, choose a message from it
If more than one entry queue is nonempty, choose one, nondeterministically,
from which to accept a message
If all are empty, wait
The construct is often called a selective wait
Extended accept clause - code following the clause, but before the next clause
– Executed concurrently with the caller
69
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
Semantics of select with Guarded accept Clauses:
select first checks the guards on all clauses
If exactly one is open, its queue is checked for messages
If more than one are open, non-deterministically choose a queue among them
to
check for messages
If all are closed, it is a runtime error
A select clause can include an else clause to avoid the error
– When the else clause completes, the loop repeats
Example of a Task with Guarded accept Clauses
Note: The station may be out of gas and there may or may not be a position
available in the garage
task Gas_Station_Attendant is
entry Service_Island (Car : Car_Type);
entry Garage (Car : Car_Type);
end Gas_Station_Attendant;
Example of a Task with Guarded accept Clauses
task body Gas_Station_Attendant is
begin
loop
select
when Gas_Available =>
accept Service_Island (Car : Car_Type) do
Fill_With_Gas (Car);
end Service_Island;
or
when Garage_Available =>
accept Garage (Car : Car_Type) do
Fix (Car);
end Garage;
else
Sleep;
end select;
end loop;
end Gas_Station_Attendant;
Competition Synchronization with Message Passing
Modeling mutually exclusive access to shared data
Example--a shared buffer
Encapsulate the buffer and its operations in a task
Competition synchronization is implicit in the semantics of accept clauses
– Only one accept clause in a task can be active at any given time
70
Task Termination
The execution of a task is completed if control has reached the end of its code
body
If a task has created no dependent tasks and is completed, it is terminated
If a task has created dependent tasks and is completed, it is not terminated
until all its dependent tasks are terminated
The terminate Clause
A terminate clause in a select is just a terminate statement
A terminate clause is selected when no accept clause is open
When a terminate is selected in a task, the task is terminated only when its
master and all of the dependents of its master are either completed or are
waiting at a terminate
A block or subprogram is not left until all of its dependent tasks are terminated
Message Passing Priorities
The priority of any task can be set with the pragma priority pragma Priority
(expression);
The priority of a task applies to it only when it is in the task ready queue
In Ada, both the Producer-Consumer problem and the Dining Philosophers problem can be
addressed using concurrency features provided by the language. Ada offers tasking constructs
that facilitate the development of concurrent programs. Below are brief explanations of how
each problem can be solved in Ada.
1. Producer-Consumer Problem:
The Producer-Consumer problem involves two types of tasks: producers, which produce
items, and consumers, which consume items. They share a common, bounded buffer. The
challenge is to ensure proper synchronization and mutual exclusion to prevent race
conditions.
ada
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Threading; use Ada.Threading;
procedure Producer_Consumer is
task type Producer is
entry Produce(Item: in Integer);
end Producer;
protected Buffer is
entry Add(Item: in Integer);
entry Remove(Item: out Integer);
private
Data : Integer;
end Buffer;
P : Producer;
C : Consumer;
begin
null;
end Producer_Consumer;
In this Ada code, tasks Producer and Consumer share a common buffer implemented using
the Buffer protected type. The Add and Remove entries in the protected type provide
synchronized access to the buffer.
ada
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Threading; use Ada.Threading;
procedure Dining_Philosophers is
protected type Fork;
protected type Table;
T.Forks(Id).Taken := True;
T.Forks((Id mod 5) + 1).Taken := True;
T.Forks(Id).Taken := False;
T.Forks((Id mod 5) + 1).Taken := False;
end loop;
end Philosopher;
F : Fork;
T : Table;
begin
null;
end Dining_Philosophers;
In this Ada code, the Table protected type defines an array of Fork protected types. Each
Philosopher task alternates between thinking and eating, while ensuring proper
synchronization using the Taken attribute of the Fork protected type. The delay statements
simulate the passage of time during thinking and eating phases.
Both of these examples showcase how Ada's tasking constructs and protected types facilitate
the development of concurrent programs, allowing developers to address synchronization and
mutual exclusion issues in a clear and expressive manner.
Exception handling is a critical aspect of software development that involves managing and
responding to exceptional conditions or errors that may occur during the execution of a
program. Designing an effective exception handling mechanism requires careful
consideration of various design issues. Here are some key design issues related to exception
handling:
Issue: Determine the level of granularity at which exceptions are handled. Should
exceptions be caught at a high level, encapsulating large portions of code, or at a more
fine-grained level, catching exceptions closer to where they occur?
Considerations: Fine-grained exception handling allows for more specific error
recovery and reporting, while coarse-grained handling simplifies the code structure.
2. Exception Propagation:
Issue: Decide how exceptions should propagate through the call stack. Should
exceptions be propagated up the call stack until caught, or should they be caught and
handled locally within each function or method?
Considerations: Propagating exceptions up the call stack allows for centralized error
handling, while local handling provides more control over specific error conditions.
Issue: Determine how errors and exceptions are reported and logged. What
information should be included in error messages, and where should error logs be
stored or displayed?
Considerations: Clear and informative error messages help with debugging. Logging
should capture relevant details such as timestamp, context, and stack trace for
comprehensive analysis.
4. Resource Management:
Issue: Address how resources (e.g., files, network connections, memory) are managed
in the presence of exceptions. How should resources be released when an exception
occurs?
Considerations: Use mechanisms like "try-with-resources" to automatically manage
resource cleanup. Ensure proper resource deallocation to avoid resource leaks.
Issue: Organize exceptions into categories or hierarchies based on the types of errors.
How should exception classes or types be structured?
Considerations: Design a meaningful hierarchy of exception classes to capture
different types of errors. This allows for more specific exception handling based on
the nature of the error.
Issue: Determine how to handle system-level exceptions that may arise due to factors
beyond the program's control (e.g., out-of-memory).
Considerations: Define strategies for gracefully handling system-level exceptions
and potentially logging critical information before the program terminates.
Issue: Enforce consistency in exception handling across the codebase. Should there
be a standardized approach to exception naming, handling, and documentation?
Considerations: Consistency improves code maintainability and readability.
Establish coding standards for exception handling conventions.
8. Recovery Mechanisms:
Issue: Decide on strategies for recovering from exceptions. Can the program recover
from certain exceptions, and if so, how should recovery be attempted?
Considerations: Some exceptions may allow for recovery strategies (e.g., retrying an
operation), while others may require termination or rollback.
Issue: Plan for testing and debugging in the presence of exceptions. How can
developers simulate and test exceptional conditions?
Considerations: Ensure that exceptions are appropriately thrown during testing, and
provide mechanisms for debugging and inspecting exceptions during development.
10. Documentation:
Addressing these design issues thoughtfully ensures that exception handling in a program is
effective, maintainable, and aligns with the overall design goals of the software. A well-
designed exception handling mechanism contributes to the reliability and robustness of a
software system.
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
Logic Programming:
1. Declarative Nature:
o Logic programming is often described as a declarative paradigm, where the
programmer specifies what needs to be accomplished rather than specifying
how to achieve it. Declarative programming focuses on expressing the logic
and relationships between entities.
2. Logical Statements (Clauses):
o Programs in logic programming are composed of logical statements or clauses.
A clause can be a fact, a rule, or a query. Facts describe relationships, rules
define how new information can be inferred from existing facts, and queries
seek to find solutions or verify facts.
3. Predicates:
o Predicates are relationships or properties that can be true or false. They are
expressed in terms of facts and rules. Predicates are used to define the logical
structure of the program.
4. Rules:
o Rules specify relationships between different predicates. They consist of a
head and a body. The head declares a new predicate, and the body contains
conditions that must be satisfied for the rule to be applied.
prolog
parent(john, mary).
parent(john, lisa).
sibling(X, Y) :- parent(Z, X), parent(Z, Y), X \= Y.
In the example, sibling(X, Y) is a rule defining the sibling relationship.
Facts:
Facts are basic statements that are assumed to be true. They represent the foundational
knowledge on which rules and queries operate.
prolog
color(apple, red).
color(orange, orange).
In this example, color(apple, red) is a fact indicating that apples are red.
Queries:
Queries are used to ask questions or find solutions in logic programs. They consist of
a predicate with variables that need to be instantiated with values that satisfy the
specified conditions.
prolog
?- color(apple, X).
This query seeks to find the color of an apple, and the variable X will be instantiated with the
result.
Backtracking:
Unification:
prolog
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Horn Clauses:
Logic programming often uses Horn clauses, which are logical implications in the
form of "head :- body." A Horn clause with an empty body is a fact, and a Horn
clause with a non-empty body is a rule.
prolog
9. grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
10. In this example, grandparent(X, Z) is a Horn clause.
Logic programming languages like Prolog follow these declarative principles, allowing
programmers to express relationships, rules, and queries in a natural and intuitive way. The
execution model of logic programs involves searching for solutions by exploring the logical
relationships defined in the program.
In Prolog, a logic programming language, the basic elements include facts, rules, queries,
variables, and predicates. Here's an overview of each of these elements:
1. Facts:
o Facts are the basic statements in Prolog that declare relationships or properties.
They represent information assumed to be true. Facts are written as predicates
with arguments.
prolog
color(apple, red).
size(apple, small).
In these examples, color/2 and size/2 are facts with two arguments.
Rules:
Rules specify relationships between different predicates. They consist of a head and a
body. The head declares a new predicate, and the body contains conditions that must
be satisfied for the rule to be applied.
prolog
sibling(X, Y) :- parent(Z, X), parent(Z, Y), X \= Y.
Queries:
Queries are used to ask questions or find solutions in Prolog. They consist of a
predicate with variables that need to be instantiated with values that satisfy the
specified conditions.
prolog
?- color(apple, X).
This query seeks to find the color of an apple, and the variable X will be instantiated with the
result.
Variables:
Variables in Prolog are represented by names starting with an uppercase letter or an
underscore. Variables allow for the generalization of queries and the binding of values
during execution.
prolog
bigger(X, Y) :- size(X, large), size(Y, small).
Predicates:
prolog
color(apple, red).
size(apple, small).
Unification:
prolog
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Lists:
Prolog supports lists as a fundamental data structure. Lists are used to represent
sequences of elements. Lists are enclosed in square brackets and can be manipulated
using built-in predicates.
prolog
colors([red, green, blue]).
The cut operator ! is used in Prolog to control backtracking. It prunes the search space
by committing to the choices made so far, preventing the system from backtracking to
find alternative solutions.
prolog
8. max(X, Y, X) :- X >= Y, !.
9. max(_, Y, Y).
10. In this example, max/3 uses the cut operator to commit to the first rule when X is
greater than or equal to Y.
These elements form the foundation of Prolog programs, allowing developers to express
logical relationships and constraints in a declarative manner. The execution of Prolog
programs involves searching for solutions that satisfy the specified conditions.
It seems there might be a slight confusion in your question. "SL" is a broad term that could
stand for various things depending on the context. Without a specific context or clarification
of what "SL" refers to, I can provide explanations for a few possibilities:
If you could provide more context or clarification regarding what "SL" specifically refers to,
I would be able to offer more precise information.
Q7. Explain in detail about data types and values in phython language?
In Python, data types and values are fundamental concepts that play a crucial role in
programming. Python is a dynamically typed language, which means you don't need to
declare the data type of a variable explicitly. The interpreter infers the type based on the
value assigned to it. Here's an explanation of various data types and values in Python:
1. Numeric Types:
a. int (Integer):
b. float (Floating-point):
c. complex (Complex):
2. Sequence Types:
a. str (String):
b. list:
c. tuple:
3. Set Types:
a. set:
b. frozenset:
4. Mapping Type:
a. dict (Dictionary):
5. Boolean Type:
a. bool (Boolean):
6. None Type:
a. NoneType:
Key Characteristics:
1. Dynamic Typing:
o Python is dynamically typed, meaning you don't have to specify the type of a
variable explicitly. The interpreter infers it based on the assigned value.
2. Type Conversion:
o You can convert between different data types using built-in functions like int(),
float(), str(), etc.
python
x = 5
y = float(x) # Convert integer to float
z = str(x) # Convert integer to string
Some data types, like lists and dictionaries, are mutable, meaning their values can be
changed after creation. Others, like tuples and strings, are immutable.
python
my_list = [1, 2, 3]
my_list[0] = 10 # Valid for lists (mutable)
my_tuple = (1, 2, 3)
my_tuple[0] = 10 # Invalid for tuples (immutable)
Type Checking:
You can use the type() function to check the type of a variable.
python
x = 5
print(type(x)) # Output: <class 'int'>
Python supports optional type annotations using the typing module, introduced in Python
3.5.
python
5. from typing import List, Tuple
6.
7. def my_function(values: List[int]) -> Tuple[int, int]:
8. # Function body
9.
Understanding data types and values is crucial for writing correct and efficient Python code.
Python's flexibility in handling various types allows for versatile and readable programming.
Python Variables:
1. Definition:
o A variable in Python is a symbolic name that refers to a value or an object.
Variables are used to store and manage data within a program.
2. Dynamic Typing:
o Python is dynamically typed, meaning you don't need to declare the type of a
variable explicitly. The interpreter infers the type based on the assigned value.
python
x = 5 # x is an integer
y = "hello" # y is a string
python
3. age = 25
4. user_name = "John"
5.
Storage in Python:
1. Memory Management:
o Python manages memory automatically using a mechanism called garbage
collection. Memory is allocated and deallocated as needed.
2. Object References:
o Variables in Python are references to objects in memory. When a variable is
assigned a value, it references the memory location where the object is stored.
python
x = 10 # x references the memory location of the integer object 10
Immutable objects (e.g., integers, strings, tuples) cannot be changed after creation.
Mutable objects (e.g., lists, dictionaries) can be modified.
python
3. # Immutable
4. x = 5
5. x = x + 1 # Creates a new integer object, x now references the new
object
6.
7. # Mutable
8. my_list = [1, 2, 3]
9. my_list[0] = 10 # Modifies the existing list in-place
10.
Control in Python:
1. Conditional Statements:
o Python supports if, elif, and else statements for conditional execution.
python
x = 10
if x > 0:
print("Positive")
elif x < 0:
print("Negative")
else:
print("Zero")
Loops:
Python provides for and while loops for iterating over sequences or executing code
repeatedly.
python
# For loop
for i in range(5):
print(i)
# While loop
x = 0
while x < 5:
print(x)
x += 1
Functions:
python
def add_numbers(a, b):
return a + b
result = add_numbers(3, 7)
print(result) # Output: 10
Exception Handling:
Python uses try, except, else, and finally blocks for handling exceptions.
python
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero.")
Python allows you to organize code into modules and packages for better structure
and reusability.
python
5. # Module
6. # math_operations.py
7. def add(a, b):
8. return a + b
9.
10. # main.py
11. from math_operations import add
12. result = add(3, 5)
13.
Python's variable management, memory handling, and control structures contribute to its
flexibility and readability. Understanding these concepts is essential for writing efficient and
maintainable Python code.
In Python, bindings and scope are fundamental concepts related to how variables are assigned
and accessed within a program. Let's explore these concepts in detail:
Bindings:
1. Definition:
o A binding in Python refers to the association of a name (variable) with a value
(object). When you create a variable and assign it a value, you are creating a
binding between the variable name and the object in memory.
python
x = 5 # 'x' is bound to the integer object 5
Dynamic Typing:
Python is dynamically typed, meaning you can reassign a variable to a different type.
python
x = 5 # 'x' is initially bound to the integer object 5
x = "hello" # 'x' is now bound to the string object "hello"
Multiple Bindings to the Same Value:
python
x = y = 10 # 'x' and 'y' are both bound to the integer object 10
python
4. x = 5 # 'x' is bound to the integer object 5
5. x = "hello" # 'x' is now bound to the string object "hello"
6.
Scope:
1. Definition:
o Scope refers to the region of code where a variable is accessible. In Python,
variables have either global or local scope.
2. Global Scope:
o Variables defined outside any function or block have a global scope. They are
accessible throughout the entire program.
python
global_var = 10
def my_function():
print(global_var)
my_function() # Output: 10
Local Scope:
Variables defined within a function or a block have local scope. They are only
accessible within that function or block.
python
def my_function():
local_var = 5
print(local_var)
my_function() # Output: 5
LEGB Rule:
Python follows the LEGB (Local, Enclosing, Global, Built-in) rule to determine the
scope of a variable. When a variable is referenced, Python looks for it in the following
order: Local, Enclosing (if inside a function), Global, and Built-in.
python
x = 10 # Global scope
def my_function():
x = 5 # Local scope
print(x)
my_function() # Output: 5
Nonlocal Keyword:
python
5. def outer_function():
6. x = 10 # Enclosing scope
7.
8. def inner_function():
9. nonlocal x
10. x = 5
11.
12. inner_function()
13. print(x) # Output: 5
14.
15. outer_function()
16.
Understanding bindings and scope is crucial for writing maintainable and error-free Python
code. It helps you manage variable assignments and access in a way that aligns with the
structure and requirements of your program.