Ensuring Technical Readiness For Copilot in Microsoft 365
OOP in JS
1. OOP in JS
Revisited
Eugene Lazutkin
ClubAjax on 6/5/2012
Dallas, TX
2. About me
• Eugene Lazutkin
• Open Source web developer
• Majors: JavaScript & Python, Dojo & Django.
• Independent consultant
• Blog: lazutkin.com
• Twitter: @uhop, Google+: gplus.to/uhop
3. Prerequisites
• Basic knowledge of object-oriented programming
is required.
• Basic knowledge of JavaScript version of OOP is
assumed.
4. OOP foundation
• The foundation of OOP is an object.
• No, not a class or any other entity.
• Object incapsulates its state.
• OOP is a technique for an imperative
programming.
5. OOP foundation
• Object comes with methods (functions) that can use
or modify its state.
• Objects are used to partition a program state into
manageable pieces.
• Ultimate goal is to reduce the overall complexity.
• Instead of huge state space we deal with a
smaller number of objects w/ compact API.
6. Reducing complexity
• While the whole state space can be huge, not all
states are possible:
• There are certain conditions that should be
satisfied for a state to make sense.
• Operations on objects may have pre- and post-
conditions.
7. Example: car
• Car is much more than a
sum of its parts.
• How parts fit together is an
invariant.
9. Invariants
• It is a good practice to enforce invariants.
• Object methods should not violate invariants.
• Only constructor and destructor can violate
them.
• Constructor builds an object from a certain
state.
• After destructor an object cannot be used.
10. Program state
• Imagine that we can observe
program's state and how it
changes over time.
• Now imagine that we
partitioned this space into a
finite number of objects.
11. Program state
• Some objects can be very
similar to others.
• The same class.
• Some objects have
similarities yet not of the
same class.
• Related classes.
12. What is a class?
• A recipe for an object, which can be reused.
• An object pattern expressed in some declarative
form.
• A factory function, which can produce similar
objects.
13. Class relations
• How to model relationship between classes?
• One popular way to do that is a single
inheritance.
• JavaScript does the same with delegation.
14. Class relations
• How single inheritance (SI) work:
• A base class provides some state (member
variables) and a set of operations on it
(methods).
• A derived class adds its own state chunk and its
own methods.
15. SI: invariants
• A derived object can be classified as being of the
base class, and of the derived class at the same
time.
• Both class invariants should be satisfied at the
same time.
• Methods of the derived class should not violate
the base class invariant.
16. SI: life cycle
• A derived class constructor usually assumes that it
started with a valid base object building on it.
• When a derived destructor has finished, it leaves a
valid base class object.
• Usually there is a primordial Object class, which is
the basest foundation for any other class.
• In JavaScript it is {}.
17. Destructors
• Why do we need to destroy an object? Isn't it
excessive in the age of garbage collection?
• Objects may have references to physical
resources, which has to be freed (network
connections, files, USB devices, and so on).
• Objects may have known references to them
from other long-lived objects, preventing them
to be garbage-collected.
18. Chaining
• Invariant requirements assume chaining:
• Base class constructor should run before
derived constructor.
• Base class destructor should run after derived
destructor.
19. Chaining
• Invariant requirements assume chaining:
• Derived methods that update its own state in
response to base class changes usually should
run after its base class counterparts.
• Derived methods that set up its state to ride side
effects of base class changes should run before.
20. Chaining
• Invariant requirements assume chaining:
• Derived methods that update its state
independently from base class changes usually
run before or after.
• Derived methods that should update its base
state to satisfy the base invariant usually do
that, then call its base method, then update
state back according to the derived invariant.
21. Chaining
• All types of chaining can be done manually with
super calls.
• Manual super calls can be error-prone.
• Manual super calls in constructors are extremely
error-prone, especially when refactoring.
22. Super call problem
• Constructor super call problem:
• JavaScript objects are open: I can access
whatever member variable I want.
• Imagine I know how my base class is
constructed, so instead of calling its constructor
I decided to initialize all necessary variables in
the derived constructor.
23. Super call problem
• Constructor super call problem:
• Now every time I change my base class I have
to hunt down "smart" derived classes and
modify them too.
• The same goes for bypassed methods.
24. Super calls
• There are two ways to do super calls:
• Call a base method explicitly.
• Call a base method implicitly.
• JavaScript only supports explicit calls.
• There is a class proposal in works for ES6 that
introduces implicit super calls.
26. Complexity fail #1
• OOP doesn't scale down. You are better off writing
simple programs without it.
• Example: the official "Hello, world!" in Java:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
27. Complexity fail #1
• Do we really need a named class, with a static
method?
• Additional conclusion: in JS you will need OOP
when your program is big enough ⇒ stop worrying
about the size of OOP package you use, look for
completeness and correctness of its
implementation.
28. SI fail
• Who said that a single inheritance is the only form
of a relationship between classes?
• Trying to use a hammer (a single inheritance)
for all problems leads to poor code reuse:
• Cut-and-paste code.
• Duplication of methods.
• Top heavy hierarchy with stubbed methods.
29. SI fail
• Example:
• A fish, a duck, a hippo, and a submarine can
swim.
• Does it mean that they have a common
swimming ancestor?
30. Complexity fail #2
• OOP doesn't scale up.
• It is not a technical limitation, it is a human
limitation.
• People are bad at constructing big hierarchies.
31. History lessons
• Plato:
• Mentored by Socrates.
• Mentor of Aristotle.
• First major attempt to
understand the
classification problem in
his "theory of forms".
32. History lessons
• Aristotle
• Mentored by Plato.
• Mentor of Alexander
the Great.
• "Corrected" Plato's
theory in over 170 of
his works!
33. History lessons
• Since 18th century
numerous philosophers
criticized predecessors and
offered different strategies of
classification.
• The work is not finished yet.
34. Methodology fail
• So how to classify objects? How to find objects in a
soup of state space?
• Unless your domain has well-defined physical or
logical entities, you are on your own.
• Examples of well-defined objects: physical objects,
graphics, UI objects, tax forms, and so on.
35. What did we learn?
• Like all techniques OOP has its own sweet spot/
applicability area.
• It is not a universal tool. Do not abuse it.
• Single inheritance is very limited.
• If it doesn't fit your project, you better look for
alternatives.
• Keep your inheritance diagram compact.
36. SI alternatives
• One way to keep compact inheritance diagram is
to move from a tree to a DAG:
• AOP (crosscutting concerns).
• Multiple inheritance (MI) (like in C++?).
• Mixins (inherit from multiple bases using a
DAG linearization technique).
• Traits (mixin-like entities that scale up better).
37. SI alternatives
• Let's drop multiple inheritance.
• JavaScript supports single inheritance natively,
and DAG linearization would work better.
• Let's drop traits.
• The full machinery is too complex.
• Traits rely on some static analysis, while
JavaScript is essentially dynamic.
38. SI augmentation: AOP
• Aspect-oriented programming (AOP) requires
weaving methods using three types of advices:
before, after, and around.
• "Before" and "after" advices are essentially
chaining we already looked at before.
• "Around" advice is a super call.
39. SI augmentation: AOP
• In order to be flexible we should support two
modes of weaving:
• Static (when classes are composed).
• Dynamic (when objects are advised).
40. SI augmentation:
mixins
• Mixins can inject its own state, and support its own
invariants.
• Mixins may participate in an object life-cycle.
• Mixins can redefine existing methods, add new
methods.
• Mixins rely on existing methods and member
variables.
41. SI augmentation:
mixins
• Any multiple inheritance technique produces an
inheritance DAG and relies on its linearization (we
don't run parallel bases in parallel).
• While a relative order of mixins can be specified,
an absolute order is not defined.
• Mixins cannot call base methods explicitly.
• Implicit super calls are required.
42. SI augmentation:
mixins
• In order to reuse JS existing single inheritance
mechanisms we need to linearize an inheritance
DAG.
• C3 MRO (method resolution order) is the most
popular and well-understood technique used in
languages like Python.
43. What we want
• Reasonable requirements for OOP implementation
so far:
• Well-defined linearization (C3 MRO).
• Chain constructors using "after" chaining
automatically (optional).
• Chain destructors using "before" chaining
automatically (optional).
44. What we want
• Reasonable requirements for OOP implementation
so far:
• Anonymous/implicit super calls.
• Before/after advices for methods during class
composition.
• Before/after/around advices for objects to
weave dynamically.
45. Sample implementation
• New project that implements required functionality
under development: dcl.
• https://github.com/uhop/dcl
• Runs on Node.js.
• Runs with AMD-based loader (including Dojo
1.7 and RequireJS).
• Can be used stand-alone in a browser.
46. Sample implementation
• Based on proven Dojo technologies:
• The venerable dojo.declare().
• dojox/lang/aspect
• dojox/lang/oo
• Like Dojo licensed under BSD and AFL.
48. dcl
• mini.js:
• Provides automatic constructor chaining out of
box.
• Provides implicit super calls.
• For byte-conscious: just over 900 bytes.
49. dcl
• dcl.js:
• Adds “before” and “after” weaving for class
methods.
• Adds after/before chaining.
• Intended to be used as a main module.
50. dcl
• advise.js:
• Provides “before”, “after”, and “around”
weaving for object methods.
• Advices can be removed dynamically.
• That’s the main difference with dcl’s advices.
51. dcl
• In works:
• Special debugging version of said modules.
• Nobody cares about how we debug libraries.
It is time we do.
• Micro-library of mixins and advices including:
method timer, counter, tracer, memoizer, flow
analyzer, and so on.