Live data from Hacker News

Classes are Expressions

raganwald.com

21–30 of 46 posts

Re: Classes are Expressions

#21

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 pe…

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.

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

#22

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…

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

#23

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…

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

#24

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…

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

#25

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 pe…

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

#26
post #21

Earlier quoted context omitted.

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.

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?

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

#27

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…

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.

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

#28
post #26
post #21

Earlier quoted context omitted.

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?

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?

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

#29

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 pe…

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]…

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

#30

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 pe…

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]…

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

Post reply on HN