Principles of Programming
Languages – Unit III
Subprograms and Implementations
Introduction to Subprograms
• → Subprograms are modules that perform specific operations
• → They improve modularity, readability, and reusability
• → Types: Procedures (no return) and Functions (return value)
• → Called by main programs or other subprograms
• → Single entry point and returns control to the caller
Subprogram Structure
• → Header: name, parameters, return type
• → Body: logic and statements
• → Declaration defines interface; definition implements logic
• → Example (C): int add(int a,int b); int add(int a,int b){return a+b;}
• → Header defines protocol between caller and callee
Calling and Returning
• → Caller suspended during subprogram execution
• → Control always returns to caller after completion
• → Example (Python): def greet(): print('Hello'); greet()
• → Supports hierarchical and modular programming
Parameter Binding
• → Positional binding: Arguments bound by order
• → Keyword binding: Arguments matched by parameter names
• → Default parameters: Optional values in header
• → Example (Python): def display(msg='Welcome'): print(msg)
• → display() uses default, display('Hello!') overrides
Variable Number of Parameters
• → Some languages allow flexible argument lists
• → C#: uses 'params'
• → Python: uses *args and **kwargs
• → Example (Python): def add(*nums): return sum(nums)
• → print(add(2,3,4))
• → Useful for generic utilities
Procedures vs Functions
• → Procedures perform actions, may modify variables, no return
• → Functions return a value
• → Example (C): void printSum(int a,int b){printf('%d',a+b);} int
sum(int a,int b){return a+b;}
• → Functions can be reused in expressions
Design Issues in Subprograms
• → Consider concurrency, memory, and performance
• → Includes synchronization, portability, scalability, debugging
• → Proper design improves parallel performance
• → Example: using threads safely
Local Referencing Environments
• → Local variables can be static or stack-dynamic
• → Stack-dynamic supports recursion
• → Static variables retain value between calls
• → Example (C): static int x=0; x++
Parameter Passing Methods
• → In mode: only value passed
• → Out mode: result returned to caller
• → Inout mode: allows both input and modification
• → Example (C++): void swap(int &a,int &b){int t=a; a=b; b=t;}
Pass-by-Value and Result
• → Pass-by-Value: copies value; safe but can be slow
• → Pass-by-Result: sends back computed result
• → Pass-by-Value-Result: combination
• → Example (C): arguments by value, Fortran allows in/out
parameters
Pass-by-Reference and Name
• → Pass-by-Reference: passes address; efficient but risky
• → Pass-by-Name: textual substitution (Algol-style)
• → Example (Python): def modify(x): [Link](5); a=[1,2]; modify(a)
Parameter Checking
• → Static Checking: compile time (C, Java)
• → Dynamic Checking: runtime (Python)
• → Ensures type safety and reliability
• → Some languages allow prototypes for optional checking
Overloaded Methods
• → Multiple subprograms with same name but different parameters
• → Distinguished by parameter profile (signature)
• → Example (C++): int add(int a,int b); double add(double a,double
b);
• → Allows reuse for similar actions
Generic (Polymorphic) Methods
• → Operate on multiple data types
• → Enable type-safe reusable functions
• → Example (C++): template<class T> T max(T a,T b){return a>b?a:b;}
Function Modularity & Reuse
• → Modular design: independent development and testing
• → Functions reusable across modules
• → Avoid redundant logic using helpers
• → Example: utility functions for validation
Error Handling in Functions
• → Handle errors via exceptions, return codes, or assertions
• → Example (Python): try: result=compute() except ValueError:
print('Invalid data')
• → Document behavior for predictable usage
Minimizing Side Effects
• → Pure functions: no side effects
• → Avoid modifying globals inside functions
• → Example (Bad Python): total=0; def add(x): global total; total+=x
• → Prefer returning results instead
Input Validation & Documentation
• → Validate input types and constraints
• → Document function’s purpose, parameters, return
• → Example Python docstring: def divide(a,b): 'Return division
result; raises error if b=0' return a/b
Function Testing & Performance
• → Unit testing ensures correctness
• → Profiling identifies performance bottlenecks
• → Avoid premature optimization
• → Use efficient algorithms and structures
Semantics of Calls and Returns
• → Defines how control and data are transferred
• → Involves saving state, parameter passing, return address
• → Example (C): result=add(2,3)
• → After execution, control returns with result
Implementing Simple Subprograms
• → Subprogram’s non-code part = Activation Record
• → Contains local variables, parameters, return address
• → Each call creates activation record on stack
• → Ensures proper isolation between calls
Stack & Dynamic Local Variables
• → Dynamic locals allow recursion and multiple activations
• → Managed through runtime stack
• → Each call creates a new activation record
• → Environment Pointer (EP) points to current stack frame
Nested Subprograms
• → Some languages allow functions inside others
• → Supports encapsulation and better organization
• → Example (Python): def outer(): def inner(): print('Nested'); inner()
Accessing Non-local Variables
• → Nested subprograms can access outer variables (lexical scoping)
• → Example (Python): def outer(): x=10; def inner(): print(x)
Blocks
• → Blocks define user-created local scopes
• → Lifetime of variables limited to block
• → Prevents name conflicts, improves memory reuse
• → Example (C): { int temp=0; temp++; }
Dynamic Scoping
• → Variable bindings determined at runtime
• → Opposite of static scoping
• → Common in early Lisp versions
• → Access chain = dynamic chain of active subprograms
Dynamic Scoping Example
• → A calls B; B calls C; C references variable from A
• → With dynamic scoping, lookup follows call chain
• → Difficult to debug, mostly replaced by static scoping
Summary – Subprogram Design
• → Subprograms improve modularity and reuse
• → Proper parameter passing avoids errors
• → Activation records manage runtime control flow
• → Scoping defines visibility and lifetime
End Slide
• → Unit III – Subprograms and Implementations
• → Subprograms form the foundation of structured programming
• → Understanding scope, lifetime, and calling mechanisms ensures
efficient design