-
Notifications
You must be signed in to change notification settings - Fork 16
/
polymorphism.theory.txt
102 lines (88 loc) · 8.75 KB
/
polymorphism.theory.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
POLYMORPHISM
POLYMORPHISM ==> #Using a single function for several types (for reusability)
#Can use:
# - subtyping (including subclassing), typecasting, overloading, generic programming
# - composition, aggregation, association: not polymorphism, but related
TYPE REUSABILITY ==> #A type can reuse another type behavior by:
# - reusing that type (simpler, more object-oriented):
# - from tighter to looser relationship (i.e. simpler to more modular) (see OOP doc):
# - inheritance, coercion, composition, aggregation, association
# - reusing its related functions, i.e. making it more generic (more abstract, more algorithm-oriented):
# - overloading: simpler (reimplement whole function)
# - generic: more abstract (only reimplement concepts)
SUBTYPING ==> #Also called "inclusion polymorphism"
#Concept:
# - extending base type by reimplementing its full interface
# - child-parent relationship
# - geared towards general concepts, i.e. usually OOP objects (except static members)
#Name resolution (dispatch): usually dynamic, but can be static with CRTP
#Can use multiple base types:
# - called "multiple inheritance" with inheritance
# - conflicts are resolved by:
# - calling only last base type (i.e. overriding)
# - calling each base type (called "multicast delegate" with prototype-based inheritance)
#When all types of a type system are subtypes of a base type, it is a "unified type system".
SUBCLASSING/INHERITANCE ==> #Also called "nominal subtyping" (as opposed to "structural subtyping")
#Subtyping where child ("subclass") explicitely references its parent ("supercass"):
# - inherits parent's interface:
# - abstract methods: methods that only get their definition (not implementation) inherited
# - abstract class: class with only abstract methods
# - type identity conforms to parent's
#Can be:
# - class-based: class (i.e. static, compile-time) vs instances (i.e dynamic, runtime)
# - prototype-based: types are instances, either by copy ("concatenating") or by reference
#Some types might be non-subclassable, e.g. builtin types in some languages
TEMPLATE METHOD ==> #Alternative to reimplementing methods in full:
# - only variant parts are separated into other methods, meant to be reimplemented
# - provides better code reuse
TYPECASTING ==> #Also called "coercion polymorphism"
#Concept: extending base type by initializing|constructing another one
#Name resolution (dispatch): usually dynamic
OVERLOADING ==> #Also called "ad-hoc polymorphism"
#Concept: extending function by defining new implementation for argument types
#Name resolution (dispatch):
# - static: "overloading"|"single dispatch"
# - dynamic: "multimethods"|"multiple dispatch"
VISITOR ==> #Pattern allowing using multiple dispatch for languages that only support single dispatch
#I.e. when invoking an overloaded FUNC(VAR), VAR argument type must be known compile-time
#Solution:
# - instead of firing FUNC(VAR) ("dispatch|visit" function)
# - firing VAR.FUNC2() ("accept" function), which fires FUNC(this) (since "this" is known compile-time)
#In OOP, usually:
# - all versions of FUNC usually put together in a single object, "visitor" or "dispatcher"
GENERIC PROGRAMMING ==> #Also called "parametric polymorphism"
#Concept:
# - extending function by defining new argument types implementing "contract" (used by the function)
# - types are "generic", i.e. "any" + "traits" (contracts)
# - more abstract, i.e. harder to build generic type, but easier to extend
#Can implement several contracts using:
# - mixins
# - traits, like mixins but:
# - usually only methods, no attributes
# - can be composed instead of just overriding, e.g. addition, substraction or allowing aliasing if name conflict
# - subtyping ("bounded quantification|polymorphism" or "constrained genericity")
# - e.g. <T extends U>()=>T
# - "f|recursively-bounded quantification|polymorphism": when can be recursive
# - e.g. <T extends U<T>>()=>T
#Name resolution (dispatch): static is "templates", dynamic is "mixins"|"traits"
#Type definition:
# - predicative (as opposed to impredicative): can define with generic types, but must assign with non-generic types
# - rank-n (1 is "prenext"): can define with a generic type, that takes itself another generic type, etc. (n times)
# - e.g. FUNC(any_database of any_collection of any_item)
VARIANCE ==> # - covariant: equal|stricter|subset, e.g. string <-- string|number
# - contravariant: equal|weaker|superset, e.g. string|number <-- string
# - bivariant:
# - either covariant or contravariant
# - but must have intersection, not be completely different
# - e.g. string <-- string|number, string|number <-- string, but not boolean <-- string
# - invariant: equal, e.g. string <-- string
POLYMORPHISM RULES ==> #For TYPE2 <-- TYPE, TYPE2 must be contravariant to TYPE.
#For functions, this means:
# - covariant preconditions: input, side effects
# - contravariant postconditions: output, exceptions, time complexity
#For subtyping:
# - PARENT <-- CHILD must be possible
# - i.e. PARENT must be contravariant to CHILD
# - called Liskov Substitution Principle (LSP, "L" of SOLID principles), substitutability, "inheritance semantics"