Please enable JavaScript.
Coggle requires JavaScript to display documents.
COMP26020 Programming Languages and Paradigms - Coggle Diagram
COMP26020 Programming Languages and Paradigms
C
Programming Paradigms
What is a programming paradigm?
Defines a fundamental style of programming and how the programmer describes the program in the source code with the data and computations
A language belongs to one or several paradigms
Functional (Haskell/OCaml)
Object Oriented (C#/C++/OCaml)
Logical (Prologue)
A paradigm is a programming style that describes a computation
It defines how the programmer describes the program computations and the data computations are applied on
sequential/parallel statements
how the result looks
functions
basic types
custom data structures
global/local variables
Picking a Programming Paradigm
Choosing a language to solve a problem implicitly selects some paradigms
This has consequences on how to design the solution and map it to the code and impacs the efficiency, size, complexity, clarity of the code
Imperative
Programmer describes sequences of statements maipulating the program state
Structured
Programmer uses advanced control flow operations e.g. loops, conditionals, procedured
Easier to describe/reason about complex/large programs
Their modularity makes it easier to write code for medium/large programs as there is less complexity and code is easier to understand, test and develop
Object-oriented
Encapsulation of code and the associated data into objects
Well suited to represent problems with a lot of state/operations
Ease reasoning about/organisaing large codebases, but can be overkill for small programs
Allows code resue through concepts such as inheritance and polymorphism
Concurrent
The programmer uses execution threads/processes to describe interleaving and/or parallel computation flows
Many imperative languages provide ways to exploit concurrency e.e. shared-memory threads/processes, message passing, loop-parallelisation etc
Declarative
The programmer describes the meaning/result of computations with high level abstraction, used in document rendering, structured data storage and manipulation
Functional
Calling and composing functions to describe the program
First-class/higher-order functions
Loops implemented with recursion
Pure functions have no side-effects
Concurrent
Less need for synchronisation
Used in distributed applications, web services etc
Multi-paradigm Languages
Haskell: purely functional
OCaml: mainly functional, allows OO and imperative constructs
C, C++: imperative but allow some functional idioms
Extra Details
Compilation is the transformation of the program's textual source code into machine code that can be executed by the CPU
A first-class function is a function that can be passed as a parameter to other functions and returned from other functions
C Basics
Characteristics
Pros
Syntax
Low level
Fast - no checks
Controlled memory footprint
Cons
Large area for making mistakes
Lack of memory safety, hence undefined behviour at runtime
Used in systems software, high performance computing, embedded systems, virtual machine monitor etc
Hello World
requires, #include <stdio.h>, return type, statements end with semi-colons, printf
Compilation: Warnings an Errors
Errors are unrecoverable
Warnings may indicate a problem and should be fixed
Some warnings are disabled by default
Variables
Variable: name, type value
Must be declared before use and start with a letter or underscore
Types
Defines the amount of memory allocated to the memory
Compiler checks the validity of operations on the variable
short/unsigned int is at least 16 bits
unsigned/long int is at least 32 bits
unsigned/long long is at least 64 bits
float is generally 32 bits
double is generally 64 bits
You use single quotes for characters
You use decimal numbers for floats
When mixing floats in arithmetic, integers are promoted to floats
When stored in an integer variable, floats are truncated
printf
Accepts one or more arguments: format string + variable list with escaped characters
Arrays
Stored contiguously in memory and static initialisation allows us to omit the size of the first dimension
Character arrays i.e. strings
when declaring strings using an array you must account for the \0 end string marker
Command Line Arguments
int argc: integer indicated the number of command line arguments that are passed to the program
char argv: bi-dimensional character array containing the command line arguments
arguments are strings, to convert to integer use atoi and to convert to double use atof
Conditionals
"false" is 0 and "true" is everything else
Boolean operations &&, || and !. Beware of their precedence !, then && then ||
Switch Statement
Test the quality of an integer against a list of values, using break to aboud fall through and a default if no cases match
For and While Loops
break within a loop body exits the loop
continue within a loop body goes to the next iteration
If the loop body is a single statement, we can omit the braces
Functions
Have a name, zero or more parameters with types and a return type (or void)
Parmeters and return value are passed by copy not reference, so each function has a local copy
As the compiler parses source files from top to bottom, you must declare a function beofre using and defining it
Variables scope and lifetime
Global variables declared outside functions are visible at the level of the entire file, but make it harder to reason about the program
Within a function, a local variable is accessible within its enclosing braces
It is good practice to declare local variables at the beginning of their block
Custom types
You can use typedef to alias a type e.g. typedef long long unsigned int my_int
Custom data structures
Use struct to define a data structure with named fields (like a class)
Use struct <struct name> tosrefer to it as a type and access the fields of a variable with <variable name>.<field name>
Fields are placed consecutively inn memory and structures can be typedef'd
Enumeration
User defined type for assigning textual names to integer constants, the compiler assigns an integer constant to each value fo an enum, and they can be typedef'd
Memory Management and the Standard Library
Addresses
A program's accesible memory is its address space, it is a contiguous array and the addresses are indexes in that array
This is virtual memory and the address of a variable is the address of the first byte storing that variable
Use the & operator to get the address of a variable
Pointers
A variable that contains an address: <pointed type> *<pointer name>;
Use parentheses to dereference the pointer of a struct
Dereferencing is accessing the pointed variable with *
Pointer applications
Allows a function to access the calling context, allowing it to 'change its parameters' or return more than a single value
Efficient function calls with large data structures - allowing us to maintain a single copy of a variable instead of making copies
Arrays are pointers, and for pointer arithmetic +1 means + sizeof(array type)
Pointer Chains
A pointer is a variable and has an address, hence can be pointed to
Dynamic Memory Allocation
Program memory layout
static data: large size, allocations fixed at compile time, stores global variables
stack: small, most allocations fixed at compile time
heap: large, allocations made dynamically at runtime
Allocating on the Heap: malloc
malloc allocates a chunk of memory on the heap and returns a pointer to it (check that it doesn't fail)
It is important to free memory after you're done with the data
void *: a generic pointer type
size_t: long unsigned int
heap memory can only be accessed through pointers
String Manipulation
string copy: *strcpy/strncpy
string concatenation: *strcat/strncat
format based string creation: sprintf, fills a string with printf-like specifiers
string manipulations: get length with strlen, compare with strcmp which returns 0 if they match
Console input
fgets to get a string from the user
scanf to get a number from the user
Memory manipulation
*memset copies something a set number of times
*memcpy
Math functions
ceil for double, ceilf for float
sqrt, pow, cos etc
Time
sleep for a number of seconds or usleep for microseconds
current time uses the time function
measuring execution time uses gettimeofdat
File I/O
open creates a reference to a file
flags: O_RDONLY/O_WRONLY/O_RDWR
file creation: O_CREAT
truncate to 0: O_TRUNC
read attempts to read bytes from a file
fd is the file descriptor
buf is the address of the bugger that will recieve the content read
count is the number of bytes to read
return is the number of bytes actually read
write attempts to write count bytes from buf into the file correspondingto the fd
close terminates file I/O on a given descriptor
Random Numbers
rand(), rand()%100 or srand(time(NULL)) to initate a random seed
Error management
The variable errno can be used to get more information about the failure of function. They are listed in the function man page.
The problem with atoi
It offers no knowldge of if the string is invalid/underflows or overflows
We can use strtoi, converting the string nptr to a long integer and returning that and *endptr points the the first invalid character of the string
strtoi is ised to check string validity by looking at the value of *endptr and checking for under/overflows with errno and the return value
Stream-based File I/O
Opens the file identified by the pathname and return a stream object or NULL on error
Has modes r, r+(read-write), w(write with truncate or create), w+(read-write with truncate, or create)
We close streams wth fclose
Building C Programs, Use cases
Memory Safety and More Use Cases
C++
Obeject Oriented C++
Generic C++
Functional C++ and Modern C++
Haskell
Defining functions
Types
Strictness
More types
Input and Output
Compilation
Introduction
Lexical Analysis
Syntax Analysis
The middle-end
Code Generation
Advanced Topics
Concurrency
What is concurrency?
parts of a computation happening at the same rime
It increases resource utilisation and has high performance
The problem with concurrency
computation beyond a certain level take time
All consistent orderings of computations are possible and have to be considered
It is hard to understand and reason about because its breaking our assumptions about how code works (atomicity and ordering)
Data Race -> non-determinstic output due to the failure to control concurrency
SW Concurrency
Threads
Independent streams of computations with shared tate
Interactions between threads are implicit
Coordination has to be explicit
Processes
Each process has its own internal state
Interactions between thread explicit hence less coordination
Rust Memory Management - Ownership and Borrowing
Rust - Lifetimes