William Cook talks about the difference between objects and Abstract Data Types (ADTs) in this great paper: On Understanding Data Abstraction, Revisited. In his treatise on objects, he lists a property called “Autognosis” which, in his words, describes the contraint:
An object can only access other objects through their public interfaces.
Put another way (again by Cook):
An autognostic object can only have detailed knowledge of itself.
I find this constraint particularly interesting, because it’s something that’s easily violated in conventional OOP languages. Presumably because it’s so easy, a lot of OOP code also actually does violate it.
Let’s take the example of a 2D vector; a reasonable implementation in C# (I’ll come to Javascript later) might go something like this:
So what’s the problem? Well, to compute the sum of the two vectors the augend needs access to the private data of addend (addend._x and addend._y). Thus, one object (the augend) accesses another object (the addend) through something else than the public interface. This violates the Autognosis constraint.
In Javascript, we can have an equivalent implementation:
Whether the autognosis property is violated in this case is a little less clear: Javascript doesn’t have access modifiers, so it isn’t clear from the code itself what is part of the public contract and what is not. If x and y are part of it, it isn’t violated. For now, however, let’s assume only fields that have a function value are part of the public contract. So let’s fix it:
By itself, this doesn’t bring us very much, we’ve just wrapped the instance variables. However, from an extensibility point of view this has brought us a great lot: we can now create new, interoperable vector implementations:
And their interoperation:
Let’s take a moment to appreciate what we did here. We were able to introduce a new vector implementation and use that seamlessly within our existing code, without needing to change any of that existing code. This is great, since it means that your application can be extended and improved after writing it in the first place, without needing to modify it.
There is another great advantage to this: besides you writing new extensions, other people can do that as well, allowing your application to do stuff that you never imagined in the first place. Arguably, the vector example doesn’t really show those traits, but OO design principles is exactly what’s at the heart of platform ecosystems such as iOS and Android Apps, or even the internet itself.
To summarize, that’s one of the great benefits of OOP: objects provide for autonomous extensibility with interoperability. Autognosis is one of the key facilitators of that property.
Afterthoughts
This story isn’t specific to Javascript. In C# or Java we can use interfaces to obtain similar results. We should be careful not to explicitly test for class type in the implemention though, since that again violates the autognosis property. (The same goes for Javascript, but testing for types seems to be less common there)
Also notice that nowhere in this post I either talked about classes or inheritance, yet still arrived at some very useful properties directly related to OOP. This strengthens my beliefs that classes and inheritance are not fundamental parts of OOP.
I haven’t said too much about ADTs in this post, however I’ll try and do a follow up post to explore how you’d do a similar extension using ADTs.
Credits
Inspiration for this post came from: