News for hackers. Stuff that matters.
Re:Classes are Expressions by keithwhor on Thursday June 04, 2015 @03:38PM (#9661552)
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.

Re:Classes are Expressions by togakangaroo on Monday June 08, 2015 @04:10PM (#9682028)
Fantastic, now what if your domain model actually requires an underscore in things? Or more realistically umm ... ooh ... I dunno, how about I want to write some infrastructure, that iterates over objects? Surely, that's not a thing we use literally all the time. But hey, just write the code to filter out underscores.

Oh wait, now I'm passing my object to a third party library that preforms infrastructure? I guess they better provide a hook that I can inject my own naming conventions.

Yes, underscore fields work, until they don't. Is a function that returns an object really that hard for beginners? I can answer that as I actually teach beginners - yes, it's hard for like two class sessions, after the third homework assignment they have no other issues. So yeah, closures are the way to solve this.

I wouldn't use what this article proposes unless I definitely needed classes, but for the 1% of the time that I do this is a pretty nifty solution to one of my biggest gripes.

Re:Classes are Expressions by matchu on Thursday June 04, 2015 @05:08PM (#9662071)
I like the simple syntax of the underscore convention, and I also appreciate that the article's approach actually enforces the encapsulation. I wonder if there's a convenient way to use this structure and also keep the simpler syntax.

Heck, you could probably make a macro such that `this._foo` compiles to `this[privateProperties.foo]`, but I'd probably scream about how misleading that is…

Re:Classes are Expressions by quad50 on Friday June 05, 2015 @10:18AM (#9665630)
What are the reasons for keeping components of a 'thing' private? I go back and forth on this.

1. expose a clean API surface so users don't care how it works (as long as it works :)

2. make it easier to change the innards without changing its public behavior

3. keep malicious programmers from delving into the innards of our precious code.

It seems like a lot of the discussions on encapsulation (over many years) focuses on #3. Especially in the C++ and Java world. But worrying about that leads to various forms of obfuscation that make the code worse. And who cares about folks who will hack our objects? That's their problem.

Re:Classes are Expressions by gotofritz on Saturday June 13, 2015 @05:42PM (#9712791)
It doesn't have to be "malicious" programmers. It can be less experienced, lazy, or under-pressure colleagues.
Re:Classes are Expressions by wvenable on Thursday June 04, 2015 @05:01PM (#9662015)
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.
Re:Classes are Expressions by woah on Thursday June 04, 2015 @07:32PM (#9662918)
In general, js is more about good practices and craftsmanship, and less about finding ways for the language to force people to do things.
Re:Classes are Expressions by wvenable on Friday June 05, 2015 @12:09PM (#9666274)
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.

Re:Classes are Expressions by woah on Monday June 08, 2015 @04:08PM (#9682010)
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.
Re:Classes are Expressions by wvenable on Monday June 08, 2015 @04:55PM (#9682328)
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.

Re:Classes are Expressions by Jare on Thursday June 04, 2015 @05:34PM (#9662261)
Developers willing to make messes in the code must be identified ASAP, and the "_" acts as an easy to see red flag.
Re:Classes are Expressions by stuartaxelowen on Friday June 05, 2015 @12:27PM (#9666369)
As they say in Python - we're all consenting adults.
Re:Classes are Expressions by nickbauman on Thursday June 04, 2015 @05:25PM (#9662179)
Python has been doing this forever and it just works. Objective-C has had access modifiers and such but I find nobody uses them either. It's a baroqueism.
Re:Classes are Expressions by greggman on Thursday June 04, 2015 @03:15PM (#9661410)
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`.

Re:Classes are Expressions by braythwayt on Thursday June 04, 2015 @03:30PM (#9661499)
> I don't get the relucatance to use the language's features rather than hacks

Symbol is a language feature. As is accessing a property with `[` and `]`. Using the language's features as they were designed is not a hack. And I think we may see your browser's tooling improve when it natively supports ECMAScript 2015, instead of whatever is transpiled today.

Now: Why do you think that properties named by symbols have this special property of being non-enumerable by default? Do you think it is just a coïncidence that it is useful for making a pseudo-private property?

I do not think this particular pattern is a "hack," I think it is one of the use cases that were considered when designing symbols in the first place.

But returning to the purpose of the article, whatever you or I may think of the performance of using closures to create private data, your pattern again supports the article's thesis: By making classes out of functions, objects, and prototypes, we can use the features of the language to extend a class's semantics.

If there was a full-featured monolithic class system like Ruby, we might find that the scoping for methods is not like the scoping for lambdas, and thus we can't just use a closure when we want one.

Your proposed solution leverages the exact same property of JavaScript as TFA.

Re:Classes are Expressions by greggman on Thursday June 04, 2015 @11:24PM (#9663735)
I guess I don't see obfusticating my own code as a good pattern. I gave the debugging example. Similarly serialization? With the closure solution I just do

    var Person = function(first, last) {
      var serializable = {
        first: first,
        last: last,
      };
      ...
With Symbol? I guess I just don't see making things more complicated as a positive pattern.
Re:Classes are Expressions by braythwayt on Thursday June 04, 2015 @11:59PM (#9663829)
If you consider the use of symbols as “obfuscating your own code," use closures with my blessing.

What, exactly, is the problem here? I don’t recall the article saying that symbols are the only way to do this, or the best way to do this out of all the options. I recall people saying similar things about closures for a while, until it caught on that closures and lexical scope are a natural part of JavaScript.

TFA’s point is that ECMAScript 2015’s choice to keep classes as first-class functions with prototypes that are objects is what allows us to use all of the techniques we already have for first-class values, including returning them from functions.

As I keep saying, using a closure (if that’s what you want to do) demonstrates the exact same thing, it works because a method is just a function.

Now that we have established that I am not claiming that symbols are better than closures, I will warn you about an edge case: When you use compact method syntax, you do get something that an ordinary function does not provide, the `super` keyword.

I do not know how to make that work in the case where you assign a function to an instance of an object. So if you want to override a function while calling the super-class’s implementation, it might be tricky to use the closure solution.

That being said... I wouldn’t stay up late worrying about it.

Re:Classes are Expressions by munificent on Thursday June 04, 2015 @05:29PM (#9662205)
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! :)
Re:Classes are Expressions by Cushman on Thursday June 04, 2015 @06:09PM (#9662462)
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

Re:Classes are Expressions by munificent on Thursday June 04, 2015 @07:00PM (#9662759)
> [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. :)

Re:Classes are Expressions by Cushman on Thursday June 04, 2015 @07:17PM (#9662839)
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

    ...
Re:Classes are Expressions by gcb0 on Friday June 12, 2015 @04:36PM (#9708358)
so, it is exactly the same as (assume the keys are in a closure i'm too lazy to type it all)

function Person(first, last){ var firstNameProperty = {}, // unique snowflake obj lastNameProperty = {} // yet another unique obj this[firstNameProperty] = first; this[lastNameProperty] = last; }

ES6 should be saving me from typing all the scoping hacks such as closure. not giving me syntax sugar for things i could do already without odd language constructs (now i have to run TWO loops to get my obj properties. which is what everyone is going to do anyway, since you can iterate on all the symbol properties anyway)

Re:Classes are Expressions by rmrfrmrf on Thursday June 04, 2015 @05:57PM (#9662406)
sure :P (EDIT: Just kidding; the parent's point totally flew over my head). I've actually created classes this way in the past when I worked with a team of enterprise Java developers lol. You could also make magic getter/setter methods if you really wanted to get crazy with it.

    var Person = (function() {
        return function(firstName, lastName) {
            var privateVars = {
                firstName: "",
                lastName: ""
            };

            this.getFirstName = function() {
                return privateVars.firstName;
            };

            this.setFirstName = function(firstName) {
                privateVars.firstName = firstName;
                return this;
            };

            this.getLastName = function() {
                return privateVars.lastName;
            }

            this.setLastName = function(lastName) {
                privateVars.lastName = lastName;
                return this;
            };

            this.sameFirstName = function(otherPerson) {
                return this.getFirstName() == otherPerson.getFirstName();
            }

            this.setFirstName(firstName);
            this.setLastName(lastName);
            Object.freeze(this);
            return this;
        }
    }());

    var p = new Person("John", "Doe");
    var q = new Person("John", "Smith");
    var r = new Person("Jane", "Doe");

    p.sameFirstName(q); // true
    p.sameFirstName(r); // false
Re:Classes are Expressions by Cushman on Thursday June 04, 2015 @06:17PM (#9662514)
This isn't quite the same; the parent is pointing out that you can implement `sameFirstName` without exposing `firstName` publicly at all, not even as a getter.
Re:Classes are Expressions by rmrfrmrf on Thursday June 04, 2015 @06:28PM (#9662584)
Oh wow, I totally missed that. Thanks for clarifying!
Re:Classes are Expressions by Cushman on Thursday June 04, 2015 @06:49PM (#9662717)
Np! Mind it is technically possible to do, check out my sibling comment if you haven't already.
Re:Classes are Expressions by serve_yay on Thursday June 04, 2015 @04:21PM (#9661785)
I don't understand why you're talking about this like yours is the normal way and his isn't, or something. Symbols are "real" too.
Re:Classes are Expressions by matchu on Thursday June 04, 2015 @05:01PM (#9662014)
The closure-based solution has been around for a long time; the symbol-based approach is new.

My reaction to the article's approach was largely: okay, cool, this seems approximately as good as the closure-based solution; is there any reason for me to switch? Or is this just a cool toy example to show off classes-as-expressions?

Re:Classes are Expressions by malkia on Thursday June 04, 2015 @05:33PM (#9662251)
It's not new in the some other language worlds, where your approach is also not new - I mean "make-symbol" in Common Lisp...

Btw, once a symbol is created, is it ever garbage collected? (They are not in Common Lisp for example).

Possibly on page reload (for javascript in browser) they would. But how about long-running javascript code?

Re:Classes are Expressions by matchu on Thursday June 04, 2015 @05:50PM (#9662374)
Okay, some better phrasing, then: the closure-based approach has been idiomatic for years, but the symbol-based idiom is new.

What lessons have folks learned from trying these approaches in other languages? Which is more idiomatic, and why?

Re:Classes are Expressions by spankalee on Thursday June 04, 2015 @03:38PM (#9661550)
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.

Re:Classes are Expressions by ravicious on Thursday June 04, 2015 @01:59PM (#9660908)
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.
Re:Classes are Expressions by Zikes on Thursday June 04, 2015 @02:12PM (#9661007)
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...

Re:Classes are Expressions by braythwayt on Thursday June 04, 2015 @02:26PM (#9661125)
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.
Re:Classes are Expressions by Animats on Thursday June 04, 2015 @02:29PM (#9661141)
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.
Re:Classes are Expressions by braythwayt on Thursday June 04, 2015 @02:50PM (#9661279)
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.

Re:Classes are Expressions by rmrfrmrf on Thursday June 04, 2015 @03:44PM (#9661582)
That's part of why I think CoffeeScript isn't going anywhere anytime soon.
Re:Classes are Expressions by ravicious on Thursday June 04, 2015 @02:39PM (#9661206)
Sure thing, but could you show an example? Let's say we want the `rename` function be private, this is what I came up with: https://gist.github.com/ravicious/5412eebf8a1934ec7886

I don't particularly like this solution, because now I can't just write `this.rename()` in other Person functions. That's why I'd rather have a baked-in way to define private properties & functions instead of having to use (in my opinion) this weird syntax and later explain the whys and hows to other developers.

Re:Classes are Expressions by braythwayt on Thursday June 04, 2015 @02:47PM (#9661262)
Writing this[rename](...) instead of this.rename(...) is hardly onerous.

Your solution mostly works, but a simpler one takes advantage of combining computed property keys and compact method syntax:

https://gist.github.com/raganwald/18f8c179101cfd93c291

Re:Classes are Expressions by ravicious on Thursday June 04, 2015 @03:04PM (#9661364)
Okay, now this certainly feels better than my example and is much more bulletproof than prefixing function names with `_`, thanks.
Re:Classes are Expressions by mikegerwitz on Thursday June 04, 2015 @02:54PM (#9661298)
You wouldn't be able to simply; the same issues exist as in ES3 in this regard.

(I wrote about them extensively years back here: http://mikegerwitz.com/papers/coope/coope.pdf.)

Re:Classes are Expressions by emehrkay on Thursday June 04, 2015 @02:41PM (#9661223)
This is cool, could this behavior be mimicked by doing:

    var name = 'name_' + Math.random() ; //assumed uniqueness
Re:Classes are Expressions by braythwayt on Thursday June 04, 2015 @02:44PM (#9661237)
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...

Symbol tosses that in "for free."