TIL from WebKit

TIL = “today I learnt”.

Unlike other browser engines, WebKit’s C++ almost reads like JavaScript. As a long time JavaScript programmer, I really appreciate the clarity and simplicity that brings to the project. Just as an arbitrary point of comparison, WebKit’s implementation of Navigator.cpp is ~200 lines of code, compared to Gecko’s, which is ~2000! yep, 10x as much code. As you can imagine, the cognitive load of working on, or reading WebKit code is much less than in other engines.

Other things in WebKit make the code easy to follow and often “programmatically beautiful” and a real delight to work with (e.g., use of “auto” everywhere). The other cool thing is that WebKit doesn’t shy away from using C++ standard library features. Coming from projects that have traditionally shun the use of “std::” things, I often run into cool little things that C++ does that I had no idea about!

These cool little things I hope to document here, as well as other arbitrary language features that were never mentioned while I was learning C++… so I’m always like “wow! I wish I’d learned that sooner”.

Static once flags

You can create static flags (e.g. for cases where “only show or do X once”), so you don’t need to add random members to classes that only get set once.

static std::once_flag onceFlag;
// Just pass a lambda expression to perform some action.
std::call_once(onceFlag, [] {
  // do your thing! 
});

Prefer forward declarations to header files

When dealing just with class related information (e.g., a particular return type), it’s preferable to use a “forward declaration” instead of including a header file. So, with:

#import ExceptionOr.h
class NavigatorGamepad : public Supplement<Navigator> {
public:
  static ExceptionOr<const Vector<RefPtr<Gamepad>>&> getGamepads(Navigator& navigator, Document& document)
}

You would instead drop the header import and do:

template<typename> class ExceptionOr;
class NavigatorGamepad : public Supplement<Navigator> {
public:
  static ExceptionOr<const Vector<RefPtr<Gamepad>>&> getGamepads(Navigator& navigator, Document& document)
}

Put static only declaration (.h) side of a method signature

In case where you need to return some static value (see below), like:

ExceptionOr<const Vector<RefPtr<Gamepad>>&> NavigatorGamepad::getGamepads(Navigator& navigator, Document& document)
{
    if (!document.isFullyActive()) {
        static NeverDestroyed<Vector<RefPtr<Gamepad>>> emptyGamepads;
        return { emptyGamepads.get() };
    }
}

You only put “static” on the method declaration:

static ExceptionOr<const Vector<RefPtr<Gamepad>>&> getGamepads(Navigator&, Document&);

I think (but not 100% sure), it’s telling the declaration to expect a static, and then the implementation actually contains the static being returned (the static NeverDestroyed above).

Argument names are optional in method declarations

For example, instead of:

public:
  static ExceptionOr<const Vector<RefPtr<Gamepad>>&> getGamepads(Navigator& navigator, Document& document);

You can omit the navigator and document argument names:

public:
  static ExceptionOr<const Vector<RefPtr<Gamepad>>&> getGamepads(Navigator&, Document&);