Hacker News new | past | comments | ask | show | jobs | submit login
Prototypes Are Not Classes (raganwald.com)
64 points by raganwald on Jan 19, 2014 | hide | past | web | favorite | 43 comments

The author has to emphasize that prototypes and classes are a different concept at least five times in the article. Why? Because the explanation is long-winding and weak.

This is the best feedback so far.

How about this for an abbridged version?

"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."

TL;DR: long winded bad analogy, but maybe helpful

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.

How about this:

"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)"

It felt like the author was using the post as a cathartic persuasion for why prototypes differ from classes. JavaScript functions are a prototype of a class. Prototyping in JavaScript is an analog to class extensions, with elaborate definitions for private/protected variables. It's a debate over semantics and syntax, and it's useless because the analog to a object oriented class can be done with JavaScript's syntax.

  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.

Encapsulating instance state us not the point, encapsulating the class behaviour is the point. So, if you can make the prototype itself private and modify the prototype with class methods, you have something that prototypes by themselves do not express.

The analogy is not to a private instance variable in Ruby, the analogy is to a class method in Ruby Dutch as define_method.

I've read it twice and still can't find the point.

Every time someone tries to explain why prototypes are so very much not classes, I can't help but come away thinking 'yeah potato/potato - so they're basically the same'. Be it Crockford, this guy, any of the 100 articles you find only when you go looking for it. Sure the nuances between languages are different, big deal - what is called 'class' in a dynamic language is very different from what is called 'class' in C++, yet everybody calls them classes and doesn't go around writing articles about how runtime-modifiable object blueprints really are fundamentally different from those that are set in compile time.

Did you read TFA or simply fold it into an airplane and launch it towards the dustbin?

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.

Yes I did read it, several times even, because I really want to understand it if there is a difference. This is why I could remark what I did - because I've actively looked into explanations of the difference, several times, over the last year or so, and walked away with the same conclusions every time.

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).

This sort of realization is the first step to realizing that you really shouldn't be writing javascript like java/C++. It makes things feel a lot nicer when you start really thinking in JS. I'd recommend checking out Crockford's "Crockford on Javascript" series for some good intro on thinking about Javascript (http://www.youtube.com/watch?v=JxAXlJEmNMg). Section 3 is where you really start talking about JS.

For a good counter-example, check out a lot of google's JS libs (in all their giant module goodness).

I've never heard anyone, experienced or newbie, say "JavaScript has classes". People at best will say "You can sort of make classes in JavaScript using objects".

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

Your first and second paragraph seem contradictory to me. Javascript, through what is called 'prototypes', has "a family of objects with the same structure and behaviour, and a way to create them", and varies only in implementation and semantic details from other languages. So I agree with your second paragraph and would say that JS does have classes, but then I'm not sure what your first paragraph means.

You can use objects and prototypes to build classes, but they are not classes by themselves. Similar to how you can use objects to create a linked list, but the language itself does not have linked lists.

Jesus, the language is called Smalltalk. Not SmallTalk.

Btw., in a typical language supporting prototypes, I would expect that prototypes are nothing special. Every object could be a prototype for others...

That's true in JavaScript - there's an Object.create() method, which creates new object with any other object set as prototype: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

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.

> There is a problem with accessing prototypes of objects, as they are not exposed to the user

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)

> the internal one is `[[Prototype]]`

I was thinking about this one.

> Actually, Object.getPrototypeOf was added in ECMAScript 5.1.

Wow. Thanks, I wasn't aware of this.

And weirdly, I often miss-spell JavaScript as "Javascript." No idea why.

I think there is a serious problem in vocabulary. Wikipedia's definition of class ([1]) is quite reasonable, which, slightly paraphrased, reads, "A class is an extensible template for creating objects, providing initial values for state and implementations of behavior." While typically we don't use prototype objects for default state in Javascript, we always can if we choose, and they are widely used for providing behavior. And both "extensible" and "template" fit well. So by this definitions, prototypes really are classes.

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)

I guess before learning JavaScript, developers need to be sent to a Self learning camp.

I'm not sure that's a good idea, because then they'd be made very sad by constructors, by prototypes being something completely different[0], by not having mixins[1], by single-inheritance, by dynamic inheritance[2], by the lack of blocks (and non-local returns), etc…

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 that the claims that "JavaScript is like Self" or that "JavaScript is like Scheme" are attempts to legitimize what really isn't a very good language to being with. I think that this is also done out of ignorance, to a large extent. People hear about Scheme and Self being held in high regard, hear about some very vague similarities with JavaScript, and then assume that JavaScript is somehow like Scheme and Self, even if they've never used Scheme or Self. The supposed similarities only extend to JavaScript supporting anonymous functions and closures (just like numerous other languages) in the case of Scheme, or merely just sharing some terminology with Self. So there isn't any real basis to these claims.

I think that the claims that "JavaScript is like Self" or that "JavaScript is like Scheme" are attempts to legitimize what really isn't a very good language to being with.

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.


I am aware of that.

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.

MI still sends shivers down my spine, having spent time in the C++. Just say no.

So C++ got multiple inheritance wrong... That doesn't mean it must be rejected in all cases.

What are the cases where MI is better than mix-ins or component architectures?

NewtonScript had a neat concept of heterogeneous multiple inheritance: Its "objects" had a prototype-like inheritance chain and a container inheritance chain.

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.

> NewtonScript had a neat concept of heterogeneous multiple inheritance: Its "objects" had a prototype-like inheritance chain and a container inheritance chain.

See also HyperCard/HyperTalk...

Maybe just in some corner cases.

However Eiffel, OCaml and Python MI implementations seem to be implemented in a more sane way.


Beware, Self inheritance is not class-based inheritance, and thus Self MI has very little relation to C++'s MI.

OK, I'll bite. Please tell me what exactly your problem was.

Would that make them... Self-aware?

I'll just show myself out...

I hate to be _that_ guy, but I found the grey on light-grey text to be difficult to read.

Yet another shallow article describing the difference between prototypes and classes. Does anybody know of more in depth ones that also discusses multi-leven inheritance, polymorphism etc?

polymorphism is actually orthogonal to the ideas around metaobjects like classes. They are both powerful ideas. but can be expressed in different ways. Languages like Common Lisp and Haskell allow you to express polymorphism entirely through overloading of functions, for example.

Good (enough) for GUIs, bad for business logic.

Never get why people are so excited with atomization, that necessity of decomposing everything in atomic parts...

Some people just want to watch the world burn.

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.

I think the decomposition is important but not necessariy that you have to continue that process until you have atomic parts.

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.

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact