This presentation is also meant to be a resource that you can consult later. So I will be running pretty quickly through things like the new APIs, because they're not really that interesting to talk about; but you can go back and read them later and click through the links.
Part One. What's new for GNOME 40 and the soon-to-be-released GNOME 41?
Crash fixes! By the way, I'll use these little circled 40 and 41 icons to show things that you can expect to see in GNOME 40 and 41. And I'll doff my hat icon to the person who contributed it. First of all, we have fixed just as many crashing bugs as were reported in the past year. Although that means we have the same number as we started out with, most of them are new. Marco did several refactors for GNOME 40 that increased type safety in the codebase with C++ features. I've done a few as well. These are not specifically crash fixes, but they decrease the likelihood that there are yet undiscovered crashes lurking in there.
Marco has also worked on a pair of pull requests, which should be ready to merge in time for GNOME 41, which not only increase type safety, but also reduce the amount of memory taken by introspected objects and functions. It's a savings of a few bytes per object, but when you have ten-thousands of objects alive in GNOME Shell, it actually makes a difference.
Here are the ways that ES modules might not be straightforward to port from non-module source code. ES modules are always automatically in strict mode, so there may be some incompatibilities there. However, a lot of the strict mode errors are already discouraged by linters. The bodies of ES classes are also automatically in strict mode, and I'm not aware of much breakage due to that. But the one instance that I personally did see was obscure, so this is something to keep in the back of your mind if you start using ES modules and you see an obscure error. The other thing that you may have to take care to do differently is conditional imports. Unlike the legacy module system, resolving imports happens at compile time, not run time, so import statements are only legal at the top level. If you need to import something conditionally, use the built-in dynamic import function. This function is asynchronous, so it returns a Promise that needs to be await-ed. That means you'll have to refactor your code somewhat.
Next major improvement in GNOME 40 on my list to talk about, is the work of Nasah, GJS's Outreachy intern from the December 2020 round. Look for her lightning talk in the intern lightning talk session on Friday at 1500 hours UTC! We've gotten several improvements to make the debugger more useful for debugging. The original debugger was quite basic. It had a backtrace command of course, but now it has a backtrace full option just like GDB, which prints all the information about the local variables in the stack frame. It also now has access to the source code, so there is a list command that also works like GDB, and when you show a frame it also shows the line of source code that goes along with it. I'll show you an example of what this looks like.
Here's a sample program to debug...
...and here's a demonstration of the new features. For the backtrace, you can see the value of the local variable `d`. The program listing can even highlight the current line, depending on the value of an option, although that's not visible here because I couldn't get it to highlight in a plain text markdown block.
Another project from Evan is to provide an implementation of the console specification. Like TextEncoder, this is another web API which is also implemented by NodeJS and it can be useful for sharing code. Most people know console.log but there are a bunch of other functions in the console namespace as well that can be useful. With a bit of luck, we can land this for GNOME 41.
Finally I want to give a special shout out to the Extensions Rebooted initiative which apart from all the other work they've been doing that's important for the GNOME Desktop, have also been gradually improving the documentation of GJS.
That was a selection of some of the exciting new things that we either have already or will get soon. Now for Part Two. What are the exciting things that we should be able to see in the upcoming year in GNOME 42, or possibly 43?
First off I'd like to talk about the work of Veena, GJS's Outreachy intern from the May 2021 round. She will also be giving a lightning talk about this, so if you want to know more, here's another reminder to go see the intern lightning talk session on Friday at 1500 hours UTC! Veena is working on adding annotations to gobject-introspection, such as finish-func and sync-func, that allow us to tie together these pairs of functions automatically. Previously we had to tie together these functions manually with Gio.promisify, in order to use async style programming. In the future, we'll be able to leave that out, like it shows here in the commented out code. Promisify was the work of Avi, our Outreachy intern from 2018, and I'm excited that it's being continued. The annotations are getting near to being ready in gobject-introspection. The corresponding changes in GJS are a stretch goal for the internship, so those may happen for GNOME 41 or later.
We get the at() method for arrays and strings, which lets you do nicer indexing, passing -1 to get the last item, and so forth. So you don't have to calculate the length and risk off-by-one errors.
Last year we got Promise.all(), which waits until all of its sub-promises have resolved. Now we also get Promise.any(), which is kind of the opposite. It waits for any one of the sub-promises to succeed, and then resolves with that promise's value, ignoring the resolutions of the remaining promises. That sounds complicated, but this example might make it clearer. This sample code sends requests to two servers EAST and WEST, and resolves the promise with whichever server responds faster. But if neither server responds within 30 seconds, it'll give up. It's different from Promise.race(), where the promise resolves with the first sub-promise's resolution, even if that's a failure. In this example, Promise.race() wouldn't be the right thing to use, because if checkServer EAST was offline and returned an error quickly, then we'd get that error as the result of the promise, ignoring the result from checkServer WEST even though WEST might still be online.
We also get a bunch of new operators, that can be used to assign default values to a variable. They short-circuit, so the right hand side is not evaluated if the left-hand side already determines that the assignment doesn't take place.
Part Three. Want more exciting stuff to happen? Here's how we could use your help!
First-time app and extension writers often copy code in order to get started quickly, and this is a perfectly normal thing to do! That's part of what free software is all about: the freedom to study software. So we should have good code and good practices available for people to learn from. I made some improvements recently on updating the GJS sample app, since some Outreachy applicants were running into problems with it being outdated this year. Also for my talk at the Linux Application Summit I made a somewhat more complicated sample app that integrates some tools from the NodeJS ecosystem, just to see if that was possible, and maybe some of these should become best practices as well. Evan is also exploring the integration between GJS and TypeScript and he is planning a Birds-of-a-Feather session on this topic on Friday at 1610 hours UTC. If you've started using GJS and you find something that is confusing, or a bad example, come talk to us in our Matrix channel. The thing you're asking about may or may not be a mistake or a bug, but usually there's at least a good answer to the question "where would have been a good place for you to find this information?" that will move things forward for the next person to have the same question.
On that note, I'd like to end by acknowledging everyone who helped in any way with GJS in GNOME 40 and 41! Here's the license; you may reuse bits of this presentation as-is, with attribution, and not for commercial use. Now it's time for...