Primary Paradigms
- Historical programming language paradigms - imperative 
- declarative 
 
- Recent programming languages blur distinctions 
- But concept of programming paradigm meaningful 
H. Conrad Cunningham
31 January 2019
Copyright (C) 2017, 2018, H. Conrad Cunningham
Acknowledgements: I created these slides in Fall 2017 and revised them in Summer 2018 to accompany what is now Chapter 2, Programming Paradigms, of the book Exploring Languages with Interpreters and Functional Programming.
Browser Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of January 2019 is a recent version of Firefox from Mozilla.
Introduce concepts of abstraction: procedural and data
Describe what is meant by term “programming paradigm”
Examine natures of the two primary programming paradigms: imperative and declarative (functional and logic)
Examine natures of other important programming paradigms: procedural, modular, etc.
Simplicity is good; complexity is bad.
concentrating on the essentials and ignoring the details
remembering the “what” and ignoring the “how”
Make large complex problems understandable by decomposing into subproblems
Procedural abstraction: separate properties of action from implementation details
Break complex actions into subprograms; develop program as sequence of calls
Data abstraction: separate properties of data from representation details
Identify key data representations; develop program around these and associated operations
Procedure (pure) takes zero or more arguments but does not return value; executed for effects
Function (pure) takes zero or more arguments and returns a value; does not have effects
Method is procedure or function associated with object in object-oriented program; object may be implicit parameter
Good practice to maintain distinction between procedure and function even if language does not
Timothy A. Budd. Multiparadigm Programming in Leda, Addison-Wesley, 1995, page 3:
“a way of conceptualizing what it means to perform computation, of structuring and organizing how tasks are to be carried out on a computer.”
Historical programming language paradigms
imperative
declarative
Recent programming languages blur distinctions
But concept of programming paradigm meaningful
Imperative program
Imperative language
Imperative program
    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }State in above Java example
count and maxc    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }State changes (side effects)
count
valueprintln adds line to
output    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }Execution in sequence
while
causes execution zero or more timescount, maxc    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }State implicit because state assumed from context
Variable count
mutable because value can change—yield different values at
different times
Variable maxc also mutable,
but does not change here
To allow execution, the Java code above can be included in main method
Imperative languages well suited for traditional computer architectures
Examples: Fortran, C, C++, Java, C#, Python, JavaScript, Lua
Object-oriented languages?
Declarative program
Declarative program
Declarative language
Declarative program
Declarative paradigm subdivided into
Underlying computational model is mathematical function
    counter :: Int -> Int -> String 
    counter count maxc 
        | count <= maxc = show count ++ "\n" ++ counter (count+1) maxc 
        | otherwise     = ""Above Haskell example similar in meaning to earlier Java example
countercount and maxccount to maxc one per line    counter :: Int -> Int -> String 
    counter count maxc 
        | count <= maxc = show count ++ "\n" ++ counter (count+1) maxc 
        | otherwise     = ""Function “call” (application) of counter
count and maxc    counter :: Int -> Int -> String 
    counter count maxc 
        | count <= maxc = show count ++ "\n" ++ counter (count+1) maxc 
        | otherwise     = ""Repetition of counter by
recursive call
State of counter
explicit because passed in arguments
Values of arguments immutable within body
Names like count and
maxc (in pure functional
language)
Previous Haskell code executes no actions
Must execute IO program to
do input/output
Referential transparency very important! It allows:
In functional languages, functions often are:
Higher-order functions very important
Pure examples: Haskell, Idris, Elm, Miranda, Hope, Backus’s FP
Hybrid examples: Scala, F#, OCaml, SML, Erlang, Elixir, Lisp, Clojure, Scheme
Mainstream imperative language with functional subsets: Java 8+, C#, Python, Ruby, Groovy, Rust, Swift
Underlying computational model is mathematical relation (or predicate)
    counter(X,Y,S) :- count(X,Y,R), atomics_to_string(R,'\n',S).
    count(X,X,[X]). 
    count(X,Y,[])     :- X  > Y. 
    count(X,Y,[X|Rs]) :- X < Y, NX is X+1, count(NX,Y,Rs).Above SWI-Prolog example similar in meaning to earlier Java and Haskell examples
X to Y, one per
line    counter(X,Y,S) :- count(X,Y,R), atomics_to_string(R,'\n',S).
    count(X,X,[X]). 
    count(X,Y,[])     :- X  > Y. 
    count(X,Y,[X|Rs]) :- X < Y, NX is X+1, count(NX,Y,Rs).Above defines database consisting of clauses
count(X,X,[X]).
defines fact
X, list [X] with single
value X,
count(X,X,[X])
asserted truecount(X,Y,[]) :- X > Y.
defines rule
:- true if right side also truecount(X,Y,[])
true when X > Y    counter(X,Y,S) :- count(X,Y,R), atomics_to_string(R,'\n',S).
    count(X,X,[X]). 
    count(X,Y,[])     :- X  > Y. 
    count(X,Y,[X|Rs]) :- X < Y, NX is X+1, count(NX,Y,Rs).Can query database for missing components
count(1,1,Z).
yields value Z = [1]count(X,1,[1]).
yields value X = 1.counter(0,10,S),
print value of S with
following ruleImperative and functional languages run computation in one direction yielding one answer
Prolog can run computation in multiple directions yielding multiple answers
Example relational languages: Prolog, Parlog, miniKanren
Most Prolog implementations not pure, have imperative features (cut, assert and retract clauses)
Subcategory of imperative paradigm
organizes programs primarily using procedural abstractions
may limit variable/subprogram scope by nesting
    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6 string interpolation
            incr()Call counter(0,10)
similar to Java fragment
counter procedure called
“function” in Python
counter returns special
value None
    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6+ string interpolation
            incr()Has nested function has_more and procedure incr
Abstracts out loop test and increment action
    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6 string interpolation
            incr()Scope is range of code where name accessible
Lexical scope begins at definition, ends at end of block
has_more and incr scopes begin with definitions, end
with counter body
    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6 string interpolation
            incr()counter parameters count and maxc accessible within body
unless hidden
hidden in function has_more by new parameters of same
names
accessible in procedure incr, but count declared nonlocal to
allow assignment
Python, C, Fortran, Pascal, Lua, etc.
Refers more to design method than to language
Decomposes program into units (i.e. modules) that can be developed separately
Encapsulates key design and implementation details inside module (i.e. exhibits information hiding)
Each Python module is in separate file, creates separate name space
Defines 3 module-level functions: has_more, incr, counter
Defines 2 module-level global variables: count, maxc
Initializes global variables: count, maxc
Gives lexical scope in module to global variables & functions
globals count, maxc hidden in has_more by parameters with same
names
globals count, maxc visible in incr, counter
Declares count as global in incr for assignment
Imports feature counter
from module CountingMod.py
Does not make other features accessible
Imports all features of module, but requires qualified names
Allows modification of imported module’s variables
Most modern languages support “modules” in some way
Some languages (e.g. Standard ML) provide advanced support for encapsulation and multiple implementations of interfaces
Object-based paradigms (object-based, class-bassed, object-oriented, prototype-based) — Chapter 3
Concurrent paradigms — future
etc.
Procedural and data abstraction
Imperative paradigm expresses how something computed
Declarative paradigm expresses what is computed
Imperative Java program Counting.java
Functional Haskell program Counting.hs
Relational (logic) SWI-Prolog program Counting.pl
Procedural Python 3 program CountingProc.py
Modular Python 3 program CountingMod.py