Hacker News new | comments | ask | show | jobs | submit login
WebKit is now 100% ES6 complete (twitter.com)
755 points by M4v3R on May 16, 2016 | hide | past | web | favorite | 109 comments



The jump in support from Safari 9 (53%) to TP (99%, and then the last little bit from TP to current WebKit) is staggering.


Webkit was probably one of the last major web engines to start integrating ES6 features, yet they have TCOs done. Anyone explain what's holding it up in Chrome/FF/Edge?


We wrote about this in detail in http://v8project.blogspot.com/2016/04/es6-es7-and-beyond.htm... under the heading "Proper Tail Calls".

tl;dr we implemented it, it works, but we are not shipping it because we believe it would hurt developers to lose some stack frames from Error.stack in existing sites, among other issues.


Our approach was to make our debugger still show those frames, and to observe that in the year since we've had tail calls in builds, we haven't seen a single compatibility issue from the change to error.stack behavior.


I program in Lua, which does to TCO and I've never found it to be an issue with debugging. Now, that could be because of the ways I use TCO---I tend to use it in a recursive routine:

    function mainloop()
      local packet = receive()
      if not packet then
        syslog('warning',"error")
        return mainloop()
      end
      process(packet)
      return mainloop()
    end
(mainly because Lua does not have a 'continue' statement, and this is the best way I've found to handle that) or in state machines:

    function state_a(state)
      return state_b(state)
    end

    function state_b(state)
      return state_c(state)
    end

    function state_c(state)
      if somecondition()
        return 'done'
      else
        return state_a(state)
      end
    end
The thing to remember is that a TCO is a form of GOTO. And with GOTO, you have no stack entry, but given that this is a controlled GOTO, I don't see much wrong with it. Do most programmers find TCO that confusing? Or is it the perception that most programmers will find TCO confusing? Have any real studies been done?


You will like the examples in the `original TCO' paper.

http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-...


If the main worry is information loss when debugging, why not figure out a mechanism that's 98% accurate but much more efficient than a full redundant shadow stack?

For example, you could compact the stack every 200 frames it grows, but never remove frames in the top 50 or bottom 50. How often in practice would that give you a misleading view of the stack? (Assume that each frame keeps track of how many tail frames are omitted after it. If needed, assume that tail frames within X distance of a non-tail frame will not be omitted ever.)


We figured out such a mechanism and we call it ShadowChicken: http://trac.webkit.org/changeset/199076

It works great!


One of the things I like most about WebKit is that several of you reliably write awesomely informative commit messages.

(I hope Felix sees this particular commit sometime; I think he might feel a little flattered! Also, wow, that's an excellent summary by Peter Bex.)

Another is that you keep looking into old quiet dark corners of language nerdery and actually make use of the good ideas lurking there (notably while retaining the "no performance regressions EVER" tyranny).

I think there are some neat ideas Chicken Scheme's compiler too.

Also, did you have a raiding party on T when doing DFG? (cf. Olin Shivers at http://www.paulgraham.com/thist.html starting with the paragraph, "This brings us to the summer of 1984. The mission was to build the world's most highly-optimising Scheme compiler." and notably also the paragraphs starting "Richard Kelsey..." and "Norman Adams...". . Always take ideas from Shivers, at least if they're faster in practice. Also, sorry for the several edits. I forgot how good this overview was, and how much meat is in it.)


pizlonator, Is ShadowChicken cheap enough to turn on all the time and make Error.stack work similarly to without PTC?


It probably could be, but we deliberately don't do it, because:

1) I'm not aware of complaints about the change to error.stack behavior from users or developers. I don't know of an app that broke because of the change to error.stack. I don't know of an app whose telemetry got messed up because of the change to error.stack. So, we don't have a real-world test case that would be improved or fixed by integrating ShadowChicken into error.stack. We're not going to impose any overhead, or spend time trying to optimize that overhead, if it isn't going to benefit anyone.

I've heard lots of hypothetical fears about error.stack changing, but I haven't seen a real-world example of the change in error.stack behavior being harmful. If you know of an app that breaks because of our error.stack change, please let us know!

2) Philosophically, we view the feature as PTC (proper tail calls), not TCO (tail call optimization). If it was an optimization then we'd want it to be hidden from the user. But that's not what PTC is: it's a guarantee to the user about how the stack will behave. Therefore, we make error.stack precisely reflect PTC. We go to great lengths to emulate PTCs in some cases to make this work, for example if the optimizing JIT is involved. For example:

function foo() { ... } // say that this is inlined

function bar() { return foo(); } // this tail-calls foo. say that this is inlined

function baz() { return bar() + 1; } // say that our top-tier JIT compiles this

In this case, foo and bar will sort of cease to exist since all that really matters for execution is the code that the JIT generated for baz, which now also includes the code for foo and bar. Inlining is super careful about error.stack. In this case, our optimizing JIT's inlining data will include complete information about the call stack (baz->bar->foo) but will flag the bar frame as tail-deleted so that error.stack will only show baz->foo.

So, instead of making ShadowChicken hide PTC from error.stack, we actually have an entirely separate set of features to make error.stack precisely reflect the reality PTC. On the other hand, if you open the inspector, we want ShadowChicken to show you the tail-deleted frames and to flag them appropriately. The inspector integration WIP is here: https://bugs.webkit.org/show_bug.cgi?id=156685

Screenshot: https://bug-156685-attachments.webkit.org/attachment.cgi?id=...

TL;DR. JSC doesn't try to lie to its clients about PTC. PTC is part of the language, so we precisely reflect PTC's behavior in error.stack and in the inspector (the tail-deleted frames show up but are flagged as such).

(EDIT: I changed the definition of bar and baz above because my original example didn't have the tail calls that I wanted.)


I will bite the bullet: Do you have a sense of how many devs use Safari compared to Chrome/FF for debugging?


I don't have such numbers, and I'm not sure they would be relevant to this discussion.

We already know that debugging isn't the issue. ShadowChicken solves the debugging problem and other VMs could do it, too. ShadowChicken is just one possible algorithm in a much larger family of chicken algorithms.

The only way that PTCs are observable outside the debugger - beyond making you run faster and use less memory - is error.stack. Hence the challenge: find me a website that uses error.stack in such a way that PTC breaks that website. Surely if the other VMs are so against PTC on the grounds that it will break websites, they will be able to tell us about a website that broke in Safari because of PTC.


I do. Sometimes.

Even if were the worst engine since IE4, it's Not Chrome(tm) and can help when chrome dev tools fail (or - more likely - I fail at working with chrome dev tools and need a fresh perspective.)

It's also good practice to run the profilers at least occasionally, because (a) performance in Safari is relevant and I've been bitten by idiosyncrasies where one browser took >5x than another (in all directions. And (b), as above, just by being different they may add useful information.


In the linked commit the "readme" states a 6% overhead.


Ah, too bad to hear that's the route you're going that route given the discussion here https://twitter.com/getify/status/716861612850749440

What changed your/the team's mind?


There's been heavy discussion (especially recently) on the value of implicit TCO for developers. I believe all three V8/Chakra/Spidermonkey all found TCO regresses performance a bit. Additionally, it hampers debugging considerably as call stacks are completely twisted.

There's been a lot of active discussion between browser vendors and TC39 recently to sort out a path forward. All teams are excited about explicit TCO syntax, but there remains skepticism that implicit TCO is good for users or developers.


TCO is "tail call optimization" if anyone is trying to figure it out.


How does tail call optimization cause a regress in performance? Superficially, it seems very counter-intuitive that this should even be possible.


It's not a performance regression in JSC. Maybe the other implementations aren't as good as JSC's.


Shots fired.


Messes with calling conventions. Citing Rust: https://mail.mozilla.org/pipermail/rust-dev/2013-April/00355...


I agree that it messes with calling conventions.

This is a problem for AOT languages, where binary compatibility is paramount and so you cannot change the calling convention. Since tail calls don't play well with existing native conventions, they end up being hard (or sometimes even impossible) to implement.

That's not really an issue in JS or other VM-based languages. JS VMs don't make their internal calling conventions public. In JSC, our old calling convention was incompatible with PTC, so we changed our calling convention to make PTCs work.


GCC/Clang can generate code with tail calls, if you don't mind losing the stack frame. And I don't think they have any issue tail-calling external libraries on the ABIs I know. How are these different?


It's worth noting that's from 2013; in my understanding, things have changed in LLVM since then, which was another big blocker.


There's some debate over whether tailcalls should be explicit or implicit, and Chrome/FF/Edge are leaning towards the explicit side:

https://news.ycombinator.com/item?id=11563305


Yet only 98% ES5 compliant: https://kangax.github.io/compat-table/es5/

No browser is at 100%, BTW.

Waiting for a WATWG JavaScript standard that removes these parts from the spec...


Are you aware of https://javascript.spec.whatwg.org/? :) Thankfully that spec is almost obsolete as TC39 has moved much of it into the main spec over time. It used to be the only place important de-facto language features like __(define|lookup)(Getter|Setter)__, or String.prototype.blink, or Function.prototype.{arguments,caller} were specified. You can see the history of it getting smaller in https://github.com/whatwg/javascript/commits/master.

On the subject of the table, it's interesting that Firefox's only failure is in "Date.parse produces NaN for invalid dates". However, as far as I can tell this is not a requirement of the spec, since per https://tc39.github.io/ecma262/#sec-date.parse

> If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.


IMHO, we should switch from that mess to common repository of JS libraries (CJSAN), which can be referred using tags like <lib name="foo" version="1.0"><script .../></lib>. Such libraries will act as polyfills for an API, while browsers will be able to provide optimized versions of these libraries.

I.e. instead of waiting for ecma262 to be implemented by all browsers, scripts can just load common polyfill, which then can be overridden by browser later:

   <lib name="ecma262" version="1.0"><script scr="https://cdn.host/ecma262.polyfill.js"/></lib>


Maybe I should have said a WATWG YavaScript standard...

I didn't know the standard existed.

Generally, agree with the "let's put back every piece of dung in place after paving the cowpath" approach the WHATWG follows. Anosmic folks come to rely on the reduced friction coefficient...

I suppose that the Date.parse stuff was updated between ES5 and the living stabdard.


You can pretty much consider Opera 12.10 100%. The only thing missing is "parseInt ignores leading zeros", which is such a minor issue (octal bugs I assume).


Heh, after I saw it was 96-7% last time (when the developer preview versions were announced), I was pretty sure they'd push it to 100% soon, to make a (small) point of it on the WWDC Keynote.


This is nice. But I still think platform features in WebKit such as webrtc and fewer bugs in indexeddb would be a better place for them to focus... Service workers too


Does this include native module import/export? I never saw anything to suggest they were even working on that.


Module import/export syntax was in ES6, but the browser implementation has not yet been standardized.


Well, it's been standardized, but implementation work is still ongoing. Details at https://blog.whatwg.org/js-modules


I'm confused by what it means that the semantics of imports weren't part of the spec yet. Do you mean polyfills like es6-module-loader (https://github.com/ModuleLoader/es6-module-loader) were just guessing how modules would behave?


The wonders of standards: the standards committee for JS language syntax (ECMA TC39) is a different standards committee from the committee for Browser behaviors like loading (WHATWG). (So many standards bodies to choose from!) The WHATWG Module Loader spec has been slower to be "finalized" and adopted than the ES2015 spec.


Although your larger point stands, about the division of responsibilities, it's important to distinguish "specifying browser module loading" from the Loader spec draft.

The loader repository at https://whatwg.github.io/loader/ is an experimental proving ground, as noted by its title ("A Collection of Interesting Ideas") and its Status section ("This document is a work in progress and dreams of becoming a living standard."), as well as the fact that it's in the whatwg.github.io namespace instead of the spec.whatwg.org namespace. To my knowledge no browser implementers have begun implementation of the experimental ideas here.

Contrast that with the agreed-upon work in the WHATWG HTML Living Standard discussed at https://blog.whatwg.org/js-modules, which is relatively finalized and is being actively implemented now in all browser engines.

I think we will see a gradual stabilization of the experimental ideas in the Loader spec, either in the Loader spec itself (with the stable ideas staying, and the experimental ones moving to a supplementary document) or by moving the relevant spec text into other locations (HTML and/or ES, probably). For example, I would hope that we will soon see a very simple promise-returning `importModule("./foo.js")` async module loading API, far ahead of the loader's more experimental in-browser-transpilation APIs or create-a-module-from-scratch-reflectively APIs. That could be done either by specifying it in the Loader spec, or by specifying it in ES with a call-out to a HostFetchModule() abstract operation, which HTML then specifies for browser hosts.


> Contrast that with the agreed-upon work in the WHATWG HTML Living Standard discussed at https://blog.whatwg.org/js-modules, which is relatively finalized and is being actively implemented now in all browser engines.

Just to clarify, unlike TC39, the WHATWG HTML ("Living Standard") spec requires no consensus at all in order to add new features. Consensus is arrived at once all implementers have implemented the relevant features to the stable versions of their browsers.

To say that what is in the spec has consensus at the same time as browser implementers are beginning implementation (and expressing some concern over details) gets the WHATWG process backwards.


That's not correct, Yehuda. For HTML especially, we work on a rough consensus model wherein features are not added to the spec unless they have multi-vendor implementation interest and review.

If you'd like to analogize to the TC39 process, features are merged into the HTML Standard once they've reached TC39 "stage 3".


So are you saying that, for example, the change to CORS from <script> in <script type='module'> has multi-vendor consensus?


Yes, that's exactly correct. Babel, polyfills, etc. were all just guessing at the future.


When TC39 creates ES modules, it's re-inventing the wheel ("The node community has already made modules that work, why'd you make a new one??").

When the Babel community creates a module loading approach, it's guessing at the future ("The spec is the law! When the community makes something, it's guessing at the law!").


I wouldn't say es6ml was "guessing", it was based on the old loader spec that was removed from ES2015, and was quite accurate. It's no longer relevant though, since whatwg/loader is quite different.


Import/export has been postponed AFAIK.


Note that this doesn't include ES6 modules. The referenced kangax compatibility table doesn't cover modules, so the tweet is technically correct, but the headline here on HN is a bit misleading.


They're in JavascriptCore, just not yet integrated into WebCore fully.

https://bugs.webkit.org/show_bug.cgi?id=147340


The opposite appears to be the case: https://twitter.com/xeenon/status/729086068666982401


If I had to choose between having all the ES6 features except modules, versus having ES6 modules without all the other ES6 features, I would choose the latter. Sure, I'm biased, because I'm working on a huge single-page app with gazillion lines of JS code...


Although I'm also looking forward to ES6 modules, I've completely forgotten about the issue since I started using Browserify. It "just works".


As far as I know modules aren't a ES6 feature.

Edit: To clarify, I want them standardized more than anything else, but as far as I know ES6 only specified the syntax


Is anyone using Safari Technical Preview as their main Browser? I was hesitant to use it, but I've heard a few people say that it's stable.


It was good for a bit, then 1Password broke and I accepted that my Slack messages were never going to load.

It's a dev preview. There is no reason to use it as your main browser. There isn't even much point testing your site in it, since you can never tell who's responsible for something being broken, and it becomes more a test of how production-ready the preview is, which is a really pointless metric. The only real reason for its existence is so we can all track progress in benchmarks, and for this story to get publicity when all us browser nerds check ES6 compat and then try little code snippets in the console.

If you want the cool purple icon, copy it to to Safari 9. That's what I've done.


Ah if 1Password doesn't work, that's definitely a blocker for me. I could always copy the usernames and passwords from the app, but I don't think I need to test the latest and greatest features that badly.


I think that was fixed in the last TP.


I don't think I'll be able to handle any instability in that right now. My primary development focus doesn't involve web development so having the latest and greatest browser won't benefit me that much. I do want to try the latest features, but I have patience and can wait a few more months.


I mean, you can have it installed alongside regular Safari and just switch between them at will. It's not an all or nothing decision.


I tried for about a week. My complaints with it were the same i have with base Safari, but TP specifically worked fine. No unique issues despite using it as dev platform and a consumer browser.


I wish Safari would have the same incognito mode as Chrome's. Currently, tabs in the same incognito window do not share sessions so you have to log in again on every new tab.


I prefer it this way around. There is even a long standing issue in the Chromium bug tracker https://bugs.chromium.org/p/chromium/issues/detail?id=24690


"Long standing" makes me think it's an open issue, but it was closed as WontFix the same day it was filed, in 2009.


Yep. If I command-click a same-domain link I expect my login to be forwarded to the new tab.


I've been using it as my main browser since release. I've noticed two things:

1) With gifs, Safari TP will loop the first few frames (or whatever loads quickly) and loop that, whilst the remaining frames load, but then never update to looping the entire gif once completely downloaded; refreshing doesn't correct it, just focussing the address bar and hitting to load the gif from cache.

2) Math.random() returns the same result the first two calls on page load.


LOL @ Math.random()

Tracked here: https://bugs.webkit.org/show_bug.cgi?id=157805


Yeah, that was too hilarious a comment to not check out.

Great job spotting it chrstphrknwtn!


I've been using it for about a month now as my main browser, haven't had any issues with it. Any issue's I had in Safari 9 seem to have been fixed :)


It is my main browser. Last week there was an update that bricked it. I had to redownload it from apple.com ignorer to get it to work. Other than that it is very good, can't really tell the difference between it, webkit nightly, and reg safari (I don't dev on bleeding-edge though).


I'm currently using it; some sites that serve popups can cause the webpage to disappear, prompting the back button, but other than that it works great.

I changed the icon out with the original safari icon though, personal preference, and set it as my system default web browser.


I did use the 1st release on a daily basis, but I had some problems with it (few websites misbehaved). I may revisit it since it's already at its 4th release and they fixed a ton of bugs judging from their release notes.


So, today I'm using babel to transpile my code to es5.

Anyone know of any good tooling to use transpiled code for older browsers and es6 for newer?


It'd be nice to see support similar to Autoprefixer[1]'s use of Browserlist queries[2]. Those let the developer to specify the desired target platforms by browser versions, by global usage stats (e.g. '> 5%'), or by custom usage stats ('> 5% in my stats') etc., and derive the correct prefixes needed to deploy to those targets.

EDIT (for clarity): It'd be great to see similar query support to derive a "lowest common denominator" Babel preset for an intended ES generation vs. browser profile set.

[1] https://github.com/postcss/autoprefixer [2] https://github.com/ai/browserslist#queries


Yep, it's our plan to do something like that with community help - have a PR open for discussion at https://github.com/babel/babel/pull/3476.

Also https://twitter.com/samccone/status/722826060161617923.


What you are describing is serving up different assets based on user agent detection. The "tool" in this case would be the application responsible for serving it, most likely either your custom server-side web app code, or your web server itself.

You should continue to use the transpilers for some time though. It has been reported that many ES6 features run quite a bit faster as transpiled ES5 than natively as ES6.


It should be possible to do so client-side by having a bit of loading / bootstrapping JS that does the feature detection.


While technically feasible that is a low quality solution for the sake of keeping the solution space in JavaScript. JavaScript-based feature detection is one thing but conditionally loading the entire application is another. It is wholly pointless if you are already transpiling to ES5, and as mentioned numerous times, a performance problem in at least the short term.


Is ES6 native much faster than transpiled?


Here's a chart: https://kpdecker.github.io/six-speed/. Often the answer is "not yet". Transpilers convert the code to ES5, which has benefited from six years or optimization. New ES6 features will take some time to catch up.


From my limited anecdotal testing no. In fact it may be slower. This is a good view of this: https://kpdecker.github.io/six-speed/

However... the potential upside is size. Native code will usually be smaller, which for a web client is a win.


I'm having trouble reading the table, when it says 16x slower, is it saying the implementation is slower or the engine?


You might be missing the header row of the table listing various engines and their versions, and the little note that says "Performance of ES6 features relative to the ES5 baseline operations per second."

And I would assume that the baseline has been established on a per-engine basis.


I remember having exactly this impression last time it popped up on HN. Bad design needs explaining.


Watching that table makes me think it's about time to start switching to es6


You don't need to wait to use ES2015, just use a transpiler and your ES2015 code will work with most reasonably ES5 browsers.


And then, IE happens to your plans.


Ever heard of Babel?


If you're using Babel already, WebKit hitting 100% support is irrelevant. IE is going to be the thing that prevents us from running ES6 natively in the browser for several years more.


I was going to reply it wasn't that long, until i realized ie will be around in meaningful numbers for another 4 years. Windows 7 is supported until 2020, and IE is the only game in town there for enterprises. The new distribution policies of w10 will mean plenty of places will run out the clock on w7 support. So, yeah, I guess we're supporting IE 11 for half a decade to come.


I think we're going to see high IE usage in some markets well past that point. Just as an example, almost every Korean website that keep any sensitive data (and many, many that don't), rely on old IE plugins that are never going to be supported by Edge. Although the gov't is now throwing money at developers to rid themselves of the outdated tech, it's going to be a long process.

Chrome JUST took over IE in market share in the last few months here. All other browsers are sub-5%.


IE 11 ships also with Win8.1 and Win10, so IE11 will be around until 2022 or 2025.

IE11 is the new IE6 and will be around a long time in enterprise. Thank you Microsoft. It's epecially annoying as Edge is based just on a refactored and improved trident engine after all, so basically IE12 html engine under hood (and was already called "Edge" in DevTools in IE11).


At the very least, if you use Safari for development you won't need to run Babel every time you change something and want to test it, only for release builds or when you want to test on other browsers, which is nice.


Setting up a build watcher in Grunt/Gulp/etc is really worth the time savings, especially if you use Live Reload. I make a change to a file in vim, and the page reloads with the new build.


There are a lot of node/npm modules that aren't ES6 friendly... unless they pull in and shim out cjs/npm modules, then it will still be some time before it's really useful.


MS now feel the pain when writing a lot web apps: Azure, Office 365, Outlook etc. MS already killed IE 8, 9, 10 and even added nagware in IE11.


Anyone have any clue when we'll see this land in Safari?


In the latest Technology Preview [0] it's already at 99%. Next release on 25th May will have 100%.

[0] https://developer.apple.com/safari/technology-preview/


Probably at WWDC, between June 13 and June 17.


Likely in the developer previews that they release during WWDC then available to consumers in the fall.


I don't think that it will take this long. They pushed out Safari 9.1 this year, which saw pretty significant changes. I think they could release the things from the tech preview with a 9.2 release for El Cap, maybe a month from now (WWDC coincidently?)


open up chrome console, type `class Foo { }` and it works now out of the box. For what it's worth, when you try define a class that already exists. it throws an error. It seems that re-defining an identifier with the `var` keyword will throw an error too. I don't remember this being the case before.


It's been hours and nobody has showed up to call this an atrocity? The JS world really is improving.


Maybe code on the REPL is being evaluated with strict mode on?


is there a `isUseStrictOn()` equivalence? [0]

[0] var isStrict = (function() { return !this; })();


Maybe now they can fix all their layout bugs they've been adding to the browser and not fixing.


Not to be inflammatory, just honestly curious, which layout bugs you're referencing?


I guess this means JScore, right? So Phantom will also be ES6 when it updates.


tfw when "complete" has degrees. sigh.

I'm 99% super confident that this is an almost optimal solution.


Of course it does. If you're working on a task that will take hundreds of hours and your boss asks how far along you are, is your only possible response either "finished" or "not finished"?


And even when you think it's "finished", is that really true? I'm pretty sure no software is ever 100% finished / to spec, esp when the spec is ambiguous like most specs are.




Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: