Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

OOP in JS

2,212 views

Published on

OOP in JS revisited. The presentation is built in part on my blog post: http://lazutkin.com/blog/2012/jan/18/oop-and-js/

Published in: Technology
  • Be the first to comment

OOP in JS

  1. 1. OOP in JS Revisited Eugene LazutkinClubAjax on 6/5/2012 Dallas, TX
  2. 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. 3. Prerequisites• Basic knowledge of object-oriented programming is required.• Basic knowledge of JavaScript version of OOP is assumed.
  4. 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. 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. 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. 7. Example: car• Car is much more than a sum of its parts.• How parts fit together is an invariant.
  8. 8. Example: car• Is it a car? • No, its invariant is violated.
  9. 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. 10. Program state• Imagine that we can observe programs state and how it changes over time.• Now imagine that we partitioned this space into a finite number of objects.
  11. 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. 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. 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. 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. 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. 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. 17. Destructors• Why do we need to destroy an object? Isnt 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. 18. Chaining• Invariant requirements assume chaining: • Base class constructor should run before derived constructor. • Base class destructor should run after derived destructor.
  19. 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. 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. 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. 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. 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. 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.
  25. 25. OOP fail• Sometimes it does.• Let’s look at some practical criticism of OOP.
  26. 26. Complexity fail #1• OOP doesnt 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. 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. 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. 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. 30. Complexity fail #2• OOP doesnt scale up. • It is not a technical limitation, it is a human limitation. • People are bad at constructing big hierarchies.
  31. 31. History lessons• Plato: • Mentored by Socrates. • Mentor of Aristotle. • First major attempt to understand the classification problem in his "theory of forms".
  32. 32. History lessons• Aristotle • Mentored by Plato. • Mentor of Alexander the Great. • "Corrected" Platos theory in over 170 of his works!
  33. 33. History lessons• Since 18th century numerous philosophers criticized predecessors and offered different strategies of classification.• The work is not finished yet.
  34. 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. 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 doesnt fit your project, you better look for alternatives.• Keep your inheritance diagram compact.
  36. 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. 37. SI alternatives• Lets drop multiple inheritance. • JavaScript supports single inheritance natively, and DAG linearization would work better.• Lets drop traits. • The full machinery is too complex. • Traits rely on some static analysis, while JavaScript is essentially dynamic.
  38. 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. 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. 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. 41. SI augmentation: mixins• Any multiple inheritance technique produces an inheritance DAG and relies on its linearization (we dont 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. 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. 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. 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. 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. 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.
  47. 47. dcl• Currently consists of three modules: • mini.js • dcl.js • advise.js
  48. 48. dcl• mini.js: • Provides automatic constructor chaining out of box. • Provides implicit super calls. • For byte-conscious: just over 900 bytes.
  49. 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. 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. 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.
  52. 52. That’s all!
  53. 53. Picture creditsCar: http://www.flickr.com/photos/arcaist/2311533441/Car parts: http://www.flickr.com/photos/7603557@N08/2662531345/Voronoi diagram: http://en.wikipedia.org/wiki/File:2Ddim-L2norm-10site.pngVoronoi 3D: http://en.wikipedia.org/wiki/File:Coloured_Voronoi_3D_slice.pngPlato: http://en.wikipedia.org/wiki/File:Plato_Silanion_Musei_Capitolini_MC1377.jpgAristotle: http://en.wikipedia.org/wiki/File:Aristoteles_Louvre.jpgPlato & Aristotle: http://en.wikipedia.org/wiki/File:Sanzio_01_Plato_Aristotle.jpg

×