# programming paradigms brief overview # what is a paradigm a paradigm is a typical example or pattern of something; a pattern or model. the programming paradigms we are going to look at are: * imperative * procedural * object-oriented * declarative * functional * logic # note about languages languages usually support a mix and possibly all programming paradigms. some languages are designed to favor one paradigm. for example java with object-oriented programming. some ways in which languages make it more difficult to use alternative paradigms are: ## requirements for example requiring to create files with classes to be able to create functions ## limitations unsupported features, for example no support for first-class functions domain- and problem-specific built-ins # short descriptions ## imperative series of commands that modify a programs state ### procedural imperative commands structured into subroutines ### object-oriented structure a program into objects with behaviour and data. or: both subroutines and data stored in records ## declarative describe "what" and not exactly "how" ### functional treat computation as the evaluation of mathematical functions ### logic express facts and rules and ask the system # additional descriptions ## imperative * the order of expressions is usually very relevant. this can be problematic for parallelism and the understanding of code * relatively few abstractions away from the machine (von neumann architecture), this makes manual low-level performance optimisations easier ## procedural avoids having to deal with goto by using subroutines ## object-oriented avoids having to deal with subroutines that modify global state by encapsulating data via classes in objects. classes act as templates for new objects ## functional * ideally no side-effects (does not mutate anything outside of the function) * order of computation is less relevant because there is less dependent shared state. this is beneficial for parallelisation because it makes it simpler to evaluate function calls independently on separate processors * referential transparency (same input leads to same result, same arguments always lead to the same result, function calls can be more easily substituted with their results) * more predictable (formal verification, automatic optimisations) * state changes are always explicit via return values and function arguments ## logic * logic and control * leaves much of the "how", the choice of necessary computations, to the system # code examples the factorial function implemented in different styles. each example shows definition then application. the factorial function calculates the product of all positive integers less than or equal to n ## example ~~~ factorial(5) = 5 * 4 * 3 * 2 = 120 ~~~ ## procedural (coffeescript) ~~~ factorial = (n) -> result = 1 while n >= 1 result = result * n n = n - 1 result ~~~ ~~~ factorial 5 ~~~ ## object-oriented ~~~ class Factorial result: null calculate: (n) -> @result = 1 while n >= 1 @result = @result * n n = n - 1 ~~~ ~~~ f = new Factorial f.calculate 5 f.result ~~~ ## functional ~~~ factorial = (n) -> if n <= 1 then 1 else n * factorial(n - 1) ~~~ ~~~ factorial 5 ~~~ ### alternative ~~~ factorial = (n) -> [1..n].reduce (result, n) -> result * n ~~~ ## logic (prolog) ~~~ factorial(0,1). factorial(N,F) :- N > 0, N1 is N - 1, factorial(N1,F1), F is N * F1. ~~~ ~~~ ?- factorial(5, X). ~~~