Prototypes Are Not Classes
raganwald.com
raganwald.com
"You can add methods to any objects (no metaclass required), and any object can be inherited form, becoming the prototype of its descendants. In other words, any object can perform the job of a class in a class-based language."
That doesn't sound quite right to me. Not that it is wrong, but maybe looking at it the wrong way?
For the discussion, I propose an object has some state, and can receive messages and send messages in response.
A class is the abstract idea of what an object should be like. To break out the bad analogies, it's like ordering from a restaurant menu. You ask the runtime for an instance of a class. If you want something special, you have to have it put on the menu first. Prototype restaurants have no menus, but they have the dishes on display, and you can order those. Or, if you're so inclined, just point at your neighbours' food and order what that guy's having. If he's eaten half of it already, you'll only get as much as he has left, but luckily you can add combine it with other dishes or ingredients as you go.
You can see that if we put some rules in place about which objects can be copied, and what happens during copying exactly, and we call some special objects classes, and use them to create other special objects we call instances, a prototype-based object system can be made to behave like any class-based object system. If we bake those special rules into the language, we make the computer's job easier with hard-wired shortcuts.
"In a class based model, skeletal templates (classes) serve as object factories, with something general (the class) serving as the starting point of something specific (an object).
In a prototype based model, the prototype object provides a fully fleshed out starting point for other objects, with something specific (the prototype) serving as the starting point of something even more specific (the inheriting object)"
function MyClass()
{
var self = this;
var privateVar = 0;
this.getPrivate = function() { return privateVar; }
this.setPrivate = function(val) { privateVar = parseInt(val); // restrict type }
this.publicVar = "Hello World";
}
MyClass.prototype.extension = function() {
// Here 'this.publicVar' can be set but 'this.privateVar'
// and 'privateVar' are not a valid references.
}
Long story short, the class analog is semantically no different than the JavaScript prototype when done correctly.The analogy is not to a private instance variable in Ruby, the analogy is to a class method in Ruby Dutch as define_method.
1. This is not a dynamic vs. static thing, the languages cited in the article with classes are all dynamic languages. Metaobjects are typically found in dynamic languages like Common Lisp and Smalltalk.
2. The difference between a class as described in this article and a prototype is the same as the difference between a C struct or Pascal record and a Smalltalk object. I do recall people saying "potato/potato" about that when OO was first going mainstream, but I think over time people accepted that encapsulating private state is more than a nuance.
Your Milage May Vary.
My point is that the more I try to understand other people's explanation, the more I think it's just semantics. To put it in your terminology as used in your post, it seems that you are redefining what is commonly and in a broad sense known as 'classes' as 'metaobjects' as a generalization of different ways to implement classes. Which is fine, when you look at the details, but to me the difference doesn't warrant overloading a well-known term like 'class'. (Although I'm still not clear what you'd call a C++ class, if it's not a meta-object as your reply suggests.)
To stay with your C/Pascal vs Smalltalk example - I'd be perfectly fine calling a C struct a 'class' when doing object-oriented C, for example as done in GObject (from GLib, one of the Gnome base libraries), and calling a Smalltalk class also 'class'. 'class' is a malleable OO concept, and its exact implementation isn't all that important or interesting conceptually, and is certainly not tied to one specific implementation of the concept. I still don't see how the Javascript 'implementation' (I put this in quotes because most things in Javascript are just accidents derived from design decisions that put a high premium on ease of implementation, which BTW is usually how I like it, I'm not knocking on JS for that here) of classes is so different that it warrants its own name ('prototype'), suggesting it's completely different from 'classes' (and not only that suggestion, but also people claiming that they're 'very' or 'fundamentally' different - not saying your claim is that strong, I can't really tell from the post, just that some people do).
For a good counter-example, check out a lot of google's JS libs (in all their giant module goodness).
To me a Class has always been "a family of objects with the same structure and behaviour, and a way to create them". Stuff like hiding, constructors, type checking, polymorphism and inheritance are interesting, but secondary details. But then, I was taught OOP using Modula-2 back in '89, so I'm used to the idea that language features and paradigm features need not match 1:1
Btw., in a typical language supporting prototypes, I would expect that prototypes are nothing special. Every object could be a prototype for others...
There is a problem with accessing prototypes of objects, as they are not exposed to the user and only available through internal property __prototype__ (IIRC). And there's quite a bit of magic involved with constructor prototypes, which - again - makes it impossible to traverse prototype chain unless you create your objects yourself and store the references yourself.
So yeah, prototypes are nothing special in JS, but their API kind of sucks and could get better. Object.create is a step in the right direction IMO.
Actually, Object.getPrototypeOf was added in ECMAScript 5.1. It's even supported by IE9.
> only available through internal property __prototype__ (IIRC)
It's an external property (the internal one is `[[Prototype]]`_, and is called `__proto__`. It's non-standard, although all modern browsers implement it (even IE11, but not IE10)
I was thinking about this one.
> Actually, Object.getPrototypeOf was added in ECMAScript 5.1.
Wow. Thanks, I wasn't aware of this.
But almost everyone who comes to Javascript from a class-based language brings a number of additional preconceptions. I don't know the Ruby community well enough to know if your descriptions are accurate, but I know that many of those coming from Java or C# backgrounds expect classes to be (1) distinct creatures from objects (and those who know much about the reflection class Class understand that the objects of that class are objects and not the classes themselves), (2) design/development/compile-time abstractions separate from the run-time realities, (3) unchanging at runtime (which is obviously different from Ruby), and (4) the enforcers of access policies of instance methods. None of these things are true for Javascript prototypes. So to these people, it's easiest to explain that Javascript does not have classes.
I have never implemented a serious programming language. But I understand from those who have that implementing classes and implementing prototypes can be very, very similar processes. So, while I won't stop insisting to those from other languages that Javascript doens't have classes, I do recognize that I'm talking more to their preconceptions and not to the deepest truth I know.
[1]: http://en.wikipedia.org/wiki/Class_(computer_programming)Essentially, by javascript not being a very good Self.
[0] IIRC in Self the prototype is the object you copy, objects linked through parent slots are either mixins or traits.
[1] although it doesn't have a lobby, which makes the difference between traits and mixins, js's prototypes are probably closer to self's traits.
[2] that's being added in ES6, yay. But still single, boo.
I think it can be helpful to say that JavaScript is "like" Scheme if the purpose is to think harder about JavaScript and some of the consequences enabled by its features. On the other hand, I don't think JavaScript really is a Lisp, and it's a terrible idea to say so for the purpose of justifying all of its design choices.
On my case, the remark I made had more to do with the fact that many developers tend to be unaware that these concepts also exist in other languages and could learn a bit by seeing them on the languages they originated from.
Even when JavaScript only took tiny details from them.
If client-side JavaScript had this design, there would be no need for the DOM to have a special event mechanism that lives outside of method handling: DOM elements would simply have method handlers and the dispatch system would handle prototype and container inheritance.
See also HyperCard/HyperTalk...
However Eiffel, OCaml and Python MI implementations seem to be implemented in a more sane way.
I'll just show myself out...
Others are curious. What is fire? Is electricity fire? What's the smallest thing That can be on fire? How can you make something burn faster?
We make up little explanations about how knowing the answers to these questions makes us more productive world-burners, but in the end we're just curious people.
Understanding the decomposition allows you to internalize the behavior of a complex entity and thus understand and predict how it will behave in different (i.e. previously unseen) contexts.
If you avoid decomposition and instead view each entity as a one-off with its own unique behavior patterns then you are limited to memorizing the behavior on a case-by-case basis. Any extrapolation or prediction of behavior would be as effective as random guesses.