17.1. OOP About

  • Three main programing paradigms

  • Programming paradigms

  • Procedural Programming (PP)

  • Functional Programming (FP)

  • Object Oriented Programming (OOP)

17.1.1. Procedural Programming

  • Languages: C, Pascal, Fortran, COBOL, BASIC, etc.

  • Share: 20% (don't quote me on that)

  • Since: 1950s

  • Vocabulary: variable, constant, reference, procedure, call, loop, iterate, switch, module, subprogram

  • Scaling: Vertical (buy faster computer)

  • Procedure is a set of commands which can be executed in order

  • Procedures == routines == subroutines

  • Function can return, procedures can't

  • Function has read only access to its parameters, and produce no side-effects

  • Procedure might have write access to its parameters, and are expected to produce side-effects

>>> def is_even(x):
...     if x % 2 == 0:
...         return True
...     else:
...         return False
>>>
>>> result = []
>>> for x in range(0,5):
...     if is_even(x):
...         result.append(x)
...
>>> print(result)
[0, 2, 4]

17.1.2. Functional Programming

  • Languages: OCaml, Haskel, Scheme, Lisp, Closure, etc.

  • Share: 5% (don't quote me on that)

  • Since: 1930s

  • Initiator: Alonso Church, lambda calculus, 1930s

  • Scaling: Horizontal (add more computers to the cluster)

  • Vocabulary: lambda, closure, curry, pure function, atom, bridge, monad, monoid, map, filter, reduce

  • No loops, use map, filter, recurrence

  • No variables, only constant values

For instance, a function sort might take a list, and return a new sorted list; whereas a procedure sort might take a list, and modify that list in-place without returning a new list.

>>> from functools import reduce
>>> from operator import add
>>>
>>>
>>> def even(x):
...     return x % 2 == 0
>>>
>>> def positive(x):
...     return x > 0
>>>
>>> def non_negative(x):
...     return x >= 0
>>>
>>> def square(x):
...     return x ** 2
>>>
>>> def increment(x):
...     return x + 1
>>>
>>> def decrement(x):
...     return x - 1
>>>
>>> def apply(data, fn):
...     return map(fn, data)
>>>
>>> filters = (
...     even,
...     positive,
...     non_negative,
... )
>>>
>>> maps = (
...     square,
...     increment,
...     decrement,
... )
>>>
>>> data = range(0, 1024)
>>> filtered = reduce(apply, filters, data)
>>> mapped = reduce(apply, maps, filtered)
>>> result = reduce(add, mapped)
>>>
>>> result
1024

17.1.3. Object Oriented Programming

  • Languages: Python, Java, JavaScript, C++, C#, Smalltalk, Swift

  • Share: 75% (don't quote me on that)

  • Since: 1970s

  • Vocabulary: class, instance, method, attribute, inheritance, subclass, superclass

  • Scaling: Vertical (buy faster computer)

>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...         self.authenticated = False
...
...     def login(self, username, password):
...         if username == 'alice' and password == 'secret':
...             self.authenticated = True
...             print('User logged-in')
...         else:
...             raise PermissionError('Invalid username or password')
...
...     def logout(self):
...         self.authenticated = False
...         print('User logged-out')
...
...     def set_name(self, firstname, lastname):
...         if self.authenticated:
...             self.firstname = firstname
...             self.lastname = lastname
...             print('User name changed')
...         else:
...             raise PermissionError('User is not authenticated')
>>> user = User('Alice', 'Apricot')
>>>
>>> vars(user)
{'firstname': 'Alice', 'lastname': 'Apricot', 'authenticated': False}
>>> user.set_name('Bob', 'Banana')
Traceback (most recent call last):
PermissionError: User is not authenticated
>>> user.login('alice', 'secret')
User logged-in
>>>
>>> vars(user)
{'firstname': 'Alice', 'lastname': 'Apricot', 'authenticated': True}
>>> user.set_name('Bob', 'Banana')
User name changed
>>>
>>> vars(user)
{'firstname': 'Bob', 'lastname': 'Banana', 'authenticated': True}
>>> user.logout()
User logged-out
>>>
>>> vars(user)
{'firstname': 'Bob', 'lastname': 'Banana', 'authenticated': False}

17.1.4. Philosophy

keyword is defined by parser:

class

type is defined by class keyword and label:

>>> class str:
...     def __init__(self, value):
...         ...

instance is created from type and scalar:

>>> str('alice')
>>> str('secret')

value is created from instance and identifier:

>>> username = str('alice')
>>> password = str('secret')

sequence is created from multiple values:

>>> user = str('alice'), str('secret')

mapping is created from sequence and labels:

>>> user = {
...     'username': str('alice'),
...     'password': str('secret'),
... }

data is created from mapping and behavior:

>>> class User:
...     def __init__(self, username, password):
...         self.username = username
...         self.password = password
...
...     def change_password(self, new_password):
...         self.password = new_password
>>>
>>>
>>> user = User(
...     username=str('alice'),
...     password=str('secret'),
... )
>>>
>>> user.change_password(str('qwerty'))

program is created from data and business logic:

>>> class User:
...     def __init__(self, username, password):
...         self.username = username
...         self.password = password
...         self.authenticated = False
...
...     def login(self):
...         if not self.username or not self.password:
...             raise PermissionError('Invalid username and/or password')
...         print('User logged-in')
...         self.authenticated = True
...
...     def logout(self):
...         self.authenticated = False
...         print('User logged-out')
>>>
>>>
>>> user = User(
...     username=str('alice'),
...     password=str('secret'),
... )
>>>
>>> user.login()
User logged-in
>>>
>>> user.logout()
User logged-out