|
| 1 | +{ |
| 2 | + "template": "blog", |
| 3 | + "blog": true, |
| 4 | + "title": "A Formal Commitment to New Language Features", |
| 5 | + "author": "Mike Pennisi", |
| 6 | + "date": "2015-07-07", |
| 7 | + "url": "/blog/new-lang-features" |
| 8 | +} |
| 9 | + |
| 10 | +In recent months, JSHint has been receiving requests to support [proposed |
| 11 | +JavaScript language features](https://github.com/tc39/ecma262) like |
| 12 | +[`async`/`await`](https://github.com/tc39/ecmascript-asyncawait), [method |
| 13 | +decorators](https://github.com/wycats/javascript-decorators), and [class |
| 14 | +property declarations](https://gist.github.com/jeffmo/054df782c05639da2adb) |
| 15 | +[[1](#ref-1)]. The JSHint team has turned down each request, even after the |
| 16 | +release of [ES2015](http://www.ecma-international.org/ecma-262/6.0/). This has |
| 17 | +not been easy; as open source project maintainers, nothing gives us more |
| 18 | +pleasure than to write code in benefit of our users. We've tried to explain our |
| 19 | +motivations in an ad-hoc way, but it's always come off as a bit haphazard. We'd |
| 20 | +like to take some time to more thoroughly describe our thought process. |
| 21 | + |
| 22 | +The long and short of it is: JSHint will require all language extension |
| 23 | +proposals to be at "Stage 2" of [TC-39's standardization |
| 24 | +process](https://docs.google.com/document/d/1QbEE0BsO4lvl7NFTn5WXWeiEIBfaVUF7Dk0hpPpPDzU/edit?pli=1) |
| 25 | +before parsing and linting them. |
| 26 | + |
| 27 | +## Why so defensive? |
| 28 | + |
| 29 | +Projects like [Traceur](https://github.com/google/traceur-compiler) and |
| 30 | +[Babel](http://babeljs.io/) have become very popular through progressive |
| 31 | +implementation of the latest features and proposals. It's fair to question why |
| 32 | +JSHint should be any different. |
| 33 | + |
| 34 | +First off, **it's difficult for the project maintainers**. This is not really a |
| 35 | +defensible motivation; we only offer it in the interest of full disclosure. |
| 36 | +Over the years, JSHint has grown from [JSLint](http://jslint.com/) thanks to |
| 37 | +the efforts of hundreds of contributors. This has been key to its success, but |
| 38 | +it has also contributed to a fair amount of technical debt. Extending the |
| 39 | +parser requires a fair amount of study, and even then, it isn't always clear |
| 40 | +how to do this cleanly. |
| 41 | + |
| 42 | +The project has tried to be progressive about new syntax in the past |
| 43 | +[[2](#ref-2)], and this has often contributed to technical debt. For instance, |
| 44 | +JSHint continues to |
| 45 | +([grudgingly](https://github.com/jshint/jshint/pull/2519#issuecomment-118409190)) |
| 46 | +maintain [a `moz` option for Mozilla-specific |
| 47 | +extensions](https://github.com/jshint/jshint/blob/e32e17b97289e4bb5a53116ffc3a979356792088/src/options.js#L466-L476), |
| 48 | +and the current `esnext` option includes non-standard array comprehensions. (By |
| 49 | +the way: now that ES2015 is released, that name describes a non-existent |
| 50 | +specification draft.) |
| 51 | + |
| 52 | +[A plugin system](https://github.com/jshint/jshint/issues/2079) is one possible |
| 53 | +way to address this, but that will require a large effort involving careful |
| 54 | +design, spanning refactoring, and a long-term commitment to implementation |
| 55 | +details. |
| 56 | + |
| 57 | +More importantly, **it's hazardous for developers**. Inconsistencies within |
| 58 | +toolchains will gate developers on the lowest common denominator. Imagine the |
| 59 | +day that your transpiler supports draft 17 but JSHint has moved to draft 18. |
| 60 | +Even if you're not struggling with coordination issues between parsers, the |
| 61 | +release cycle for a "progressive" parser would leave most application |
| 62 | +developers behind. Projects would frequently rely on outdated release channels |
| 63 | +that no longer received bug fixes or new features. |
| 64 | + |
| 65 | +[JSHint was born out of a reluctance to make decisions on behalf of the |
| 66 | +user](https://medium.com/@valueof/why-i-forked-jslint-to-jshint-73a72fd3612), |
| 67 | +so while we think the above considerations should be made clear to JSHint's |
| 68 | +users, we haven't made this decision based on them. |
| 69 | + |
| 70 | +We also believe **it's harmful for the ecosystem**. Empowering developers to |
| 71 | +write non-standard code can have long-term effects on the open source |
| 72 | +ecosystem. Code has a tendency to live longer than we expect, but it isn't |
| 73 | +always maintained throughout its lifetime. We all look forward to the day that |
| 74 | +features like method decorators are standard and widely-supported. Prior to |
| 75 | +that, it's important to remember that the code we write with experimental |
| 76 | +language features is itself non-standard. It will be frustrating if, in 2 |
| 77 | +years, you are reviewing older code that seems to use "standard" function |
| 78 | +decorators but that in reality depends on the syntax and semantics of "revision |
| 79 | +12" of the function decorator proposal. The differences may be subtle, and you |
| 80 | +will be forced to research the behavior of this not-quite-JavaScript before you |
| 81 | +can contribute to the project. |
| 82 | + |
| 83 | +Finally, **it's unhealthy for the language**. TC39 does not operate from an |
| 84 | +ivory tower. They recognize practical considerations of patterns in existing |
| 85 | +code. Look no further than [Annex |
| 86 | +B](http://www.ecma-international.org/ecma-262/6.0/#sec-additional-ecmascript-features-for-web-browsers) |
| 87 | +for proof of that. Sometimes, that is a good thing. [The Promises/A+ |
| 88 | +spec](https://promisesaplus.com/) offered a clear way forward when Promises |
| 89 | +were first considered for inclusion in ES2015. Sometimes, this is a bad thing. |
| 90 | +It's the reason why we expect |
| 91 | +[`Array.prototype.includes`](https://github.com/tc39/Array.prototype.includes/) |
| 92 | +instead of |
| 93 | +[`Array.prototype.contains`](https://esdiscuss.org/topic/having-a-non-enumerable-array-prototype-contains-may-not-be-web-compatible). |
| 94 | +The proliferation of production code can have [a solidifying |
| 95 | +effect](https://medium.com/@morrissinger/the-rise-of-the-bully-pulpit-in-the-evolution-of-javascript-94fb394d3b69) |
| 96 | +on new features. To the extent that JSHint is a channel through which new |
| 97 | +JavaScript flows (a minuscule one to be sure), we want to cooperate with the |
| 98 | +design process. |
| 99 | + |
| 100 | +## So why stage 2? |
| 101 | + |
| 102 | +Stage 2 seems specifically designed for our position in the ecosystem. |
| 103 | + |
| 104 | +It's not too early. Features in this stage have a formal definition (so we have |
| 105 | +a consistent and complete set of instructions to build from). These features |
| 106 | +are also relatively stable, so JSHint has a chance to keep up with the latest |
| 107 | +draft modifications. |
| 108 | + |
| 109 | +It's also not too late. The design process can still benefit from the |
| 110 | +experience of developers applying a given pattern to their code. The process |
| 111 | +document defines "incremental" changes expected for Stage 2 proposals, and only |
| 112 | +recommends "experimental" implementations. You might say, "[these features seem |
| 113 | +stable enough](https://bugzilla.mozilla.org/show_bug.cgi?id=258974#c22)", but |
| 114 | +the truth is, JSHint was dealing with non-trivial modifications to ES2015 from |
| 115 | +the moment we implemented them until as late as May of this year [[3](#ref-3)]. |
| 116 | +So it's worth noting that JSHint is *still* taking some risk here. |
| 117 | + |
| 118 | +We think there's tremendous value in experimentation at earlier stages in the |
| 119 | +process. We also feel that research should be conducted in non-production |
| 120 | +settings in order to avoid the more fundamental problems discussed above. |
| 121 | +Early-stage experiments have less to gain from automated code analysis both |
| 122 | +because of their limited scope and because their syntax is already verified by |
| 123 | +a "transpiler". In these contexts, linting has much more limited relevance. |
| 124 | + |
| 125 | +## Moving forward |
| 126 | + |
| 127 | +Here's the practical effect of all that talk: |
| 128 | + |
| 129 | +- JSHint 3 will not expose an `esnext` option; it will instead support |
| 130 | + `esversion: 6`. |
| 131 | +- JSHint will continue to support the `moz` option, and it will be the only |
| 132 | + setting that enables array comprehension parsing. |
| 133 | +- JSHint will *not* expose an `esversion: 7` option until that specification is |
| 134 | + finalized by ECMA. |
| 135 | +- JSHint will support for stage-2-and-above proposals under the `experimental` |
| 136 | + configuration namespace. These features will be clearly documented as subject |
| 137 | + to breaking changes between major releases. |
| 138 | + |
| 139 | +This policy means denying first-class support for non-standard and early |
| 140 | +proposal features. JSHint will continue to support `ignore` directives as a |
| 141 | +coarse-grained mechanism for operating on non-standard and early-proposal |
| 142 | +features, but we know [other linting tools go much farther than |
| 143 | +that](https://github.com/babel/babel-eslint). We're motivated by our |
| 144 | +responsibility to developers but also to the open source ecosystem and to the |
| 145 | +standards process itself. We hope JSHint's usership continues to enjoy the tool |
| 146 | +because they share these same values. |
| 147 | + |
| 148 | +--- |
| 149 | + |
| 150 | +<span id="ref-1"> |
| 151 | +[1] Requests for proposed language features: |
| 152 | + |
| 153 | +- [gh-1977 WIP: Async/await](https://github.com/jshint/jshint/pull/1977) |
| 154 | +- [gh-1979 Added optional asyncawait support on top of |
| 155 | + esnext](https://github.com/jshint/jshint/pull/1979) |
| 156 | +- [gh-2077 AsyncAwait plugin](https://github.com/jshint/jshint/pull/2077) |
| 157 | +- [gh-2297 Please add support for ES7 method |
| 158 | + decorators](https://github.com/jshint/jshint/issues/2297) |
| 159 | +- [gh-2304 ES7 Class Properties throws 'Unexpected token |
| 160 | + ='](https://github.com/jshint/jshint/issues/2304) |
| 161 | +- [gh-2309 class property initializers |
| 162 | + proposal](https://github.com/jshint/jshint/issues/2309) |
| 163 | +- [gh-2310 Support for ES7 |
| 164 | + decorators?](https://github.com/jshint/jshint/issues/2310) |
| 165 | +- [gh-2504 ES7: async and await](https://github.com/jshint/jshint/issues/2504) |
| 166 | + |
| 167 | +</span> |
| 168 | + |
| 169 | +<span id="ref-2"> |
| 170 | +[2] Introduction of ES6 features |
| 171 | + |
| 172 | +- [gh-971 Arrow functions](https://github.com/jshint/jshint/pull/971) (13.03.28) |
| 173 | +- [gh-1048 ES6 classes](https://github.com/jshint/jshint/pull/1048) (13.05.19) |
| 174 | +- [gh-1608 Support ModuleImport |
| 175 | + expressions](https://github.com/jshint/jshint/pull/1608) (14.04.05) |
| 176 | +- [gh-1563 Add basic support for ES6 |
| 177 | + TemplateLiterals](https://github.com/jshint/jshint/pull/1563) (14.03.21) |
| 178 | + |
| 179 | +</span> |
| 180 | + |
| 181 | +<span id="ref-3"> |
| 182 | +[3] Issues involving changes to the spec: |
| 183 | + |
| 184 | +- [gh-1123 A generator function shall contain a yield |
| 185 | + statement.](https://github.com/jshint/jshint/issues/1123) |
| 186 | +- [gh-1936 ES6 (`esnext`) error: `import * as foo from |
| 187 | + 'bar'](https://github.com/jshint/jshint/issues/1936) |
| 188 | +- [gh-2019 ES6 classes with export default flagged as 'not |
| 189 | + defined'](https://github.com/jshint/jshint/issues/2019) |
| 190 | +- [gh-2144 Support more cases of ES6 module |
| 191 | + usage](https://github.com/jshint/jshint/pull/2144) |
| 192 | +- [gh-2197 ES6 (esnext:true), jshint says "Foo is not defined"... but it's |
| 193 | + defined!](https://github.com/jshint/jshint/issues/2197) |
| 194 | +- [gh-2395 jshint incorrectly supports the module x from 'y' |
| 195 | + format?](https://github.com/jshint/jshint/issues/2395) |
| 196 | + |
| 197 | +</span> |
0 commit comments