Engineering

An evening with TC39 in London

No items found.

Two weeks ago members of the TC39 were in London and Keith Cirkel organised an evening for us common mortals. If you are still wondering what TC39 is, you can read a brief description here and there’s also Daniela Matos de Carvalho’s slides.

Some of the TC39 members, photo credits to Myles Boris (shamefully enough I didn’t take any photos)

It was a very casual meetup with a couple of the members on stage, where they started by introducing themselves followed by an explanation on what is TC39 and what’s their main purpose. Passing the mic between them, each member would add something to the conversation. One of the things that was said in the beginning, was that every member has it’s own views and opinions. After a big introduction we went straight to Q&A where anyone from the audience could ask questions. Oddly enough there was only 5/6 questions, because there were so many members, answers would last for 10/15 minutes, with each member trying to give his opinion. And because there were a couple of members among the crowd, after a while members were also rotating places on the stage.

The main topics discussed during this Q&A, was the human side of TC39, and how they as humans manage to find consensus between them, how they manage angry mobs. How one can apply or be more involved with TC39 and why it’s so important for them and the web to keep the future versions of JavaScript from breaking existing websites.

After the Q&A session, developers and members mingled in the room where all different sorts of conversations sparkled. After this, members of TC39 and what was left of the audience went to the pub for a couple of beers, as you do as one is in Britain after all.

After this evening I went back home and had a look at some of the proposals. I don’t tend to follow closely and to be honest I can’t remember when was the last time I had a look at the proposals. So as a gift to you, loyal reader, here’s some of the most exciting proposals, in my humble opinion.

Proposals

Most of these proposals, that I’m about to describe, are quite recent and their API’s are quite unstable so in the future they might change, but it’s kind of cool to have a sneak-peek into the future of JavaScript.

Temporal

This is my favourite one, you can find the spec here. This might not sound very interesting but, this tries to solve the current £#$%^]@ pain that is to work with dates in JavaScript. Basically we will have 3 API's for relative time CivilDate, CivilTime, CivilDateTime and two api’s for absolute time Instant and ZonedInstant. There are plenty of examples on the spec, but if you are too lazy to open the spec in a new tab, here’s some examples using CivilDateTime:

// Properties
let year = civilDateTime.year;
let month = civilDateTime.month;
let day = civilDateTime.day;
let hour = civilDateTime.hour;
let minute = civilDateTime.minute;
let second = civilDateTime.second;
let millisecond = civilDateTime.millisecond;
let nanosecond = civilDateTime.nanosecond;

// Functions
let civilDateTime = CivilDateTime.from(date, time);
let civilDateTime2 = civilDateTime1.plus({days: 3, hours: 4, minutes: 2, seconds: 12});
let civilDate = civilDateTime.toCivilDate();
let civilTime = civilDateTime.toCivilTime();
let zonedInstant = civilDateTime.withZone(timeZone[, options]);

Optional Chaining

This one is nothing new to the folks that have been doing Typescript, but it’s something that definitely lazy people, like me, will be using a lot. One of the most annoying things is when you have to do that really nasty if:

if (user && user.address && user.address.street) {
 console.log(user.address.street.line1) // it’s safe to log this
}

With optional chaining that’s a thing from the past, here’s the spec btw. So the previous example with optional chaining can be done with:


console.log(user?.address?.street?.line1)

No more TypeError: Cannot read property ‘street’ of undefined 🎉🎉🎉

Nullish Coalescing

Lazy people like me, are going to love this one. Before ES6 there was no way to provide default values for functions params, so a simple solution was using || operator, const c = a || b if a is false then use b. The problem with this approach is that, most of the times you want to use this operator to do this: if a is not defined use b but unfortunately anything that evaluates to false will be treated as false (you don’t say!). So if a has any of these values it will evaluate to false, therefore we will get b:

// a = false;
// a = -12;
// a = '';

That’s what Nullish Coalescing tries to solve, with the new operator ?? only undefined and null will evaluate to false, so on the previous example we would always get a. Here’s more examples:

a = false
b = 'something'
c = a || b //=> 'something'
c = a ?? b //=> false
a = undefined
c = a || b //=> 'something'
c = a ?? b //=> 'something'

You can check the spec here.

Pipeline Operator

Don’t you hate when you have to chain a lot of functions and each function returns the input for the next function? I don’t because I barely do that, but if you are one of the functional programming cool persons, then you are going to love this proposal, it clearly improves readability. Without further ado here’s the spec and an example taken from the spec:

// Some functions that do string operations
function doubleSay (str) {
  return str + ", " + str;
}
function capitalize (str) {
  return str[0].toUpperCase() + str.substring(1);
}
function exclaim (str) {
  return str + '!';
}

// old way
let result = exclaim(capitalize(doubleSay("hello")));
result //=> "Hello, hello!"

// with the new pipeline operator
let result = "hello"
  |> doubleSay
  |> capitalize
  |> exclaim;

result //=> "Hello, hello!"

Partial Application

This one is probably my favourite one in terms of new syntax, it’s a bit confusing to get the grasp of it but I bet that it will lead to all crazy implementations, that we JavaScript developers tend to create. As usual there’s plenty of examples and more in depth explanation on the spec, make sure you check it, there’s a lot of explanation around edge cases and references that I’m not going to cover on the examples.

As the spec explains, we can already achieve partial application by using bind and arrow functions, although bind only works with the leading argument and arrow functions will look too verbose when paired with the previous proposal, the pipeline operator.

The syntax:

f(x, ?) // partial application from left
f(x, …) // partial application from left with rest
f(?, x) // partial application from right
f(…, x) // partial application from right with rest
f(?, x, ?) // partial application for any arg
f(…, x, …) // partial application for any arg with rest

The code:

let addOne
function add(x, y) { return x + y }

addOne = add.bind(null, 1)

addOne = x => add(1, x)

// new syntax
addOne = add(1, ?)

// all of the previous examples are equivalent
addOne(4) //=> 5

function concat(x, y, z) { return x + y + z }

const pad = concat('****', ?, '****')
pad('sup') //=> '****sup****'

const f = (x, ...y) => [x, ...y]
const g = f(?, 1, ...)
g(2, 3, 4); //=> [2, 1, 3, 4]

Realms

What happens if you accidentally load a library that modifies global prototypes, let’s say for example your precious debug tool console.log?

console.log = function() {return ''} // no more debug for you mwahah

Surely there must be a way to restore our precious console.log right? It turns out there is, but using a very convoluted way.

const frame = document.createElement('iframe')
document.body.appendChild(frame)
console = frame.contentWindow.console
console.log('my precious!! it works')

So what has this to do with Realms? Realms don’t try to solve this specific problem, but I think this example helps you understand the reasons behind this proposal. There’s a nice article that plays with realms from iframes written by Jake ArchibaldArrays, Symbols and realms. If you haven’t read it you should check it out. The idea is that Realms are like VM’s or Docker images of the global space, where you can play around in your safe space.

let realm = new Realm();

let outerGlobal = window;
let innerGlobal = realm.global;

let f = realm.evalScript("(function() { return 17 })");

f() === 17 // true

Reflect.getPrototypeOf(f) === outerGlobal.Function.prototype // false
Reflect.getPrototypeOf(f) === innerGlobal.Function.prototype // true

Cool right? The use cases are:

  • security isolation (with synchronous but coarse-grained communication channel)
  • plugins (e.g., spreadsheet functions)
  • in-browser code editors
  • server-side rendering
  • testing/mocking (e.g., jsdom)
  • in-browser transpilation

As usual you can find more info in the spec proposal

Binary AST

As we all know, shipping all this JavaScript with all the libraries and our really great code has a cost. With tools like Lighthouse we can now audit better our web app, there’s nothing frustrating after months of development when you are going to audit for the first time and you get a terrible score.

But, but… I have SSR and code splitting and critical css and I only load pollyfills after checking if they are not supported…

Yeah…. that’s not enough unfortunately. Although everyone is betting all their chips on web assembly, until then we might benefit from this proposal.
Because I’m lazy, I’m going to just quote part of the spec, hope this is enough to pique your interest.

We propose a binary encoding based on an efficient abstract syntax tree representation of JavaScript syntax. This is a new, alternate encoding of the surface syntax, with a fairly close bidirectional mapping to the text representation. We seek to be as conservative as possible in introducing new semantics, which are currently limited to:
deferring early errors
changing Function.prototype.toString behavior
requiring UTF-8
To further speed up parsing, we propose to encode static semantics as implementation hints, and verify them as deferred assertions.
For this AST format, we currently do not propose to automatically derive from the ECMA-262 grammar since it is too verbose to be an efficient tree representation, and as such it would require a lot of flattening and inlining. Additionally, this might restrict the evolution of the JavaScript specification by effectively making the grammar a normative specification of the binary format.
Instead, we propose a separate tree grammar, with annotations on AST nodes that only express information about the syntax. There are several existing tree grammars which we may take as a starting point, such as Babylon or Shift AST.

Wrapping up

Spending my evening listening and talking with TC39’s members allowed me to better understand the reasons that move them. These individuals don’t represent themselves but rather their companies, and something that we tend to forget — all of them are humans as we are, so we can’t expect them to be perfect.

An evening with TC39 in London
was originally published in YLD Blog on Medium.
Share this article: