August 27th, 2013
About a month ago, I had a moment of clarity and started converting WebKit code to using references instead of pointers when passing around objects that are known to exist. At first I was just playing around, but it gradually got more serious and other people started chipping in patches too.
Darin suggested I write this blog post to clear up any confusion there might be about why/when to use references, so let’s cut to the chase! There are two main reasons for using e.g
Frame& instead of
Frame*. Reason number one:
It documents that we are referring to an existing Frame object, and that it’s safe to call member functions on it.
Compare this example:
// WebKit in 2012, so gaudy! return m_page->mainFrame()->eventHandler()->mousePressed();
// WebKit in 2013, so fab! return m_page.mainFrame().eventHandler().mousePressed();
In the old version, it’s not clear that
eventHandler() are non-null. In fact, you’d need a pretty good understanding of the WebCore object model to know which pointers could be null and which ones couldn’t. It was typical for functions to be littered with checks like this:
if (!m_page) return false; if (!m_page->mainFrame()) return false; if (!m_page->mainFrame()->eventHandler()) return false;
…which brings me to reason number two:
It exposes unnecessary null checks by turning them into compile errors.
C++ doesn’t let you null check references, so you have no choice but to remove them. This is awesome, because it means smaller and faster code, both binary and source wise. The CPU doesn’t have to spend time checking if the object is really there, and you don’t have to spend time worrying about what to do if it isn’t. Everyone wins!
So when should you be using references?
- If you were going to return a pointer, but you know it will never be null, make it a reference!
- If you take a pointer argument, but you don’t want to handle it being null, make it a reference!
- If your class has a pointer member that never changes after construction, make it a reference!
- BUT if your code has a
RefPtr<Frame>, note that switching to a
Frame&would no longer ref/deref the Frame, which may not be what you want!
My dream is that one day, if I see a
-> or a
*dereference, there will also be a null check in the preceding lines (or a comment explaining why it’s safe to dereference.) This may not be entirely realistic, but let’s see how far we can get.