

Classes are Expressions - brbcoding
http://raganwald.com/2015/06/04/classes-are-expressions.html

======
keithwhor
Just looks like more JavaScript antipatterns, this time with some ES6 flavour.

We know how to "solve" the problem of encapsulation with JavaScript. It's not
with closures, Symbols, or some other arbitrary hack. We do it by enforcing
specific idioms that only require a developer to recognize _intent_ instead of
learning 80 different ways to do the same thing. You simply _put a single or
double underscore_ in front of the property name.

I read what I thought was a clever anecdote by another developer the other
day, that the underscore in "obj._varname" indicates "here be dragons." It's
an extremely simple idiom to teach new JavaScript developers.

I get it, JavaScript is robust. So you can do fun things like this! These are
great experiments. But really, what are you accomplishing? You've now just
thrown in a closure and a bunch of lines of code (defining your symbols, etc.)
that any developer new to your codebase is going to look at like "... what
the... what is going on here?" You can solve the problem easily with _one
character_.

Consistency. Convention. Creating useful, easy-to-understand, repeatable
idioms. That's what we should be focusing on.

~~~
wvenable
You can't check that the convention is being broken which makes refactoring
more difficult. There will always be a temptation for some developers in some
situations to mess with the internal state of objects.

~~~
woah
In general, js is more about good practices and craftsmanship, and less about
finding ways for the language to force people to do things.

~~~
wvenable
I find this argument to be lacking; if you're using good practices and
craftsmanship then nothing is being forced on you as you would not encounter
an error for doing something improper.

I prefer to mark up my code as private/protected/public for my own purposes
both as built-in documentation and to have one less thing to think about after
it's done. Plus underscores are ugly.

~~~
woah
Yes, but you have to do a lot more typing, plus you have to do a lot of things
to satisfy a stricter language. There are a lot of abstractions like
interfaces, delegates, etc, that exist to get certain logical patterns past
the language's strictness. In loose languages you can just write the patterns
you want without the overhead.

~~~
wvenable
In other words, with less strict languages you can be sloppier. Once projects
get to a certain size, language strictness is a huge benefit.

And, in some extent, it's actually freeing. I can reach in and change
something big in a strict/compiled language and the compiler/IDE will tell me
where I have to make other changes throughout the whole project. In a dynamic
language, I either have to rely on unit testing, grep, or just having it break
at runtime. But the real truth is, you just don't make those kind of changes
when your language isn't strict. The pain isn't worth the payoff.

------
greggman
I guess I need to be schooled by why not just use closures?

    
    
        var Person = function(first last) {
          this.fullName = function() {
            return first + " " + last;
          };
          this.rename = function(newFirst, newLast) {
            first = newFirst;
            last = newLast;
          };
        };
    

Problem solved, you can't access `first` and `last` outside the class. You
might retort "they're bigger" or something but just like everything else in JS
they just need the right people to concentrate on them and they'll likely get
optimized.

I don't get the relucatance to use the language's features rather than hacks
(using naming standards and compilers to obfusticate names and then cross
fingers) or other hacks (Symbol). Really? You Really want me to write code
using Symbol? That's going to be awesome in the debugger. Let's add a watch to
"weke30o304_first". Refresh, of shit it's now "gtgrf40r3fe_first", my watches
all broke (T_T)

It also makes me sad the `class` spec didn't take that into account so you
could use a closure with a `class`.

~~~
munificent
Closures give you _object_ privacy. Symbols give you _class_ (or whatever
other scope you want) privacy. Take a look at this symbol example:

    
    
        let Person = (() = > {
          let firstNameProperty = Symbol('firstName'),
              lastNameProperty  = Symbol('lastName');
    
          return class Person {
            constructor (first, last) {
              this[firstNameProperty] = first;
              this[lastNameProperty] = last;
            }
    
            sameFirstName (otherPerson) {
              return this[firstNameProperty] == otherPerson[firstNameProperty];
            }
          };
        )();
    

Now try implementing sameFirstName() using closures. Good luck! :)

~~~
Cushman
Er, to be clear, your example uses a closure. Your real question is, can this
be done without `Symbol`?

And it can, since the symbol is just a secret stored in a closure and there
are other sorts of secrets. Aside from the "Math.random() + {enumerable:
false}" suggestion found elsewhere, you can reproduce the precise[0] semantics
of your example using something like:

    
    
        // Please do not actually write code like this
        var Person = (function() {
          var names = [];
          function Person(name) {
            this.key = names.length;
            names[this.key] = name;
          }
          Person.prototype.sameName = function(other) {
            return names[other.key] === names[this.key];
          };
          return Person;
        })();
    

Which is the ES3 generated by this CoffeeScript:

    
    
        class Person
          names = []
          constructor: (name)->
            @key = names.length
            names[@key] = name
          sameName: (other)->
            names[other.key] is names[@key]
    

Of course these implementations do something dramatically different behind the
scenes, and I emphatically don't think people should follow this example, but
the interface is the same. Edit: Except that I left `.key` as an editable
property, which is problematic. We'll leave that bit as an exercise, though.

Whether `names[this.key]` is as "nice" to work with as `this[nameKey]` is, uh,
left up to the reader; personally, count me in the camp that doing either of
those things is nuttypants compared to `this._name`.

[0]: Assuming that `otherPerson` in your constructor is a typo, of course ;P

~~~
munificent
> [0]: Assuming that `otherPerson` in your constructor is a typo, of course ;P

Oops, yup. Fixed.

Your solution is pretty clever, though it leaks memory like a sieve. To get
around that, you end up needing something like weak maps.

Once you have those, when you do the pattern you suggest, you are basically
doing metaprogramming and reinventing the very idea of an "object" yourself
from scratch.

That can be fun to do, but to me it starts to feel less like expressing "the
same thing" and more like implementing a new language that lets you express
the same thing. Just because I can implement a GC in C, that doesn't mean C
has a GC. :)

~~~
Cushman
In ES3 you'd need destructors, I think. But yes, agreed on all points :)

And yet-- is the Symbol approach not metaprogramming? It's clearly a much
saner way to shoehorn this feature in, but it's still a shoehorn. And the
underlying magic in both cases is in fact simple closure scope, which is
really what I wanted to demonstrate.

Edit: And I guess my broader point, to make this more constructive, is that in
JS these kinds of idioms live on a continuum of metaprogramming, and for the
sanity of your co-contributors you usually want to be doing as little of that
as necessary. Like others, I'm wary of presenting something like your example
as a "design pattern" without that context.

Edit 2: To illustrate what I mean, I _swear to you_ that if this pattern is
adopted widely you will find code like this in the wild:

    
    
        ... = > {
        let accountNumberKey = Symbol('accountNumber');
        return class Account {
          constructor (accountNumber) {
              this[accountNumberKey] = accountNumber;
              this.accountNumberKey = accountNumberKey; // ??? but transaction log works now
    
        ...

------
spankalee
I know this might be an unpopular view here, but declarative(ish) constructs
like class give a little hope that programs will be more statically analyzable
so that we can get nice things like static type checking and warnings, code
completion, optimizing compilers, etc.

These types of imperative patterns make life extremely hard on tools, which
now need to add in unreliable things like escape analysis to be able determine
which classes are visible. Modules will help a little with explicit exports,
so that the importing modules have some hope of tooling, but analysis within a
module would suffer.

------
ravicious
What about private functions? For now I just add `_` in front of their names,
but the code would look so much cleaner if I had some kind of a `private`
keyword.

~~~
Zikes
I don't see why this technique wouldn't also work for methods, especially with
the addition of computed property names [1].

[1] [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names)

~~~
braythwayt
This technique absolutely works for methods. And again, this shows the
elegance of having simple features that compose, rather than building a
monolithic OO system.

~~~
Animats
In practice, that turns into far too many ways of defining classes in
Javascript. There are at least four major approaches, and that was last year.

~~~
braythwayt
If you want something that isn't in the language, you build it yourself. If
what you build becomes popular, in the fullness of time it gets built into the
language as a full feature or as syntactic sugar. That's exactly how we got
the class keyword, modules, everything.

But if you choose the wrong thing, one day your choice is obsolete. That is a
risk, and it's prudent consider the consequences carefully.

If that troubles you, by all means write your code without any encapsulation,
and wait for the language to acquire the feature in a few years. In the mean
time, your code base will grow without that kind of encapsulation. Only you
can determine whether this is a bad thing or not. YMMV, and all that.

This is a very common problem to ponder, we end up arguing about whether you
should be an early adopter, a main streeter, or a laggard.

But really, the post isn't a screed in favour of using private properties,
it's a suggestion that making classes out of first-class values in the
language gives us the flexibility to build whatever we think we need.

Private properties is a particularly simple example. Traits and mixins are
also useful, but would take even more space to articulate. But the general
point is still that making new things ("classes") out of the existing
materials ("functions and prototypes") is a win in general.

------
emehrkay
This is cool, could this behavior be mimicked by doing:

    
    
        var name = 'name_' + Math.random() ; //assumed uniqueness

~~~
braythwayt
Yes, but you'll also want to use Object.defineProperty to ensure that the
property is not enumerable.

[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)

Symbol tosses that in "for free."

