IT_SEM III_CPP LAB
IT_SEM III_CPP LAB
IT_SEM III_CPP LAB
Laboratory Manual
Second Year Semester-III
Subject: Computer Programming Paradigms Lab
(ITL303)
ODD Semester
Academic year 2024-25
Name of Student :
ARMIET PIN:
Roll No.
Exam Seat No.
Sr NAME OF EXPERIMENTS
no
1 Demonstrate Compilation and interpretation stages to students for C, C++, JAVA along with how to
Vision
To be a globally recognized, skilled, research oriented and communally responsible software and
hardware engineers for catering to the various industrial needs
Mission
M1: To impart high-quality education with a focus on entrepreneurship, social responsibility,
and professional ethics.
M2: To provide students and faculty members with opportunities to innovate and disseminate
knowledge with research capability.
Java’s process differs as it compiles source code into platform-independent bytecode rather than native
machine code. This bytecode is executed by the Java Virtual Machine (JVM), which interprets or just-in-
time compiles it into native machine code. Debugging in Java typically occurs within integrated
development environments (IDEs) such as Eclipse or IntelliJ IDEA, which offer features like setting
breakpoints, stepping through code, and inspecting variable values. Additionally, command-line tools
like jdb provide alternative debugging options for Java programs. Understanding Java’s compilation
and execution model is crucial for troubleshooting and optimizing code to ensure proper functionality
across various platforms.
Output
Encapsulation is demonstrated through private data members and public methods to access and modify
these members. Inheritance is shown by creating a derived class that inherits from this base class.
#include <iostream>
#include <string>
using namespace std;
// Base class
class Account {
private:
string accountNumber;
double balance;
public:
// Constructor to initialize account
Account(string number, double initialBalance) : accountNumber(number),
balance(initialBalance) {}
// Destructor
virtual ~Account() {
cout << "Account destructor called for " << accountNumber << endl;
}
// Derived class
class SavingsAccount : public Account {
private:
double interestRate;
public:
// Constructor to initialize savings account
SavingsAccount(string number, double initialBalance, double rate)
: Account(number, initialBalance), interestRate(rate) {}
// Destructor
~SavingsAccount() {
cout << "SavingsAccount destructor called" << endl;
}
int main() {
Account* account = new SavingsAccount("123456", 1000.0, 2.5);
account->display();
account->deposit(200.0);
account->withdraw(100.0);
return 0;
}
Encapsulation: The Account class encapsulates accountNumber and balance with private
access modifiers. Public methods allow controlled access and modification.
Inheritance: SavingsAccount inherits from Account, demonstrating how a derived class
extends the functionality of a base class.
Initialization and Finalization: The constructors initialize objects, and destructors clean up
resources. Notice the virtual destructor in the base class to ensure proper cleanup of derived
class objects.
Dynamic Binding: The withdraw and display methods are virtual, allowing for dynamic
binding. The SavingsAccount class overrides these methods, which are resolved at runtime.
Shape Hierarchy
A shape class hierarchy where different shapes have different implementations for calculating area
and displaying information.
#include <iostream>
#include <cmath>
using namespace std;
// Base class
class Shape {
public:
// Virtual destructor
virtual ~Shape() {
cout << "Shape destructor called" << endl;
}
public:
// Constructor
Circle(double r) : radius(r) {}
// Destructor
~Circle() {
cout << "Circle destructor called" << endl;
}
public:
// Constructor
Rectangle(double w, double h) : width(w), height(h) {}
// Destructor
~Rectangle() {
cout << "Rectangle destructor called" << endl;
}
return 0;
}
Encapsulation: The Circle and Rectangle classes encapsulate their specific data (radius,
width, height) and provide methods to access and manipulate this data.
Inheritance: Both Circle and Rectangle inherit from Shape, showing how different shapes
can be treated through a common interface.
Initialization and Finalization: Constructors initialize the shapes, and destructors are used to
clean up. The virtual destructor in Shape ensures proper destruction of derived class objects.
Dynamic Binding: The area and display methods are pure virtual and overridden in derived
classes. The correct method implementations are called at runtime based on the actual object
type, demonstrating dynamic binding.
In Implementation 1, the destructors for both the base class (Account) and the derived class
(SavingsAccount) are called when the SavingsAccount object is deleted. This ensures that both
destructors are executed correctly due to the virtual destructor in the base class.
In Implementation 2, each derived class (Circle and Rectangle) has its destructor called,
followed by the base class destructor. This ensures proper cleanup, with each shape's specific
destructor being called first, followed by the base class destructor.
Output 2:
Theory: Haskell is a functional programming language, which means that functions are first-class
citizens. This means functions can be passed as arguments, returned from other functions, and assigned to
variables.
Installing Haskell
To start programming in Haskell, you’ll need to install the Haskell compiler and tools. The most common
way to do this is through the Haskell Platform or the Glasgow Haskell Compiler (GHC).
1. Haskell Platform:
o Windows/Mac/Linux: Download from Haskell Platform and follow the installation
instructions.
2. GHC (Glasgow Haskell Compiler):
o GHCup: For a more up-to-date installation, you can use GHCup to install GHC, Cabal,
and other tools.
Visit GHCup for installation instructions.
Using GHCi
GHCi is the interactive environment for GHC. It allows you to run Haskell commands and test
code snippets quickly.
1. Start GHCi:
o Open your terminal or command prompt.
o Type ghci and press Enter.
o You should see a prompt like Prelude> indicating that GHCi is ready to accept commands.
1. Write Code:
o Create a file with a .hs extension, for example, HelloWorld.hs.
2. Run Code:
o In GHCi, you can load your file using :load HelloWorld.hs or :l HelloWorld.hs.
o To run functions defined in the file, just type their names at the GHCi prompt.
Output
Create a file named Functions.hs: Open your preferred text editor and create a new file
named Functions.hs.
Output:
Theory: This tutorial will introduce us to operators, types, and basic concepts in Haskell. We'll cover
arithmetic and logical operators, type declarations, and type inference.
1. Arithmetic Operators:
2. Logical Operators
6. Tuples:
1. Higher-Order Functions
Output:
2. Recursion
Output:
Output:
5. Lazy Evaluation
Conclusion: By studying and experimenting with these examples, we'll gain a deeper
understanding of functional programming in Haskell.
Using Conditionals
Output:
Output:
2. List Comprehension
Output:
Output:
Output:
Output:
6. Basic Calculator
Theory: SWI-Prolog is a comprehensive and robust Prolog environment, widely used for
research, education, and development. This tutorial will guide you through the installation
process and introduce you to the basic working of SWI-Prolog.
Step 1: Installation
Windows
1. Download SWI-Prolog:
o Visit the SWI-Prolog download page.
o Click on the appropriate installer for your version of Windows (64-bit or 32-bit).
2. Run the Installer:
o Once the download is complete, run the installer.
o Follow the on-screen instructions to complete the installation.
3. Verify the Installation:
o Open the Command Prompt.
o Type swipl and press Enter.
o If the installation is successful, you will see the SWI-Prolog interactive shell.
To start the SWI-Prolog environment, open your terminal or command prompt and type swipl, then press
Enter.
1. Create a File:
o Create a new file named hello.pl using a text editor.
o Add the following content to the file:
We can ask Prolog questions (queries) based on the facts and rules:
Variables:
Conclusion: With these basics, we're ready to explore more complex Prolog programs
and harness the power of logic programming with SWI-Prolog.
Theory: Below are five Prolog programs that demonstrate declarative programming concepts such as
facts, rules, recursion, backtracking, and list processing.
1. Family Relationships
% family.pl parent(john, mary).
parent(mary, susan).
parent(paul, mary).
parent(jane, susan).
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
main :-
write('Parent relationships:'), nl,
forall(parent(X, Y), (write(X), write(' is parent of '), write(Y), nl)), nl,
write('Grandparent relationships:'), nl,
forall(grandparent(X, Y), (write(X), write(' is grandparent of '), write(Y), nl)),
halt.
Output:
Output:
3. List Length
4. Fibonacci Series
Aim: At least two Programs preferably in C++ and java to demonstrate Thread management and
synchronization.
Theory:
std::mutex mtx;
int counter = 0;
int main() {
std::vector<std::thread> threads;
std::cout << "Final counter value: " << counter << '\n';
Incrementer(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
incrementCounter();
}
System.out.println("Thread " + id + " finished");
}
void mightGoWrong() {
bool errorOccurred = true; // Simulating an error
if (errorOccurred) {
throw std::runtime_error("Something went wrong!");
}
}
int main() {
try {
mightGoWrong();
} catch (const std::runtime_error& e) {
std::cerr << "Caught an exception: " << e.what() << std::endl;
}
return 0;
}
In this program:
mightGoWrong function simulates an error by throwing a std::runtime_error.
The try block calls mightGoWrong and if an exception is thrown, it's caught in
the catch block,
where an error message is printed.
Java
In Java, exception handling is quite similar, but it uses try, catch, finally, and throw
keywords.
public class Main {
public static void mightGoWrong() throws Exception {
boolean errorOccurred = true; // Simulating an error
if (errorOccurred) {
throw new Exception("Something went wrong!");
Garbage Collection
C++
In C++, garbage collection is not built into the language, and memory management is
manual. You need to explicitly allocate and deallocate memory using new and delete.
#include <iostream>
class Example {
public:
Example() { std::cout << "Constructor called\n"; }
~Example() { std::cout << "Destructor called\n"; }
};
int main() {
Example* obj = new Example(); // Memory allocated
delete obj; // Memory deallocated
return 0;
}
Java
Java has automatic garbage collection. You don't need to manually manage
memory, as Java's garbage
collector handles deallocation.
public class Main {
static class Example {
Example() {
System.out.println("Constructor called");
}
@Override
protected void finalize() throws Throwable {
try {
System.out.println("Destructor called");
} finally {
super.finalize();
}
}
}
Conclusion: These experiments illustrate the basics of exception handling and garbage
collection in both languages.
Aim: At Least two implementations each implemented on multiple paradigms like procedural, object
oriented, functional, logic.
Procedural (C)
#include <stdio.h>
// Factorial function
int factorial(int n) {
int result = 1;
result *= i;
return result;
int main() {
int num = 5;
Object-Oriented (Java)
int result = 1;
result *= i;
return result;
int num = 5;
Functional (Haskell)
factorial 0 = 1
factorial n = n * factorial (n - 1)
main = do
let num = 5
putStrLn ("Factorial of " ++ show num ++ " is " ++ show (factorial num))
Logic (Prolog)
factorial(0, 1).
factorial(N, F) :-
N > 0,
N1 is N - 1,
factorial(N1, F1),
F is N * F1.
1. Procedural (C)
#include <stdio.h>
void fibonacci(int n) {
int t1 = 0, t2 = 1, nextTerm;
for (int i = 1; i <= n; i++) {
printf("%d ", t1);
nextTerm = t1 + t2;
t1 = t2;
t2 = nextTerm;
}
}
int main() {
int num = 5;
fibonacci(num);
2. Object-Oriented (Python)
class Fibonacci:
def generate(self, n):
t1, t2 = 0, 1
for _ in range(n):
print(t1, end=" ")
t1, t2 = t2, t1 + t2
3. Functional (Haskell)
haskell
Copy code
fibonacci :: Int -> [Int]
fibonacci n = take n $ map fst $ iterate (\(a,b) -> (b, a+b)) (0,1)
main :: IO ()
main = do
let num = 5
print (fibonacci num)
4. Logic (Prolog)
prolog
Copy code
fibonacci(0, 0).
fibonacci(1, 1).
fibonacci(N, F) :-
N > 1,
N1 is N - 1,
N2 is N - 2,
fibonacci(N1, F1),
fibonacci(N2, F2),
F is F1 + F2.
Conclusion:
Procedural Paradigm: Focuses on step-by-step instructions. The task is broken down into
procedures or functions that change the state of the program.
Object-Oriented Paradigm: Encapsulates the task within objects, which manage their state and
behavior. Involves defining classes and methods to perform the task.