Introduction to PLs PDF
Document Details
Uploaded by ComplementaryZither918
Al Akhawayn University
Pr. Nabil BENAMAR
Tags
Summary
This document provides an introduction to programming languages (PLs). It covers learning objectives, reasons for studying programming languages, programming domains, language evaluation criteria, and other essential aspects.
Full Transcript
Introduction to PLs Pr. Nabil BENAMAR 1 Introduction to PLs Learning Objectives 1. Define the concept of a language. 2. Discuss the significance of studying programming language concepts. 3. Describe the syntax and semantics of a language. 4. Identify the main facto...
Introduction to PLs Pr. Nabil BENAMAR 1 Introduction to PLs Learning Objectives 1. Define the concept of a language. 2. Discuss the significance of studying programming language concepts. 3. Describe the syntax and semantics of a language. 4. Identify the main factors driving the evolution of programming languages. 5. Outline the different generations of programming languages. 6. Compare the computational models of imperative, functional, and declarative paradigms. 7. Evaluate the influence of machine architecture on programming languages. 8. Trace the progression from subprogram units to data units in program organization. 9. Explore various programming languages, including those of theoretical interest and those in widespread use. 2 Reasons for Studying Concepts of Programming Languages Improved background for Increased ability to Increased capacity choosing learn new to express ideas. appropriate languages. languages. Better Better use of Overall understanding of languages that are advancement of the significance of already known. computing. implementation. 3 Programming Domains Scientific Business Artificial Web Applications Applications Intelligence Software 4 Language Evaluation Criteria 5 Language Evaluation Criteria A second complicating characteristic of a programming language is: Feature Multiplicity: For example, in Java, a user can increment a simple integer variable in four different ways: 6 Language Evaluation Criteria 7 Language Evaluation Criteria A third potential problem is operator overloading Operator over-loading is further discussed in Chapter 7. 8 Language Evaluation Criteria Orthogonality The word orthogonal comes from the mathematical concept of orthogonal vectors, which are independent of each other 9 Data Types 10 Syntax Design The syntax, or form, of the elements of a language has a significant effect on the readability of programs. Special words while, class, and for Ada uses end if to terminate a selection construct and end loop to terminate a loop construct. 11 Writability Writability is a measure of how easily a language can be used to create programs for a chosen problem domain. Visual BASIC (VB) and C in GUI writing systems programs, such as an operating system 12 Reliability A program is said to be reliable if it performs to its specifications under all conditions. 13 Computer Architecture 14 Figure 1-1 The von Neumann computer architecture The fetch-execute cycle 16 Figure 1-2 Layered interface of virtual computers, provided by a typical computer system Figure 1-3 The compilation process Figure 1-4 Pure interpretation Figure 1-5 Hybrid implementation system Introduction to PLs What is a language? Language is a structured system of communication used by humans and, in different forms, by some other animals. In humans, language is characterized by the use of complex and dynamic systems of symbols, which can be vocal (spoken), gestural (as in sign languages), or graphical (written). vocal gestural graphical 21 Symbols Introduction to PLs What is a language? The concept of "language" can be generally defined as a system of communication that uses symbols arranged according to a set of rules to express information. This definition covers a wide range of systems, including both natural and formal languages. Examples: Natural Languages : English, Arabic, French, Mandarin Chinese, Spanish, Hindi, … Formal Languages : Python, C/C++, Java, HTML, SQL, Racket, Prolog, … Mathematical and Logical Languages : Predicate Logic, Algebraic Notation, … 22 Introduction to PLs Characteristics of Language 1. Symbolism: Languages use symbols, which are sounds, gestures, or written characters that represent objects, actions, ideas, and states. 2. Structure: Languages have grammar, a set of rules that dictate how symbols can be arranged and manipulated to produce meaningful statements. 3. Generativity: Using a finite set of symbols and rules, languages can generate an infinite number of messages and ideas. 4. Dynamism: Languages evolve and change over time, adapting to the needs of their users and influences from other languages and cultural changes. 5. Contextuality: The meaning in language often depends on context, including the speaker's intent, the situation, and the cultural background of the communication. 23 Introduction to PLs Symbols Symbols are the basic units of any language, representing sounds, letters, or objects: In spoken language : phonemes or words. In written language : letters and punctuation marks. In programming languages : characters, keywords, or operators. Examples: In English, the letters "A" through "Z" are symbols used to construct words. In mathematics, symbols include numerals (0-9), operations (+, -, *, /), and other special characters like π (pi), universal quantification ∀ ("given any"), Existential quantification ∃ ("there exists", "there is at least one") In programming, symbols in Python include keywords like def (to define functions), for (to start loops), and symbols like {} (used to define blocks of code). 24 Introduction to PLs Syntax Syntax refers to the set of rules that determine the arrangement of symbols to form valid structures: such as sentences in natural languages or commands in programming languages. Examples: In English, a basic syntactic rule is that a typical sentence structure follows the Subject-Verb-Object order: "She (subject) eats (verb) apples (object)." In programming, Python uses indentation to define blocks of code, which is a syntactic requirement. For example: for i in range(5): print(i) # This print statement is part of the for loop due to indentation 25 Introduction to PLs Semantics Semantics concerns the meanings of words, phrases, symbols, and structures. It deals with how the combinations of symbols are interpreted by the speakers of a language or the executors of programming languages. Examples: In English, the word "bank" can mean the "edge of a river" or a "financial institution", depending on the context. In logic, the statement “if P then Q" has the semantic interpretation that Q is a consequence of P. In programming, consider the Python function: def square(x): return x * x 26 The semantics of this function are that it takes a number x and returns its square. Introduction to PLs What is a Programing Language (PL)? Programming language is a complex tool designed to facilitate the creation of software, controlling hardware, and expressing algorithms. PL is defined by several foundational characteristics: Based on a formal language : constructed with a specific set of syntactic and semantic rules that govern the structure of valid program statements and expressions, ensuring that they can be unambiguously interpreted and executed by a computer. Interact with computer : Programming languages are the primary means through which humans communicate instructions to computers. They allow programmers to specify precisely what computations a computer should perform. 27 Introduction to PLs What is a Programing Language (PL)? In summary, programming languages are indeed based on formal languages and designed to allow humans to create a broad range of computational solutions efficiently without ambiguity. They are governed by specific rules of syntax and semantics, can interact with computer systems. 28 Introduction to PLs Factors affecting PL evolution The evolution of programming languages is influenced by a variety of factors ranging from technological advancements to changes in user needs and computational paradigms. Understanding these factors can provide insights into why programming languages develop as they do and what might influence future trends: 1. Technological Advancements 2. Developer Productivity and Ease of Use 3. Community and Ecosystem 4. Industry Trends and Market Demand 5. Educational Influences 6. Performance and Efficiency 7. Interoperability 29 Introduction to PLs Factors affecting PL evolution 1. Technological Advancements Hardware Improvements: Increases in processor speed, memory, storage capacity, and networking capabilities can drive the development of new programming features and languages. For instance, the advent of multicore processors has influenced languages to incorporate better support for concurrency and parallelism. New Platforms: The rise of mobile computing, cloud services, and more recently, the Internet of Things (IoT), has encouraged the development of languages and tools optimized for these platforms, such as Swift for iOS and Kotlin for Android. 30 Introduction to PLs Factors affecting PL evolution 2. Developer Productivity and Ease of Use Higher-Level Abstractions: Languages evolve to offer higher levels of abstraction to simplify complex tasks and improve developer productivity. For example, Python abstracts many lower-level details to simplify coding, which has contributed to its widespread adoption. Better Tooling and IDE Support: Enhancements in integrated development environments (IDEs) and other tools can drive language adoption and evolution. Languages that integrate well with powerful development tools often see increased use. 31 Introduction to PLs Factors affecting PL evolution 3. Community and Ecosystem Open-Source Communities: The growth and activity of a language's community can significantly impact its development. Open-source projects allow for more collaborative development and faster iteration of language features. Library and Framework Ecosystem: The availability of robust libraries and frameworks can make a language more attractive for certain applications, as seen with JavaScript and the Node.js ecosystem for server-side programming. 32 Introduction to PLs Factors affecting PL evolution 4. Industry Trends and Market Demand Demand for New Applications: Changes in market demand, such as the rise of data science and machine learning, have led to the evolution of languages like Python, which is favored for its rich ecosystem of data analysis libraries and frameworks. Regulatory and Security Concerns: Increasing attention to cybersecurity and data privacy can influence language development to emphasize secure coding practices and include better security features. 33 Introduction to PLs Factors affecting PL evolution 5. Educational Influences Curriculum Development: The languages taught in academic settings can influence industry trends as new graduates enter the workforce with specific language skills. For example, the adoption of Java in university computer science courses has contributed to its enduring popularity in enterprise applications. 34 Introduction to PLs Factors affecting PL evolution 6. Performance and Efficiency Optimization for Performance: The need for high-performance computing (HPC) drives the development of languages that can efficiently utilize hardware, manage memory more effectively, and execute tasks faster. Languages like Rust are gaining attention for their ability to provide memory safety without sacrificing performance. Energy Efficiency: With increasing awareness of energy consumption in computing, languages that can run more efficiently on less power are becoming more important, particularly for mobile and embedded devices. 35 Introduction to PLs Factors affecting PL evolution 7. Interoperability Compatibility with Other Languages: The ability to interoperate with other languages and systems can affect a language's evolution. For example, Kotlin's interoperability with Java has significantly aided its adoption for Android development. 36 Introduction to PLs PL evolution The evolution of programming languages is a fascinating journey through the history of computing, reflecting changes in technology, theory, and practical needs. 1. Early Developments (1940s-1950s) Machine Language and Assembly Language: Early computers were programmed using machine language, a set of binary codes directly understood by a computer's hardware. This process was cumbersome and error-prone, leading to the development of assembly languages, which use mnemonic codes (e.g., ADD for addition) to represent machine instructions. This allowed for somewhat easier programming but still required detailed hardware knowledge. 2. High-Level Languages (1950s-1960s) Fortran (1957): Developed by IBM, Fortran (Formula Translation) was the first high-level programming language, designed to allow easy translation of math formulas into code. It was primarily used for scientific and engineering calculations. COBOL (1959): Aimed at business data processing, COBOL (Common Business-Oriented Language) was designed to be readable by non-scientists, emphasizing clear syntax similar to English. 37 LISP (1958): Created for artificial intelligence research, LISP introduced many features now common in modern languages, including automatic garbage collection and dynamic typing. Introduction to PLs PL evolution 3. Structured Programming (1970s) C (1972): Developed by Dennis Ritchie at Bell Labs, C introduced efficient low-level access to memory and system resources but within a structured format. This balance made it ideal for system software development, notably for implementing operating systems like Unix. Pascal (1970): Designed by Niklaus Wirth as a teaching tool for structured programming, Pascal introduced many to the concepts of data structures and modular programming. 4. Object-Oriented Programming (1980s) Smalltalk (1980): Pioneered many concepts integral to object-oriented programming, such as classes and inheritance. C++ (1983): An extension of C, introduced by Bjarne Stroustrup, which incorporated object-oriented features into the powerful systems programming language. 38 Introduction to PLs PL evolution 5. Internet and Web Development (1990s) Java (1995): Designed with a strong emphasis on portability across different platforms, Java was crucial for web and network applications. Its "Write Once, Run Anywhere" philosophy expanded its use widely. JavaScript (1995): Created to make web pages interactive, JavaScript has become one of the most influential languages for client-side scripting on the internet. 6. Modern Developments (2000s to present) Python: Gained immense popularity due to its simplicity and readability, coupled with powerful libraries for web development, data analysis, and machine learning. Swift (2014): Introduced by Apple for iOS and macOS development as a replacement for Objective-C, offering safer memory management and modern language features. Rust (2010): Designed for system-level programming, focusing on safety and concurrency without sacrificing performance. 39 Introduction to PLs Introduction to Programming Paradigms In software engineering, programming paradigms refer to the fundamental styles or philosophies that govern the design and construction of software programs. Each paradigm emphasizes different programming concepts and structures and is suited to specific kinds of problems. Understanding these paradigms can help developers choose the most effective approach for their projects. Paradigms can significantly influence the architecture of software systems, the development process, and ultimately, the performance and maintainability of the applications. 40 Introduction to PLs Introduction to Programming Paradigms Programming Paradigms 1. Imperative Programming 2. Procedural Programming 3. Object-Oriented Programming (OOP) 4. Functional Programming 5. Logic Programming 6. Declarative Programming 7. Event-Driven Programming 41 Introduction to PLs Introduction to Programming Paradigms 1. Imperative Programming Description: This paradigm is based on a series of commands for the computer to perform. It's the most direct way of telling the computer what to do, step by step. Key Features: Uses loops, conditionals, and other control structures to operate on data stored in variables. Common Languages: C, C++, Java, Python. 2. Procedural Programming Description: A subtype of imperative programming that organizes code into procedures or subroutines. Key Features: Code reusability through functions and procedures which reduce redundancy and complexity. Common Languages: C, Pascal, Fortran. 42 Introduction to PLs Introduction to Programming Paradigms 3. Object-Oriented Programming (OOP) Description: Structures programs around objects rather than actions and data rather than logic. Key Features: Encapsulation, inheritance, and polymorphism. Common Languages: Java, C++, Python, Ruby. 4. Functional Programming Description: Treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. Key Features: First-class functions, higher-order functions, pure functions, immutability. Common Languages: Haskell, Erlang, Clojure, Scala. 43 Introduction to PLs Introduction to Programming Paradigms 5. Logic Programming Description: Based on formal logic, a program consists of a set of sentences in logical form, expressing facts and rules about some problem domain. Key Features: Rule-based, uses a declarative format to pose queries and make assertions. Common Languages: Prolog, Datalog. 6. Declarative Programming Description: Expresses the logic of a computation without describing its control flow. Key Features: Focuses on what needs to be accomplished rather than how to achieve it, making it different from imperative programming. Common Domains: SQL for databases, HTML and CSS for web design. 44 Introduction to PLs Introduction to Programming Paradigms 7. Event-Driven Programming Description: Driven by events or changes in state which trigger certain functions or processes. Key Features: Uses event handlers and callback functions to structure the flow of a program. Common Uses: GUI applications, web applications. 45 Introduction to PLs Introduction to Programming Paradigms Imperative Programming Example in C Here is a simple example of imperative programming using C to calculate the factorial of a number: #include int factorial(int n) { int result = 1; for (int i = 1; i Integer factorial 0 = 1 factorial n = n * factorial (n - 1) main = print (factorial 5) 49 Introduction to PLs Introduction to Programming Paradigms Logic Programming Example in Prolog Here is a simple example of a logic program written in Prolog that defines family relationships: % Facts: parent(alice, bob). parent(bob, charlie). parent(bob, diana). % Rules: grandparent(X, Z) :- parent(X, Y), parent(Y, Z). % Querying the grandparent relationship: ?- grandparent(alice, Who). 50 Introduction to PLs Introduction to Programming Paradigms Declarative Programming Example in SQL SQL (Structured Query Language) is a classic example of declarative programming applied to database queries. Here is a simple SQL query that demonstrates the declarative nature: SELECT name, age FROM users WHERE age > 18 ORDER BY age DESC; 51 Introduction to PLs Introduction to Programming Paradigms Event-driven Programming Example in JavaScript Here is a simple example of event-driven programming used in a web context with JavaScript: document.getElementById("myButton").addEventListener("click", function() { alert("Button clicked!"); }); 52 Introduction to PLs Program Organization Models Program organization models describe the primary structure and methodologies for arranging the components of software programs. These models dictate how data and control structures are laid out, how tasks are divided and coordinated, and how overall maintainability and scalability are addressed. 53 Introduction to PLs Program Organization Models Abstract Data Type (ADT) An Abstract Data Type (ADT) is a theoretical concept in computer science that defines a data type by its behavior from the point of view of a user of the data, specifically in terms of possible values, possible operations on data of this type, and the behavior of these operations. This definition encapsulates the data and operations without specifying how they are implemented. The focus is on what operations the data type can perform and not on how these operations will be carried out. ADTs are used to provide a mathematical model of the data structures that implement them. 54 Introduction to PLs Program Organization Models Abstract Data Type (ADT) Characteristics of Abstract Data Types Encapsulation: ADTs encapsulate the data and the operations that manipulate the data, hiding the implementation details from the user. Modularity: Since the implementation details are hidden, changes to the implementation do not affect the user of the ADT. This makes programs more modular and easier to change. Abstraction: ADTs provide a high level of abstraction, allowing programmers to think about data in terms of its operations, not its representation. 55 Introduction to PLs Program Organization Models Abstract Data Type (ADT) Common Examples of Abstract Data Types 1. List: Operations: Insert, delete, find, access by position. Use: Sequence of elements which can be manipulated independently. 2. Stack: Operations: Push (add an item), pop (remove the top item), peek (view the top item). Use: Follows the Last In, First Out (LIFO) principle, useful for undo mechanisms, parsing, backtracking algorithms, etc. 3. Queue: Operations: Enqueue (add to the back), dequeue (remove from the front), peek (view the front item). Use: Follows the First In, First Out (FIFO) principle, used in scheduling tasks, buffering data streams, etc.. 4. Set: Operations: Add, remove, check membership, union, intersection, difference. Use: Collection of unique elements with no specific order, useful for membership checking, removing duplicates, set operations. Introduction to PLs Program Organization Models Abstract Data Type (ADT) Common Examples of Abstract Data Types 5. Map (Dictionary): Operations: Insert key-value pair, delete key, find value by key. Use: Stores associations between keys and values, useful for lookup tables, database indexing, caching data. 6. Tree: Operations: Insert, delete, traverse (e.g., pre-order, in-order, post-order), search. Use: Hierarchical data storage, provides efficient searching and sorting. 7. Graph: Operations: Add vertex, add edge, find path, traverse. Use: Represents networks, such as social connections, routing algorithms, and network flows. 57 Introduction to PLs Program Organization Models Abstract Data Type (ADT) Example: Stack as an Abstract Data Type A stack is a collection of elements with two main operations: 1. Push: Add an element to the top of the stack. 2. Pop: Remove and return the element from the top of the stack. Characteristics of a Stack: LIFO (Last In, First Out): The last element added is the first one to be removed. Operations: push(element): Adds element to the top of the stack. pop(): Removes and returns the element at the top of the stack. peek(): Returns the top element without removing it. 58 is_empty(): Checks if the stack is empty. Introduction to PLs Program Organization Models Abstract Data Type (ADT) Example: Stack as an Abstract Data Type stack.h (Header File) #ifndef STACK_H #define STACK_H #define MAX_SIZE 100 // Maximum size of the stack // Define the Stack structure typedef struct { int data[MAX_SIZE]; int top; } Stack; // Function declarations for Stack operations void initialize(Stack *s); int is_empty(Stack *s); int is_full(Stack *s); void push(Stack *s, int element); int pop(Stack *s); 59 int peek(Stack *s); #endif Introduction to PLs Program Organization Models Abstract Data Type (ADT) Example: Stack as an Abstract Data Type stack.c (Implementation File) #include "stack.h" #include #include // Initialize the stack void initialize(Stack *s) { s->top = -1; // Stack is initially empty } // Check if the stack is empty int is_empty(Stack *s) { return s->top == -1; } // Check if the stack is full int is_full(Stack *s) { return s->top == MAX_SIZE - 1; 60 } Introduction to PLs Program Organization Models Abstract Data Type (ADT) Example: Stack as an Abstract Data Type stack.c (Implementation File) // Push an element onto the stack void push(Stack *s, int element) { if (is_full(s)) { printf("Stack overflow\n"); exit(1); } s->data[++(s->top)] = element; } // Pop an element from the stack int pop(Stack *s) { if (is_empty(s)) { printf("Stack underflow\n"); exit(1); } return s->data[(s->top)--]; 61 } Introduction to PLs Program Organization Models Abstract Data Type (ADT) Example: Stack as an Abstract Data Type stack.c (Implementation File) // Peek at the top element of the stack int peek(Stack *s) { if (is_empty(s)) { printf("Stack is empty\n"); exit(1); } return s->data[s->top]; } 62 Introduction to PLs Program Organization Models Modular programming Modular programming is a software design technique that emphasizes dividing a program into separate, interchangeable modules that are independently developed but work together to form a complete system. This approach is based on the concept of modularity, aiming to make software easier to build, debug, maintain, and scale. 63 Introduction to PLs Program Organization Models Modular programming Characteristics of Modular Programming Decomposition: The entire functionality of the program is divided into discrete modules that can be developed and tested in isolation from the rest of the program. Encapsulation: Each module encapsulates its data and behavior, exposing only the necessary parts through a well-defined interface. This hides the internal details of the modules, reducing the complexity for other parts of the program. Reusability: By isolating functionality into modules, these components can be reused in different parts of the program or in different programs altogether. Interchangeability: If a module needs to be replaced or upgraded, it can be done so without a significant impact on the rest of the system, provided the new module conforms to the same interface. Maintainability: Debugging and maintenance become easier because changes are localized to a module or a small set of modules. Understanding a single module does not require understanding the entire codebase. Introduction to PLs Program Organization Models Modular programming Common Practices in Modular Programming Interfaces: Define clear interfaces for each module. An interface specifies what a module will do without having to specify how it does it, using function signatures and data types. Information Hiding: Keep data and details about the module hidden from other modules. This is usually achieved through access specifiers in the programming language, such as private, protected, and public in languages like Java and C++. Loose Coupling: Modules should be as independent as possible from other modules. This means minimizing the dependencies between modules so that changes in one module require minimal changes to others. High Cohesion: Each module should have a well-defined purpose or responsibility with all its parts working together towards that purpose. This means that the module should not be a random collection of unrelated functions or data. Introduction to PLs Program Organization Models Modular programming Examples of Modular Programming Operating Systems: Operating systems like Linux are composed of various modules, each handling specific tasks such as file system management, network management, or memory management. These modules can be developed independently and loaded dynamically as needed. Libraries and Frameworks: Many software libraries are designed as collections of modules. For instance, the standard libraries in languages like Python and JavaScript consist of modules for file handling, network communications, and system management, among others. 66 Introduction to PLs Program Organization Models Modular programming Advantages of Modular Programming Simplifies Complex Systems: By breaking down a system into manageable parts, developers can focus on one area at a time without being overwhelmed by the complexity of the entire system. Enhances Collaborative Development: Multiple developers or teams can work on different modules simultaneously, speeding up the development process. Facilitates Scalability: The system can grow more easily by adding new modules or improving existing ones without affecting other parts of the software. Improves Code Quality: Encapsulation and localizing changes reduce the chance of bugs propagating through the system, improving overall code quality. 67 Introduction to PLs Program Organization Models Modular programming Example: Simple Modular Program in C Let's create a simple program that calculates the area and perimeter of a rectangle. We'll divide the program into separate modules for input, calculation, and output. Step 1: Define the Modules 1. Input Module: Handles getting the length and width of the rectangle from the user. 2. Calculation Module: Contains functions to calculate the area and perimeter of the rectangle. 3. Output Module: Handles displaying the results to the user. 68 Introduction to PLs Program Organization Models Modular programming Example: Simple Modular Program in C Step 2: Create the Modules input.h (Header for Input Module) #ifndef INPUT_H #define INPUT_H void get_dimensions(double *length, double *width); #endif input.c (Implementation for Input Module) #include #include "input.h" void get_dimensions(double *length, double *width) { printf("Enter the length of the rectangle: "); scanf("%lf", length); printf("Enter the width of the rectangle: "); 69 scanf("%lf", width); } Introduction to PLs Program Organization Models Modular programming Example: Simple Modular Program in C Step 2: Create the Modules calculation.h (Header for Calculation Module) #ifndef CALCULATION_H #define CALCULATION_H double calculate_area(double length, double width); double calculate_perimeter(double length, double width); #endif calculation.c (Implementation for Calculation Module) #include "calculation.h" double calculate_area(double length, double width) { return length * width; } double calculate_perimeter(double length, double width) { return 2 * (length + width); 70 } Introduction to PLs Program Organization Models Modular programming Example: Simple Modular Program in C Step 2: Create the Modules output.h (Header for Output Module) #ifndef OUTPUT_H #define OUTPUT_H void display_results(double area, double perimeter); #endif output.c (Implementation for Output Module) #include #include "output.h" void display_results(double area, double perimeter) { printf("Area of the rectangle: %.2lf\n", area); printf("Perimeter of the rectangle: %.2lf\n", perimeter); 71 } Introduction to PLs Program Organization Models Modular programming Example: Simple Modular Program in C Step 3: Main Program main.c (Main Program) #include "input.h" #include "calculation.h" #include "output.h" int main() { double length, width; // Get the dimensions from the user get_dimensions(&length, &width); // Calculate area and perimeter double area = calculate_area(length, width); double perimeter = calculate_perimeter(length, width); // Display the results display_results(area, perimeter); return 0; 72 } Introduction to PLs Program Organization Models Modular programming Example: Simple Modular Program in C Step 4: Compile and Run To compile and run this modular program, use the following commands: gcc -o rectangle main.c input.c calculation.c output.c./rectangle 73 Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) Concept: Aims to increase modularity by allowing the separation of cross-cutting concerns (aspects), such as logging and security, which affect multiple parts of a program. AOP involves an additional compilation step that weaves aspect-related code into the main program logic. Example Languages: AspectJ. 74 Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) Example: Logging with AspectJ Let's consider a simple example where we want to log the execution of methods in a banking application. Instead of adding logging code directly into every method, we'll use AspectJ to handle logging as an aspect. Step 1: Create the Main Application Create a simple banking application with methods for deposit and withdrawal. 75 Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) Example: Logging with AspectJ BankAccount.java public class BankAccount { private int balance; public BankAccount(int initialBalance) { this.balance = initialBalance; } public void deposit(int amount) { balance += amount; System.out.println("Deposited " + amount + ". New balance: " + balance); } public void withdraw(int amount) { if (balance >= amount) { balance -= amount; System.out.println("Withdrew " + amount + ". New balance: " + balance); } else { System.out.println("Insufficient funds. Current balance: " + balance); } 76 } } Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) Example: Logging with AspectJ Main.java public class Main { public static void main(String[] args) { BankAccount account = new BankAccount(100); account.deposit(50); account.withdraw(30); account.withdraw(150); } } Step 2: Define the Logging Aspect The logging aspect will intercept method executions in the BankAccount class and log them. 77 Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) import org.aspectj.*; @Aspect public class LoggingAspect { // Define a pointcut for all methods in BankAccount class @Pointcut("execution(* BankAccount.*(..))") public void allMethods() {} // Before advice: Run this before the method execution @Before("allMethods()") public void beforeMethod(JoinPoint joinPoint) { System.out.println("Before method: " + joinPoint.getSignature().getName()); } // After advice: Run this after the method execution @After("allMethods()") public void afterMethod(JoinPoint joinPoint) { System.out.println("After method: " + joinPoint.getSignature().getName()); 78 } Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) // After returning advice: Run this after the method successfully returns @AfterReturning("allMethods()") public void afterReturningMethod(JoinPoint joinPoint) { System.out.println("Method " + joinPoint.getSignature().getName() + " executed successfully."); } // After throwing advice: Run this if the method throws an exception @AfterThrowing(pointcut = "allMethods()", throwing = "error") public void afterThrowingMethod(JoinPoint joinPoint, Throwable error) { System.out.println("Method " + joinPoint.getSignature().getName() + " threw an exception: " + error.getMessage()); } } 79 Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) Step 3: Compile and Run To compile and run the program with AspectJ, you'll need the AspectJ tools. 1. Compile with AspectJ: Ensure you have AspectJ installed. Compile the Java files and the AspectJ aspect file. ajc -1.8 -d. BankAccount.java Main.java LoggingAspect.aj 2. Run the Program: java Main 80 Introduction to PLs Program Organization Models Aspect-Oriented Programming (AOP) Expected Output When you run the program, the aspect will log method executions: Before method: deposit Deposited 50. New balance: 150 After method: deposit Method deposit executed successfully. Before method: withdraw Withdrew 30. New balance: 120 After method: withdraw Method withdraw executed successfully. Before method: withdraw Insufficient funds. Current balance: 120 After method: withdraw Method withdraw executed successfully. 81 Introduction to PLs Program Organization Models Layered Architecture Concept: Organizes applications into layers with each layer performing a specific role within the application. Typical layers include presentation, business logic, data access, and database layers. Each layer interacts only with the layer directly below, which helps manage dependencies and separates concerns. Common in: Enterprise applications and information systems. 82 Introduction to PLs Program Organization Models Layered Architecture Example: E-commerce Application Let’s consider a simple e-commerce application with a layered architecture. We’ll divide the application into four layers: 1. Presentation Layer (UI Layer): Handles user interactions. 2. Service Layer (Business Logic Layer): Contains the business logic of the application. 3. Data Access Layer (Persistence Layer): Handles interactions with the database. 4. Database Layer: Stores data. 83 Introduction to PLs Program Organization Models Layered Architecture Example: E-commerce Application 1. Presentation Layer: This layer is responsible for displaying information to the user and interpreting user inputs. 2. Service Layer: The service layer contains the business logic. It processes inputs from the presentation layer, interacts with the data access layer, and returns the results to the presentation layer. 3. Data Access Layer: This layer handles the communication between the service layer and the database. It performs CRUD (Create, Read, Update, Delete) operations on the database. 4. Database Layer: This layer represents the actual database where the data is stored. 84 Introduction to PLs Program Organization Models Component-Based Development (CBD) Concept: Focuses on the reuse of existing software components, or the creation of reusable components, which can be assembled with well-defined interfaces to form a complete application. This model emphasizes the interconnectivity of components via interfaces and the reusability of software entities. Example Technologies: COM/DCOM, Java Beans,.NET components. 85 Introduction to PLs Program Organization Models Generic programming Generic programming is a programming paradigm that emphasizes the efficient reuse of software components through the use of highly abstracted, reusable algorithms and data structures. It is designed to work with data types that can be specified and used when needed, thus maximizing code flexibility, reusability, and efficiency. 86 Introduction to PLs Program Organization Models Generic programming Concepts of Generic Programming Type Abstraction: In generic programming, algorithms and data structures are written in terms of types to be specified later. This allows them to work with any data type that meets certain requirements, without being tied to specific data types at the time of writing. Parameterized Types: Generic programming makes extensive use of parameterized types, also known as templates in C++ or generics in languages like Java and C#. These are a way of defining classes, interfaces, and methods with placeholders for the types they operate on. This allows a class or method to be reused with different data types without being rewritten for each one. 87 Introduction to PLs Program Organization Models Generic programming Benefits of Generic Programming Reusability: Allows developers to create more general and reusable components. For instance, a generic sorting function can be used to sort lists of integers, floats, or objects, provided that these can be compared. Type Safety: Generic programming avoids the need for type casts that are both error-prone and potentially unsafe. Performance: By enabling type-specific optimizations at compile time, generic programming can often be as fast as code written for specific types, because it eliminates the overhead of type checks and conversions found in dynamically typed languages. 88 Introduction to PLs Program Organization Models Generic programming Examples of Generic Programming Standard Template Library (STL) in C++: STL is a prime example of generic programming, offering a collection of classes and functions for data structures (like vectors, lists, and maps) and algorithms (like sort, search, and transform) that can work with any data type. Generics in Java and C#: These languages use generics to allow classes like ArrayList or methods like void sort(List list), where T is a type parameter. This lets the same code work with any object types while maintaining type safety and avoiding the performance cost of boxing or unboxing. 89 Introduction to PLs Program Organization Models Generic programming Example: Generic Class for a Box Let’s create a simple generic class that can hold any type of object. public class Box { private T item; public Box(T item) { this.item = item; } public T getItem() { return item; } public void setItem(T item) { this.item = item; } public void displayItemType() { System.out.println("The type of item in the box is: " + item.getClass().getName()); 90 } } Introduction to PLs Program Organization Models Generic programming Example: Generic Class for a Box public class Main { public static void main(String[] args) { // Create a Box to store an Integer Box integerBox = new Box(10); System.out.println("Item in integerBox: " + integerBox.getItem()); integerBox.displayItemType(); // Output: java.lang.Integer // Create a Box to store a String Box stringBox = new Box("Hello, Generics!"); System.out.println("Item in stringBox: " + stringBox.getItem()); stringBox.displayItemType(); // Output: java.lang.String // Create a Box to store a Double Box doubleBox = new Box(15.5); System.out.println("Item in doubleBox: " + doubleBox.getItem()); doubleBox.displayItemType(); // Output: java.lang.Double 91 } } Introduction to PLs Sequential and Parallel Computing Sequential programming and parallel programming are two fundamental approaches to writing software, each with its specific characteristics and applications. The differences between these approaches can help in choosing the right programming style for a particular problem or to optimize performance. MPI (Message Passing Interface) is a popular library for parallel programming, especially in distributed memory systems like clusters. It allows processes to communicate with each other by sending and receiving messages. 92 Introduction to PLs Sequential and Parallel Computing Sequential Programming Sequential programming is the traditional model of programming in which commands are executed one after another. This means that each statement must wait for the previous statement to finish before it begins. Characteristics: Linear Execution: Instructions are executed in a linear sequence, one at a time. Simplicity: Generally easier to implement and debug because the flow of execution is straightforward. Deterministic: The program's behavior is predictable as the same input always produces the same output. Limitations: Performance: Can be slow for intensive tasks because it doesn't utilize multiple processors or cores effectively. Underutilization of Resources: In systems with multiple processors or cores, sequential programming may not fully utilize the available hardware. 93 Introduction to PLs Sequential and Parallel Computing Parallel Programming Parallel programming involves performing multiple operations simultaneously. This approach can significantly speed up computing processes, particularly those that are computationally intensive and can be divided into independent tasks. Characteristics: Concurrency: Executes multiple instructions simultaneously, using multiple processing units. Complexity: More complex to design, implement, and debug due to issues like data synchronization, race conditions, and deadlocks. Efficiency: Can significantly reduce program execution time by utilizing multi-core or multiple processors effectively. Challenges: Synchronization: Managing how multiple tasks access shared resources can be challenging and prone to errors. Deadlocks and Race Conditions: Proper management of resources is necessary to avoid these issues where two or more operations get stuck waiting on each other, or they 94run in an unexpected order. Introduction to PLs Sequential and Parallel Computing Example 1: Sequential Computing (Summing Numbers) In sequential computing, a single process sums the numbers from 1 to n. #include int main() { int n = 100; int sum = 0; // Sequentially sum numbers from 1 to n for (int i = 1; i