classes and enumerability

Brendan Eich brendan at
Wed Dec 24 16:05:29 PST 2014

Kevin Smith wrote:
>     Here is the summary:
>     Total Files Read:  11038
>     Files Containing Explicit 'enumerable: false':  149
>     Occurrences of 'enumerable: false' (and variants): 206
> I love this kind of analysis - thanks!

Agreed, <3 -- thanks, Rick!

> My interpretation of this data is that non-enumerability isn't 
> important enough to bother with in the vast majority of cases.

There's a confounding variable: the pain of ES6s meta-object APIs, in 
all respects.

It's probably true that enumerability doesn't matter enough for many 
programmers, but the ES5 MOP is painful enough (both its intrinsic 
complexity and ES5's indirect costs, e.g., needing to shim into 
ES3-level engines) that it does not seem prudent to assume only one 
cause, or to assume which cause is proximate vs. distal.

For those who care about prototype method enumerability, however many 
they may be, if too few pass the ES5 hurdle (for whatever reason), then 
the measurements Rick took, while informative, are not decisive.

>   It *may* still be that non-enumerability is the least-surprise 
> option for class methods, but certainly users don't care enough about 
> the issue currently to bother with typing in "enumerable: false".

This came up on the twitter thread. If we pick a painful default, people 
will still probably migrate to the shortest-path-to-joy, arguably class 
syntax. In this light we can hope not to do too much harm, either way.

But what's best? I'd like to think it's non-enumerability, based on 
built-ins combined with for-in from the old days. I made built-in 
methods non-enumerable because that made for-in much more useful, 
compared to design alternatives (built-in prototype methods enumerable; 
no such thing as non-enumerable). It may be that even early JS didn't 
have enough time to experiment and find an even better way, e.g., 
explicit shallow vs. deep enumeration. That adds more user-facing 
complexity in choice of looping forms.

> I'm still concerned about the refactoring hazard argument.  I think 
> the idea is that if I change some ES5-style class into an ES6-style 
> class, then I need to have good unit tests already in place to make 
> sure that non-enumerability won't break things.  Otherwise, I can't do 
> the refactor.
> What do we think about that one?

Yehuda made the point on twitter that enumerability matters for object 
literals passed to extend-ish methods, and object literals >> class 
prototypes. There are many objects created from literals, some of which 
are used as arguments to extend. There are few class prototypes, the 
built-in ones already have non-enumerable methods, and ES6 classes are 
new enough that if non-enumerable wins on balance, there won't be a 
refactoring hazard to-do with extends.

Other for-in-based library code than extend could break, but would with 
a built-in class that otherwise resembled the new ES6-usercode one. So 
the "design of class obligations" must include choosing and coding some 
enumerability non-default annotation or extra API boilerplate. Since 
non-default, it will be less common, possibly rare. So back to the 
"what's the best long-term default" question we cannot duck right now.


More information about the es-discuss mailing list