PPL Notes • Unit III & IV B.
Tech CSE • Sem 6
PRINCIPLES OF PROGRAMMING
LANGUAGES
Complete Study Notes — Unit III & Unit IV
[Link] CSE • Third Year • Semester 6
With Java Code Examples & Comparison Tables
Unit III Topics Unit IV Topics
Fundamentals of Subprograms Abstractions & Encapsulation
Scope & Lifetime of Variables Introduction to Data Abstraction
Static vs Dynamic Scope Static, Stack & Heap Storage
Design Issues of Subprograms Garbage Collection
Local Referencing Environments OOP in Java, C++, C#, PHP, Perl
Parameter Passing Methods Subprogram-Level Concurrency
Overloaded Subprograms Semaphores
Generic Subprograms Monitors
Overloaded Operators Message Passing
Coroutines Java Threads & C# Threads
Page 1
PPL Notes • Unit III & IV [Link] CSE • Sem 6
UNIT III Subprograms and Blocks
1. Fundamentals of Subprograms
DEFINITION
A subprogram is a named block of code that performs a specific task and can be called (invoked) from other
parts of a program. In Java, subprograms are called methods.
Think of a subprogram like a recipe. Instead of rewriting all steps every time, you write the recipe once and
refer to it whenever needed.
Key Terminology
• Definition — The actual code of the subprogram.
• Call — The statement that invokes the subprogram.
• Header — The first line (name + parameters).
• Formal Parameter — Variable listed in the header.
• Actual Parameter (Argument) — Value passed during the call.
• Return Value — Value sent back to the caller.
Procedure vs Function
Type Description Java Example
Procedure Does a task, does NOT return a void printHello()
value
Function Does a task AND returns a value int add(int a, int b)
Java — Basic Subprogram ●●●
public class SubprogramDemo { // PROCEDURE — no return value (void) static void
greet(String name) { [Link]("Hello, " + name + "!"); } // FUNCTION — returns
an int static int add(int a, int b) { return a + b; } public static void main(String[]
args) { greet("Alice"); // calls a procedure int result = add(3, 5); // calls a function
[Link](result); // Output: 8 } }
Blocks
A block is a section of code enclosed in curly braces {}. Blocks introduce local variables with limited scope.
Java — Block Example ●●●
public static void main(String[] args) { int x = 10; { // inner block starts int y = 20;
// y lives only inside this block [Link](x + y); // 30 } // y is destroyed
here // [Link](y); // ERROR! y not accessible }
Page 2
PPL Notes • Unit III & IV [Link] CSE • Sem 6
2. Scope & Lifetime of Variables
DEFINITION
Scope — The region of code where a variable is visible/accessible.
Lifetime — The duration during execution when a variable exists in memory.
TIP / ANALOGY
Easy Analogy: Scope = "Where can you see me?" Lifetime = "How long do I live?"
Variable Type Where Declared Scope Lifetime
Local Inside method/block Within that method/block Method execution
Instance Inside class, outside Whole class Object lifetime
methods
Class (static) With static keyword Whole program Entire program run
Java — Scope & Lifetime Demo ●●●
public class ScopeDemo { static int classVar = 100; // class scope, lives forever int
instanceVar = 50; // instance scope void display() { int localVar = 10; // local — only
inside display() [Link](classVar); // accessible
[Link](instanceVar); // accessible [Link](localVar); //
accessible } // localVar destroyed here }
3. Static vs Dynamic Scope
Static (Lexical) Scope
Scope is determined at compile time, based on the physical structure of the code. Most modern
languages (Java, C, C++) use static scoping.
Dynamic Scope
Scope is determined at runtime, based on the call stack. Used in older languages like early LISP.
EXAMPLE
Concept (Pseudocode):
x = 10
function A(): print(x) <-- which x?
function B(): x = 20 A()
B()
Static Scope: A() prints 10 (uses x from where A is defined)
Dynamic Scope: A() prints 20 (uses x from where A is called)
Page 3
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Feature Static Scope Dynamic Scope
Determined at Compile time Runtime
Based on Code structure (where written) Call chain (who called whom)
Predictability Easy to predict Hard to track
Examples Java, C, C++, Python Early LISP, old Perl, Bash
Performance Faster Slower
Java — Static Scope (Java always uses this) ●●●
public class StaticScopeDemo { static int x = 10; // global x static void A() {
[Link]("x = " + x); // sees global x = 10 } static void B() { int x = 20; //
local x in B A(); // A still sees global x, not B's x } public static void main(String[]
args) { B(); // Output: x = 10 (static scoping!) } }
4. Design Issues of Subprograms
When designing a language, several decisions about subprograms must be made:
• What parameter-passing methods are supported?
• Are local variables statically or dynamically allocated?
• Can subprograms be nested?
• Can subprograms be passed as parameters?
• Is overloading allowed?
• Are recursive calls supported?
• Should functions have side effects?
TIP / ANALOGY
A function that always returns the same output for the same input and has no side effects is called a Pure
Function. Pure functions are much easier to test and debug!
Java — Recursion ●●●
static int factorial(int n) { if (n == 0) return 1; // base case return n * factorial(n -
1); // recursive call } // factorial(5) = 5*4*3*2*1 = 120
5. Local Referencing Environments
DEFINITION
The local referencing environment of a subprogram is the complete set of variables visible inside it —
including local variables and accessible non-local variables.
Activation Record (Stack Frame)
Page 4
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Each call creates a new activation record on the stack containing: local variables, parameters, return
address, and return value storage.
Call Stack when factorial(3) is running: +---------------------------+ | factorial(1) n=1 | <- top
of stack +---------------------------+ | factorial(2) n=2 | +---------------------------+ |
factorial(3) n=3 | +---------------------------+ | main() | <- bottom
+---------------------------+
Type Allocation Retains value between Java Equivalent
calls?
Static local Compile time YES Static field in class
Dynamic local Runtime (stack) NO Regular local variable
6. Parameter Passing Methods
1. Pass by Value
A copy of the argument is passed. Changes inside the function do NOT affect the original variable.
Java — Pass by Value (primitives) ●●●
static void change(int x) { x = 99; // only changes the local copy } public static void
main(String[] args) { int num = 10; change(num); [Link](num); // Still 10!
Original unchanged }
2. Pass by Reference
The memory address of the argument is passed. Changes inside affect the original. Java does not have true
pass-by-reference, but passing objects allows state mutation.
Java — Object (reference copy passed by value) ●●●
static void modify(int[] arr) { arr[0] = 999; // modifies the original array! } public
static void main(String[] args) { int[] arr = {1, 2, 3}; modify(arr);
[Link](arr[0]); // Output: 999 }
3. Pass by Value-Result & 4. Pass by Name
Value-Result (Copy-In Copy-Out): Value copied in at call, copied back on return. Used in Ada.
Pass by Name: Expression substituted into function body unevaluated. Used in ALGOL 60.
Method What is Passed Caller Changed? Languages
By Value Copy of data NO Java (primitives), C
By Reference Memory address YES C++, C# (ref)
Value-Result Copy in/out On return Ada, Fortran
By Name Expression Depends ALGOL 60, Haskell
Page 5
PPL Notes • Unit III & IV [Link] CSE • Sem 6
IMPORTANT
Java is strictly pass-by-value. When you pass an object, you pass a copy of the reference. You can mutate
the object's contents but cannot make the original variable point to a new object.
7. Overloaded Subprograms
DEFINITION
Overloading means having multiple subprograms with the same name but different parameter lists. The
correct version is selected at compile time.
Java — Method Overloading ●●●
public class Overloading { static int add(int a, int b) { return a + b; } static double
add(double a, double b) { return a + b; } static int add(int a, int b, int c) { return a +
b + c; } public static void main(String[] args) { [Link](add(2, 3)); // int
version -> 5 [Link](add(2.5, 3.1)); // double version -> 5.6
[Link](add(1, 2, 3)); // 3-param version -> 6 } }
IMPORTANT
Overloading is resolved at compile time (static binding). You CANNOT overload by return type alone — the
parameter list must differ.
8. Generic Subprograms
DEFINITION
A generic subprogram can work with any data type. The actual type is specified when the subprogram is
called. In Java, this is implemented using Generics (<T>).
Java — Generic Method ●●●
public class GenericDemo { // T is a type placeholder static <T> void printItem(T item) {
[Link]("Item: " + item); } static <T extends Comparable<T>> T max(T a, T b) {
return ([Link](b) > 0) ? a : b; } public static void main(String[] args) {
printItem(42); // works with int printItem("Hello"); // works with String
printItem(3.14); // works with double [Link](max(10, 20)); // 20
[Link](max("apple","mango")); // mango } }
9. Design Issues for Functions & Overloaded Operators
Operator overloading means giving new meaning to existing operators (+, -, *) for user-defined types.
Page 6
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Language Operator Overloading? Notes
Java NO (only + for String built-in) Cannot define for user types
C++ YES, fully supported operator+ syntax
Python YES via __add__, __mul__ etc. Dunder methods
C# YES operator keyword
Functions as Arguments (Higher-Order Functions)
Java — Lambda as Argument ●●●
import [Link]; public class HigherOrder { static int
applyOp(Function<Integer,Integer> op, int x) { return [Link](x); } public static void
main(String[] args) { [Link](applyOp(n -> n * n, 5)); // 25
[Link](applyOp(n -> n + 10, 5)); // 15 } }
10. Coroutines
DEFINITION
A coroutine is a subprogram that can be paused and resumed. Multiple coroutines share execution,
switching control cooperatively.
TIP / ANALOGY
Analogy: Two people writing a story together. A writes a paragraph, passes the pen to B. B writes, then
passes back. They take turns — neither is "the boss".
Regular function: Coroutine: main -> func -> return main <-> coroutine (both can pause & resume)
Java — Simulating Coroutine with Threads ●●●
public class CoroutineDemo { public static void main(String[] args) throws
InterruptedException { Thread t1 = new Thread(() -> { for (int i = 1; i <= 3; i++) {
[Link]("Coroutine A: step " + i); try { [Link](100); } catch (Exception
e) {} } }); Thread t2 = new Thread(() -> { for (int i = 1; i <= 3; i++) {
[Link]("Coroutine B: step " + i); try { [Link](100); } catch (Exception
e) {} } }); [Link](); [Link](); [Link](); [Link](); } }
Languages with native coroutines: Python (async/await), Kotlin (suspend), Lua, C# async/await.
Page 7
PPL Notes • Unit III & IV [Link] CSE • Sem 6
UNIT IV Abstract Data Types, OOP & Concurrency
11. Abstractions & Encapsulation
Abstraction
DEFINITION
Abstraction means showing only essential features and hiding unnecessary details. You use a TV remote
without knowing the electronics inside.
• Process Abstraction — Subprograms/methods (hide HOW something is done)
• Data Abstraction — ADTs/Classes (hide the internal data representation)
Encapsulation
DEFINITION
Encapsulation means bundling data (fields) and methods together in one unit (class), and restricting direct
access using access modifiers (private, public, protected).
Java — Encapsulation Example ●●●
public class BankAccount { private double balance; // data hidden from outside public
BankAccount(double initial) { [Link] = initial; } public void deposit(double
amount) { if (amount > 0) balance += amount; } public double getBalance() { return
balance; } // controlled access } // [Link] = -9999; // ERROR! Private — cannot
access directly
12. Introduction to Data Abstraction (ADT)
DEFINITION
An Abstract Data Type (ADT) is a data type defined by its behavior (operations), not its implementation.
The user knows WHAT operations are available, not HOW they work.
EXAMPLE
A Stack ADT has: push(), pop(), peek(), isEmpty(). You don't care if it's implemented using an array or linked
list — just use the operations!
Page 8
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Java — Stack ADT Implementation ●●●
public class MyStack { private int[] data = new int[100]; private int top = -1; public
void push(int val) { data[++top] = val; } public int pop() { return data[top--]; } public
int peek() { return data[top]; } public boolean isEmpty() { return top == -1; } } //
Usage: MyStack s = new MyStack(); [Link](10); [Link](20); [Link](30);
[Link]([Link]()); // 30 (LIFO) [Link]([Link]()); // 20
13. Storage Management — Static, Stack & Heap
Static Storage
• Memory allocated at compile time. Size fixed and known before the program runs.
• Global variables, static fields.
• Very fast — no runtime overhead. Stays allocated for the entire program.
Stack-Based Storage
• Allocated and freed automatically in LIFO order during function calls.
• Local variables, parameters, return addresses.
• Very fast, but limited size. StackOverflow if recursion is too deep.
Heap-Based Storage
• Memory allocated at runtime using the new keyword.
• Flexible size. Objects persist beyond a single function call.
• Must be managed — manually (C/C++) or by Garbage Collector (Java).
Memory Layout of a Java Program: +------------------------------------------+ | HEAP | <- Objects
(new MyClass()) | [obj1] [obj2] [obj3] | +------------------------------------------+ | FREE
MEMORY | +------------------------------------------+ | STACK | <- Local vars, method frames |
[main frame] [method A frame] <-top | +------------------------------------------+ | STATIC /
METHOD AREA | <- class defs, static vars +------------------------------------------+
Feature Static Stack Heap
Allocated when Compile time Function call Runtime (new)
Freed when Program ends Function returns GC or manual
Speed Fastest Fast Slower
Size Fixed Limited Large/flexible
Java example static int x int x inside method new Object()
14. Garbage Collection
DEFINITION
Page 9
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Garbage Collection (GC) is the automatic process of finding and freeing heap memory that is no longer
reachable by the program. In Java, the JVM handles this — no manual free() needed!
GC Algorithms
1. Reference Counting — Each object counts references to it. When count = 0, it's garbage. Problem:
Cannot handle circular references.
2. Mark and Sweep — Phase 1: Mark all reachable objects. Phase 2: Sweep (free) everything unmarked.
3. Copying GC — Copies all live objects to a new space. Fast allocation but uses double memory.
4. Generational GC (Java uses this!) — Objects split into Young and Old generation. Most objects die
young, so GC runs frequently on Young gen.
Java Generational GC: +--------------------------------------------------+ | Young Generation
(frequent GC) | | [Eden Space] -> [Survivor 0] -> [Survivor 1] | | Objects promoted if they survive
enough | +--------------------------------------------------+ | Old Generation (infrequent GC) | |
[long-lived objects live here] | +--------------------------------------------------+
Java — GC Concept ●●●
String s1 = new String("Hello"); // object on heap String s2 = new String("World"); //
another heap object s1 = null; // "Hello" object now eligible for GC [Link](); //
suggest GC to run (not guaranteed) [Link](s2); // "World" still alive
15. OOP in Different Languages
Core OOP Concepts
• Class — Blueprint for objects
• Object — Instance of a class
• Inheritance — Child class inherits from parent
• Polymorphism — Same interface, different behavior
• Encapsulation — Data hiding via access modifiers
• Abstraction — Show only essential details
Java — Full OOP Example (Inheritance + Polymorphism) ●●●
abstract class Animal { protected String name; public Animal(String name) { [Link] =
name; } abstract void makeSound(); // abstract method void eat() {
[Link](name + " is eating"); } } class Dog extends Animal { public Dog(String
name) { super(name); } @Override void makeSound() { [Link](name + ": Woof!");
} } class Cat extends Animal { public Cat(String name) { super(name); } @Override void
makeSound() { [Link](name + ": Meow!"); } } // Polymorphism in action:
Animal[] animals = { new Dog("Rex"), new Cat("Whiskers") }; for (Animal a : animals) {
[Link](); [Link](); }
OOP Across Languages — Key Differences
Page 10
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Feature Java C++ C# Python/PHP Smalltalk
Multiple NO (interfaces) YES NO (interfaces) YES NO
Inheritance
Operator NO YES YES YES (Python) YES
Overloading
Pure OOP NO (primitives) NO NO Mostly YES
Garbage YES (JVM) NO (manual) YES (.NET) YES YES
Collection
Access public/private/pr Same Same+internal Convention public/private
Modifiers otected
Language Notes
• Smalltalk — Purely OOP. Everything is an object (even numbers & booleans). Method calls are called
"sending messages".
• C++ — Multi-paradigm. Supports OOP + procedural. Manual memory management.
• PHP — OOP added in PHP 5. Uses $this->property syntax.
• Perl — OOP done using packages and the bless() function. Flexible but verbose.
• C# — Similar to Java. Better async/await support. Properties instead of getters/setters.
16. Concurrency — Subprogram-Level Concurrency
DEFINITION
Concurrency is the ability of a program to have multiple parts executing at the same time (or appearing to).
A thread is the smallest unit of concurrent execution.
Key Problems in Concurrency
• Race Condition — Two threads access shared data simultaneously, causing unpredictable results.
• Deadlock — Two threads each wait for the other to release a resource — forever.
• Starvation — A thread never gets CPU time because others keep getting priority.
IMPORTANT
Race Condition Example: Thread A reads balance (1000). Thread B reads balance (1000). A adds 500 →
writes 1500. B adds 500 → also writes 1500. Expected: 2000. Actual: 1500! Money lost due to race condition.
17. Semaphores
DEFINITION
Page 11
PPL Notes • Unit III & IV [Link] CSE • Sem 6
A Semaphore is a synchronization mechanism — essentially a counter with two operations:
wait() / P() — Decrement. If counter is 0, block until positive.
signal() / V() — Increment. Wake up a waiting thread if any.
TIP / ANALOGY
Analogy: A parking lot with N spaces. When entering, check if space available (wait). When leaving, free the
space (signal).
Type Counter Range Use Case
Binary Semaphore (Mutex) 0 or 1 Mutual exclusion — like a lock
Counting Semaphore Any non-negative integer Control access to N resources
Java — Semaphore Example ●●●
import [Link]; public class SemaphoreDemo { static Semaphore sem
= new Semaphore(1); // binary semaphore static int sharedCounter = 0; static void
increment() { try { [Link](); // wait() — lock sharedCounter++;
[Link]("Counter: " + sharedCounter); [Link](); // signal() — unlock }
catch (InterruptedException e) { [Link](); } } public static void
main(String[] args) { Thread t1 = new Thread(() -> { for(int i=0;i<3;i++) increment();
}); Thread t2 = new Thread(() -> { for(int i=0;i<3;i++) increment(); }); [Link]();
[Link](); } }
18. Monitors
DEFINITION
A Monitor is a high-level synchronization construct that combines shared data, procedures, and
synchronization in one package. Only one thread can be active inside a monitor at a time. Java implements
monitors via the synchronized keyword.
Feature Semaphore Monitor
Level Low-level High-level
Data encapsulation NO YES
Ease of use Harder (manual) Easier (automatic)
Java support Semaphore class synchronized keyword
Page 12
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Java — Monitor with synchronized ●●●
public class MonitorDemo { private int count = 0; // Only ONE thread can execute this at a
time public synchronized void increment() { count++; } public synchronized int getCount()
{ return count; } public static void main(String[] args) throws InterruptedException {
MonitorDemo m = new MonitorDemo(); Thread t1 = new Thread(() -> { for(int i=0;i<1000;i++)
[Link](); }); Thread t2 = new Thread(() -> { for(int i=0;i<1000;i++) [Link]();
}); [Link](); [Link](); [Link](); [Link](); [Link]([Link]()); //
Always 2000! } }
19. Message Passing
DEFINITION
Message Passing is a concurrency model where threads communicate by sending and receiving
messages instead of sharing memory. No shared state = No race conditions!
TIP / ANALOGY
Instead of two people writing on the same whiteboard (shared memory), they pass notes to each other. Each
person has their own whiteboard.
• Synchronous — Sender waits until receiver gets the message (blocking).
• Asynchronous — Sender sends and continues (non-blocking). Message stored in queue.
Java — Message Passing with BlockingQueue ●●●
import [Link].*; public class MessagePassing { static BlockingQueue<String>
queue = new LinkedBlockingQueue<>(); public static void main(String[] args) { // Producer
— sends messages Thread producer = new Thread(() -> { try { [Link]("Message 1");
[Link]("Message 2"); [Link]("STOP"); } catch (InterruptedException e) {} }); //
Consumer — receives messages Thread consumer = new Thread(() -> { try { while (true) {
String msg = [Link](); // blocks until msg arrives if ([Link]("STOP")) break;
[Link]("Received: " + msg); } } catch (InterruptedException e) {} });
[Link](); [Link](); } }
20. Java Threads & C# Threads
3 Ways to Create a Thread in Java
Java — Thread Creation (3 Ways) ●●●
// WAY 1: Extend Thread class class MyThread extends Thread { public void run() {
[Link]("Thread way 1"); } } // WAY 2: Implement Runnable interface class
MyRunnable implements Runnable { public void run() { [Link]("Thread way 2");
} } public class ThreadDemo { public static void main(String[] args) { new
MyThread().start(); // WAY 1 new Thread(new MyRunnable()).start(); // WAY 2 new Thread(()
-> [Link]("Thread way 3")).start(); // WAY 3 Lambda } }
Page 13
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Java Thread Lifecycle
New --> Runnable --> Running --> (Blocked/Waiting) --> Terminated | | | | new start() CPU given
run() completes or stop()
wait() and notify() — Monitor Pattern
Java — Producer-Consumer with wait/notify ●●●
class SharedResource { private boolean ready = false; public synchronized void produce()
throws InterruptedException { ready = true; notify(); // wake up waiting consumer }
public synchronized void consume() throws InterruptedException { while (!ready) wait();
// wait until data is ready [Link]("Consuming!"); } }
Java vs C# Threads
Feature Java C#
Thread Class [Link] [Link]
Locking synchronized keyword lock keyword
Thread Pool ExecutorService ThreadPool, Task
async/await CompletableFuture (complex) Native async/await (simpler)
Semaphore [Link] SemaphoreSlim
Java — ExecutorService (Thread Pool) ●●●
import [Link].*; public class ExecutorDemo { public static void
main(String[] args) { // Create a pool of 3 threads ExecutorService executor =
[Link](3); for (int i = 1; i <= 6; i++) { final int taskNum = i;
[Link](() -> { [Link]("Task " + taskNum + " by " +
[Link]().getName()); }); } [Link](); } }
Page 14
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Quick Revision — Most Important Points
Unit III — Subprograms & Blocks
Topic Key Point
Subprogram Named code block; Procedure (void) vs Function (returns
value)
Scope Where a variable is visible in the code
Lifetime How long a variable exists in memory
Static Scope Based on code location — Java uses this!
Dynamic Scope Based on call chain — used in early LISP
Pass by Value Copy sent — original unchanged (Java primitives)
Pass by Reference Address sent — original can be changed (C++, C#)
Overloading Same name, different parameters — resolved at compile
time
Generics Type-safe code for any type using <T>
Coroutines Cooperative multitasking — can pause and resume
Unit IV — ADTs, OOP & Concurrency
Topic Key Point
ADT Defined by operations, not implementation (Stack,
Queue)
Encapsulation Data + methods in one unit. Use private fields +
getters/setters
Static Storage Compile-time. Global/static vars. Lives forever
Stack Storage Function call/return. Local variables. Automatic
Heap Storage Runtime, new keyword. Objects. Managed by GC
GC Java uses Generational GC (Young/Old Gen). No manual
free()
Race Condition Fix with synchronized / Semaphore / Monitor
Semaphore Counter-based lock. acquire() and release()
Monitor High-level. Java's synchronized keyword
Message Passing No shared memory. Threads communicate via messages
Java Thread Extend Thread OR implement Runnable OR use Lambda
Page 15
PPL Notes • Unit III & IV [Link] CSE • Sem 6
Principles of Programming Languages • Unit III & IV • [Link] CSE Sem 6
Study well. Best of luck! ■
Page 16