Best feature ever

Lightly edited.

    <naveed> Hello Jason. Do you have anything to for the platform
             meeting from the past two weeks?
<jorendorff> no, had a crummy couple of weeks i guess
<jorendorff> it's looking better this week, i'm going to land
             iterators for Map and Set, which is the best feature
             basically ever
    <naveed> :) 
    <naveed> why do you feel that way about iterators for Map?
    <naveed> We are tlaking about this right:
             http://wiki.ecmascript.org/doku.php?id=harmony:iterators
<jorendorff> yes
    <naveed> I read it but must admit without using some features
             I may not fully get why they are so great
<jorendorff> it's hard to explain
<jorendorff> iteration is a power tool,
<jorendorff> it's a core part of a language, inasmuch as data
             processing is one of the purposes of programming
<jorendorff> Zipping through a bunch of data efficiently is just
             *so* easy and pleasant in languages like Python and
             Ruby that get these basic data structures and control
             structures right
<jorendorff> they hit the sweet spot.
    <naveed> i do like python language features for this
* naveed doesnt know Ruby
<jorendorff> JS completely and utterly misses the sweet spot, the
             basic data structures basically have never existed,
             Array is kind of a botch and there is no syntax for
             iterating over it
<jorendorff> people use .forEach(), but you can't break out of it
    <naveed> ah true
    <naveed> i have felt that pain before
<jorendorff> people use Object for hash tables
<jorendorff> leading to the occasional bug where you do something
             like,    if (s in obj)
<jorendorff> and it just happens that s == "watch"
<jorendorff> which is the name of a property on all objects in
             Firefox :( 
    <naveed> doh!
<jorendorff> and Firefox only *wince*
<jorendorff> up to now, Map and Set have not really been usable,
             because there's no way to get all the data out.
<jorendorff> there's no .keys() .items() .toArray() anything like
             that.
<jorendorff> with iterability it is trivial to write all those
             methods yourself!
<jorendorff> function keys(map) { return [k for ([k, v] of map)]; }
<jorendorff> function items(map) { return [pair for (pair of map)]; }
    <naveed> ok i get it now
    <naveed> the comparison to Python made it very clear
<jorendorff> ok, that's all i got :) 
<jorendorff> oh!! the best part
<jorendorff> it's going to work with the DOM too, we're making the
             DOM iterable :)  :)  :)  :) 
<jorendorff> JS is going to be so much better
    <naveed> oh that is awesome
    <naveed> DOM standard?
<jorendorff> working on it :) 
    <naveed> that will make many things much cleaner
<jorendorff> the relevant patch is r?bz, he can point out any
             problems
    <naveed> 725907 (--/normal): Change for-of loop to work in
             terms of .iterator() and .next()
<jorendorff> that's the one.
    <naveed> now you have me excited !
    <naveed> Thank you for the context
<jorendorff> :) 
<jorendorff> mind if I just blit this conversation to my blog?
    <naveed> of course not

I can’t promise these changes will really land this week; they are pending code review in bug 725907, bug 743107, and bug 725909.

I really think this one cluster of new features coming to JavaScript (for-of loops, iterators, generators, Map, and Set) is more important than almost anyone appreciates. But anyone who has used Python or Ruby already knows how important this is—subconsciously.

The syntax for Map and Set is not as sweet in ES6 as it is in Python and Ruby. We’ll see if the new features hit the sweet spot. So far I have a bit of experience with them, just writing unit tests. They feel pretty darn good.

Rest arguments and default arguments in JavaScript

In the last two weeks, Benjamin Peterson has implemented two new features in the JavaScript engine. You want to know about these. If you write a lot of JS, they will make your life better.

Rest arguments are a nicer substitute for the familiar arguments object. The syntax looks like this:

function f(arg1, arg2, ...rest) {
    alert("You passed " + rest.length + " extra arguments.");
}

This works just like rest-arguments in Python, Lisp, and Ruby. Each time you call f, the first few arguments are assigned to the ordinary arguments, in this case arg1 and arg2. Any extra arguments you pass are stored in an array, rest. If you don’t pass any extra arguments, rest is an empty array.

Unlike the arguments object, a rest-argument is a real Array. It has all the Array methods, including .shift(), .forEach(), and .map(). And unlike arguments, which is re-defined in each nested function whether you want it or not, a rest-argument works exactly as expected in a closure.

Default arguments look like this:

function fade(element, seconds=0.5, targetOpacity=0) {
    $(element).animate({opacity: targetOpacity}, seconds * 1000);
}

When you call this function, if you omit the arguments that have default values, they’ll get the default values.

fade(form, 0.2, 1);  // default values are not used:
                     // fade in fast
fade(form, 3);       // targetOpacity defaults to 0:
                     // fade out very slowly
fade(form);          // seconds defaults to 0.5,
                     // targetOpacity defaults to 0:
                     // fade out at normal speed

The default value can be any expression. It can use the values of preceding arguments, as in

function logEvent(event, logger=findLoggerFor(event.target)) {
    ...
}

where the default value of logger depends on the event argument.

(Extreme technical details: Note that unlike Python, the default value is computed each time the function is called, so if an argument has =[], it gets a fresh empty Array each time. Also, note that currently you only get the default value if the caller actually leaves off the argument. If the caller explicitly passes undefined, the argument’s value is undefined and the default is ignored. But there is some discussion on the committee about maybe changing that so that the default is also used when the caller explicitly passes undefined. Other programming languages don’t do this, but it would fit with what the DOM already does in many cases. Right now we follow the current proposal; if the proposal changes, we’ll update our implementation.)

Both of these new features are on track to become part of the next ECMAScript standard.

Benjamin is still going strong. There’s more to come.

Screencast: Debugger in Scratchpad

This screencast shows how to make the JavaScript engine your plaything in just 3 lines of code.

And if you haven’t seen Scratchpad yet, prepare to fall in love with programming all over again.

After that you might want to see Jim’s talk about what it looks like when JS code runs. This talk explains beautifully why the Debugger object API is the way it is (sorry about the echo-y audio, we want to reshoot this but haven’t gotten to it yet):

Loupe

Paul Rouget wanted a tool for closely examining the UI design he was
working on. So he made it. It’s called Loupe. It puts a little
magnifying glass in your location bar:

When you click it, you get this:

You can look at a design up-close, see if the gap between two boxes is 3 pixels or 4, that sort of thing. You can grab colors, too.

I want to talk about how this tool was made. The whole thing is a single JavaScript file. Paul built it using Scratchpad. The first prototype took about 2 hours to make. Then Paul shared it using Gist.

WARNING: The following pref is off by default for security reasons. Setting it gives Scratchpad code full control over Firefox—your passwords, history, everything. Also, even if someone claiming to be me says it’s OK, please don’t copy and run code you see on the Web. That said, if you did want to check out Loupe, you would go to about:config, set devtools.chrome.enabled to true, select Tools → Web Developer → Scratchpad, select Environment → Browser, and then run Paul’s code. It’s not like I can stop you.

To me this is really exciting. Scratchpad is low-tech in the best way.

Harmony modules and asynchronous script loading and document.write (oh my)

This is my first post about Harmony modules. I hate to start right out of the gate with a long boring post about timing details, but it seems the few people who might eventually be interested in it are actually interested right now! So let’s dive in.

Once we have modules, running a script will sometimes hit the network.

    <script>
        module blottr from "blottr.js";
    </script>

(By the way: you will have to opt in to Harmony syntax somehow—yet to be determined. This post will ignore that consideration.)

When the HTML parser reaches this script, parsing will pause until “blottr.js” is loaded. This matters if “blottr.js” touches the DOM during its initialization, for example. In terms of timing, it behaves just like a <script src=> element.

(As a performance optimization, we plan to change the HTML5 parser to skim ahead, find probable module statements, and pre-fetch the scripts. Again, just like <script src=>.)

But what about this?

    function silly() {
        eval('module blottr from "blottr.js";');
    }

What should happen if silly() is called from an event handler? Should it block until “blottr.js” comes in from the network? That would be a synchronous, blocking call, like synchronous XHR.

That would be gross. So in Harmony, eval will reject such code with a SyntaxError. In short, if a JavaScript caller is waiting, the module X from "url" syntax is banned. If your code needs a module off the network, you’ll just have to run it asynchronously somehow. Two new APIs, SystemLoader.load(urlcallback, errorCallback) and SystemLoader.asyncEval(code, callback, errorCallback), are proposed for that.

Now. Suppose we take the first example above and put it in a document.write call.

    <script>
        document.write(
            '<script>' +
            '    module blottr from "blottr.js";' +
            '</scr' + 'ipt>');
    </script>

Now what happens? (Benjamin Smedberg brought this case to my attention about 12 seconds after I described modules to him. It might have been less.)

To me, this particular flavor of document.write() weirdness was something new. I’m still not totally sure how we will handle it. Boris Zbarsky suggested again treating it the same as a <script src=> element: silently make that script load asynchronously, just because document.write() created it. That sounds plausible enough.

There are still a few more special cases to sort through. What happens if you try to load a module by assigning a string to an event handler attribute of a DOM element? I’m not sure yet. Perhaps we will throw a SyntaxError.

Bored to tears? Sorry! I’ll write again in a few days, explaining what Harmony modules are, who’s working on them, and why.

Why fast reviews happen

Back in April, Jim Blandy and I started hacking on a little project in a user repo.

Last Wednesday, without warning, I posted the results of three months of work for review in bug 672829. The whole patch is 336KB (actually 534KB, if you count tests), so I split it up into sections and requested code reviews from eight different JS hackers.

The first review came in before I was even done posting all the patches.

That afternoon, I sent a brief e-mail to the JS team asking for help getting the reviews done quickly. That was the only thing I did that I wouldn’t normally do. By noon Friday, just 48 hours later, twelve of the thirteen reviews had been granted, and Brendan was about halfway through the thirteenth.

The reviewers were:

David Anderson
Andrew Drake
Brendan Eich
Andreas Gal
Blake Kaplan
Bill McCloskey
Luke Wagner
Jeff Walden

Thanks, guys.

The best part: this is no fluke or one-off effort. It’s like this every day in js/src. How did this happen? Why do you get faster code reviews in the JavaScript engine than anywhere else in the project?

I really don’t know, but I have some guesses. Brendan Eich was the module owner for many years, and he always turned reviews around lightning-fast—and not by skimming, either, as you know if you’ve ever read a /be review. (You can read a totally typical one in this bug.) I think Rob Sayre probably had an influence as well. Maybe when you run a team with that “hey, are we all acting like adults here, and if not, why not” attitude for a few years, you get a culture of fast reviews.

Whatever the reason, I’m grateful. Fast reviews make me more effective. Some days, they make my job really exciting.

A Happy Family of C++ Classes

Luke refactored a bunch of code into js/src/vm/Stack.h. In a comment on the JS engine internals group, he wrote (emphasis mine):

David and Waldo raised the very reasonable question of whether js::StackFrame should be in its own file rather than in vm/Stack.h (its big). My reasoning for not wanting to is that FrameRegs + StackFrame + StackSegment + StackSpace + *FrameGuard altogether form a single logical data structure which I’d like to present as a whole [...] The same perspective shows up in math as many-sorted algebra so its not just C++ crazy-talk :)

None of us could figure out what that last sentence meant. We prevailed upon Luke to elaborate. I thought his explanation was a nice insight, so I’m sharing it here.

I’ll hazard an answer, knowing full well that there are at least three PhDs on the list who know a lot more about this than I do and may smite my answer with truth. (I’m at a layover in Hong Kong — be gentle :)

A single-sorted algebraic “structure” is something like a monoid, group, ring, field, etc: an abstract domain with a collection of operations (over this domain) and axioms that the operations must satisfy (e.g., distributivity, associativity, commutativity, etc). A single-sorted “algebra” implements a structure by picking a particular domain and set of operations that satisfy the axioms of the structure. (For example, the ring structure specifies an abstract + and * with a couple of axioms (associativity of +, distributivity, inverse for + and *, etc); the integers with arithmetic + and * are an algebra).

An important idea about all this is that, when you prove things about an algebraic structure, the proof is expressed only in terms of the declared operations/axioms of the structure, and not the particular details of any one algebra, so your theorem holds for all algebras of that structure. Now this starts to sound like abstract data types in computer science (s/structure/public interface/, s/axioms/specification/, s/algebra/concrete class/) and we can see that abstract algebraists are kinda like programmers who really really like reusable code.

A many-sorted structure/algebra is just the extension of the concept that can have more than one domain (thus, the operations can include more than one domain in their signature). An example is a vector space (which has a domain of scalars and a domain of vectors).

So then what’s the correspondence of these multi-sorted structures/algebras in programming? Classes/interfaces (of mainstream OOP languages) associate all operations with a single domain of values. I have little doubt there exist languages which solve the problem directly. We can hack multi-sorted-ness in C++ while maintaining some semblance of interface/implementation separation by just having multiple classes (one per domain) and making them all friends of each other. Then there is the question as to how to distribute the operations between the classes (or perhaps as non-member functions), but unless you want runtime polymorphism (which requires something like multi-methods), it’s a question of aesthetics.

I mentioned this originally because recognizing many-sorted algebras as a peer concept to single-sorted algebras helps to avoid a design mindset of “every class must be its own encapsulated island” which I feel can be detrimental when trying to modularize complex data structures like we have in SpiderMonkey. The Stack was one example; I think low-level objects + property tree will be another.

How to fix a bug, episode 434494, part 2

At the end of part 1, Cameron McCormack had just tracked bug 434494 down to two .focus() calls in browser.js. It was a race condition: whichever .focus() call happened to run last got to keep the focus.

You might have wondered why these calls were happening in a random order to begin with. As we’ll see, Cameron was able to fix the bug without investigating this! But I’ll talk a little bit about it because it’s interesting, and it can bite ordinary web pages, too.

Opening files is a very common cause of non-determinism. You call a function like window.open() or XMLHttpRequest().open to make it happen, and the call returns right away, even though the document hasn’t finished loading yet, so the application can remain responsive. The system will send a load event later, when it’s done. Because loading a file takes a small but somewhat random amount of time, the order of that load event compared to other events can be slightly random.

The root cause of bug 434494 is indeed the timing of load events. But Cameron found a way to fix the bug without having to track down the root cause, as we’ll see—after a little detour…

       <heycam> ok, so we know we have these two focus calls running in either
                order
   <jorendorff> hang on
   <jorendorff> I've got a Firefox 4 nightly on my Mac. So I suppose I have a
                browser.js in here somewhere.
   <jorendorff> One hesitates to encourage people to edit their browser app
       <heycam> ah yes, if you want to try it
       <heycam> heh
   <jorendorff> but just for my entertainment...
   <jorendorff> I can just throw an alert() in here?
       <heycam> I don't know how well it works to just edit the browser.js in
                whatever jar it lives in
       <heycam> it might work
       <heycam> I tended to just do a rebuild
   <jorendorff> you edited the source file?
       <heycam> yeah
       <heycam> then make, as usual
       <heycam> but probably editing browser.js in situ is fine
   <jorendorff> ...What about a chrome debugger? Ever use one of those?
       <heycam> no, well only just yesterday
   <jorendorff> heh
   <jorendorff> let's try editing it in place ;) 
       <heycam> ok :) 
   <jorendorff>  /Applications/Nightly.app/Contents/MacOS/
   <jorendorff> omni.jar
       <heycam> I'm guessing so
   <jorendorff> chrome/browser/content/browser/browser.js
   <jorendorff> now to see if Emacs will let me edit this file in the middle
                of a jar
   <jorendorff> gosh, I think it will
       <heycam> would surprise me if it didn't ;) 

If you’re on Mac or Linux, and you have Emacs, go ahead and find omni.jar in your Firefox installation directory, make yourself a nice backup copy, and poke around inside. If you like, you can make the exact change I made. Search the archive for browser.js, open it, then search for BrowserSearch_webSearch. Add an alert, like so:

in situ, as they say in auckland

Save it… and…

   <jorendorff> restarting... *fingers crossed*
   <jorendorff> hmm, no good.

It didn’t work. But are we discouraged? We are not. Later I asked about this on irc.mozilla.org, and I found out that you can force Firefox to read omni.jar again by passing the right command-line flag. First make sure Firefox is closed. Then:

  $ cd /Applications/Nightly.app/Contents/MacOS
  $ ./firefox --purgecaches

If you’re on Mac OS 10.5, you need to use a slightly different command to start Firefox:

  $ arch -i386 ./firefox-bin --purgecaches

And of course if you are using the official Firefox 4 instead of the unstable Nightly, you’ll find the file under /Applications/Firefox.app instead.

Then, when you hit Cmd+K:

achievement unlocked: hack

You might want to put your original omni.jar back when you’re done. Software updates run a bit more smoothly when you haven’t been manually editing the programs. :)

Back to the bug:

   <jorendorff> so did you manage to convince yourself that this is what was
                happening by using alerts?
       <heycam> yes
       <heycam> alerting what the currently focused element was, at the time
                of the gURLBar.focus call
       <heycam> my thought was, not knowing anything about the random
                ordering, to ensure that the gURLBar isn't focused if we'd
                already done the search bar focusing
       <heycam> so I made an assumption, which I verified
       <heycam> that I could tell whether something had been focused already,
                by seeing if commandDispatcher.focusedElement was null
   <jorendorff> ah
       <heycam> alerting just before gURLBar.focus is called, in say a
                Cmd+N new window, showed me that focusedElement was null

This led to Cameron’s first patch for the problem. He wrapped the code that calls gURLBar.focus() in an if block, so that it only happens if we haven’t already focused something else. You can see those changes here. (The left side shows the code before the fix; the right side is how it looks after the fix. Incidentally you can find that page yourself by visiting bug 434494, then clicking “Show obsolete patches”, then clicking on the word “Diff” next to the first patch.)

   <jorendorff> the first part, i see the if statement you added
   <jorendorff> but what is that second change?
       <heycam> see the comment above the setTimeout 0 call
       <heycam> clearly it's trying to do something to avoid the url bar focus
   <jorendorff> oh
   <jorendorff> heh - yeah, it looks like someone thought they fixed this
                before. :) 
       <heycam> initially I only wrote the first hunk, and that worked.
   <jorendorff> That being done, the old setTimeout hack wasn't needed
                anymore, so you ripped it out.
       <heycam> exactly
       <heycam> there's no point in delaying the webSearch call in the
                setTimeout

The second half of the patch was just a little code cleanup.

Now Cameron had a working fix. He posted it in Bugzilla and requested a code review from Gavin Sharp, a long-time Firefox hacker who’s an expert in this area of the code. Gavin lives in Toronto.

Code reviews are interesting. You almost always learn something.

   <jorendorff> It looks like you spoke with gavin about this first patch
   <jorendorff> and you decided to make a few changes based on that.
       <heycam> yes
   <jorendorff> I don't suppose you have that chatlog...?
       <heycam> I do, hang on

Here is what Gavin said…

            <gavin> hm, that patch seems to be relying on the ordering of the load events
           <heycam> how's that?
            <gavin> and I'm not sure that it's safe to assume that focusedElement will be null on initial load
            <gavin> BrowserStartup runs off a load event
            <gavin> so does BrowserSearch.webSearch, with your change
           <heycam> I see
           <heycam> is there something I can listen for once the browser startup is done?
            <gavin> not at the moment
           <heycam> or maybe a way I could pass an argument into the browser
           <heycam> rather than listening for an event
            <gavin> oh, I lied
            <gavin> you could use browser-delayed-startup-finished
            <gavin> slightly messy because it's an observer notification, but doable
           <heycam> ok
           <heycam> I'll try that and post another patch. thanks!

Depending on .focusedElement was too iffy. Gavin suggested a different approach, which led Cameron to make a second version of the patch.

   <jorendorff> gavin left some new comments in the bug :) 
       <heycam> yes, I plan to get to them today :) 

Since my chat with Cameron last week, he posted a third version, which now bears Gavin’s seal of approval. It might be checked in by the time you read this. Sweet!

the plus means quality
       <heycam> the one hiccup was the time between my posting the original
                patch, and getting comments from gavin
   <jorendorff> Was that due to the Firefox 4 crunch?
       <heycam> probably. gavin also seems to have a long request queue.
       <heycam> so a week ago I pinged him on email
   <jorendorff> ah

So I glossed over something: the three months between Cameron’s first patch and his chat with Gavin.

I hate to admit it, but I still have review requests from that era too. Firefox 4 was in beta, monopolizing developers’ time, for months. A lot of valuable work got put on hold. We’re never doing that again, thank goodness.

But sometimes a code review gets lost in the shuffle anyway. If yours takes more than a few days, it’s important to speak up:

       <heycam> although I'm usually hesitant to prod people
       <heycam> but that mail got swallowed :( 
       <heycam> so I pinged him on irc yesterday to ask him about it
       <heycam> in general I have no idea how long I should be letting my
                patches sit in someones queue before bugging them about it :) 
   <jorendorff> At least 3 days. But never 2 weeks.
       <heycam> I think that aspect of the process should be emphasised to new
                contributors
       <heycam> getting review, expectations of turnaround time
   <jorendorff> As long as you're super nice about it, a reminder is usually
                welcome, in my experience
       <heycam> ok

So this is what open source development is like. There is some stuff that looks like work, stuff that takes multiple tries, delays and waiting. There are also cool things to tinker with, puzzles waiting to be solved, useful skills to learn, and smart people around the world who would love to help you.

Don’t be shy.

How to fix a bug, episode 434494, part 1

This is a true story about fixing a bug.

In this story, we’ll see that a bunch of the Firefox UI is written in JavaScript. We’ll do something extremely inadvisable but sort of cool. And we’ll hit on one of the key life lessons of open source development.

 


 

Our hero is New Zealand-based Mozilla hacker Cameron McCormack. Cameron knew about this bug in the first place because someone (Marco De Vitis, to be specific) took the time to report it at bugzilla.mozilla.org. It’s bug 434494.

I chatted with Cameron about the bug and what happened next.

   <jorendorff> So this bug is about what happens when you have no windows open
                and you hit Cmd+K
       <heycam> right
   <jorendorff> which I guess only really happens on the mac, right?
       <heycam> yeah
       <heycam> where closing all the browser windows doesn't quit the app

It’s normal on the Mac for an application to stay open when its last window is closed. So in Firefox on the Mac, if you close all your tabs, Firefox is still there, and you can open a new browser window from the menu or by using a keyboard shortcut. Cmd+K is the shortcut for the search bar.

   <jorendorff> OK. So Cmd+K creates a new window in that case, and the bug
                was, sometimes it would focus the search box as desired,
                sometimes the location bar instead.
(picture of a new browser window with the location bar focused)
omg firefox, what part of cmd+K did you not understand
   <jorendorff> how did you track it down?
       <heycam> I *think* I searched for where the location bar got its focus,
                first

(Cameron doesn’t remember clearly because it was a month or two ago. More about that in part 2.)

       <heycam> ok
       <heycam> http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#1485
       <heycam> so that's the only line that focuses the url bar
       <heycam> (it seems)
   <jorendorff> aha

I clicked the link and there was browser.js: nine thousand lines of JavaScript code that implement a lot of the UI around the edges of your browser window.

(a bunch of browser.js source code)
so that is what the tubes look like

Well there you go. Focus the URL bar. There’s your bug, right?

But this can’t be the whole story, because in other circumstances, Cmd+K works. Somewhere there must be code for focusing the search bar that isn’t being called or isn’t working properly in this case. Cameron had no idea where that code might be.

So he went to mxr.mozilla.org and searched for it.

(mxr.mozilla.org search results for 'Cmd+K')
only two hits for cmd+K
       <heycam> that's right
       <heycam> there's a file that has a whole bunch of keyboard mappings to
                actions
       <heycam> something.inc
       <heycam> browser-sets.inc
   <jorendorff> http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser-sets.inc
       <heycam> yeah
       <heycam> I still have no idea how all the xul things fit together
       <heycam> but having found this file, I could see that it associates
                Cmd+K with a "command"
       <heycam> Tools:Search
       <heycam> http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser-sets.inc#230
(some source code from browser-sets.inc where the Cmd+K keyboard shortcut is defined)
hipster caption writer says xml is not retro yet, still just uggs
       <heycam> and then my thinking is "what defines commands"
       <heycam> so I'd grep that directory for Tools:Search
       <heycam> $ cd browser/base/content
       <heycam> $ grep Tools:Search *
       <heycam> browser-menubar.inc: command="Tools:Search"/>
       <heycam> browser-sets.inc:    <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
       <heycam> browser-sets.inc:    <key id="key_search" key="&searchFocus.commandkey;" command="Tools:Search" modifiers="accel"/>
       <heycam> browser-sets.inc:    <key id="key_search2" key="&findOnCmd.commandkey;" command="Tools:Search" modifiers="accel,alt"/>
       <heycam> browser-sets.inc:    <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
       <heycam> that <command> element looks right
       <heycam> that gets us to the webSearch function in browser.js

Cameron saw oncommand="BrowserSearch.webSearch()", guessed correctly that it was a snippet of JavaScript, and with a bit more searching, tracked down the webSearch function. It also lives in browser.js, it turns out.

   <jorendorff> so now we know two things
   <jorendorff> We know where focusing on the search bar is supposed to happen
                (and roughly what pointers the system is chasing to get from
                Cmd+K to this JS function)
   <jorendorff> we also know there's some other code in browser.js that
                focuses on the url bar.
       <heycam> right
   <jorendorff> and the hunch is then "i bet both are happening"?
       <heycam> both are happening, but in an order that's not fixed
   <jorendorff> now what?
       <heycam> I may have put some debugging code in to make sure that both
                are running, not sure
       <heycam> like an alert or something
   <jorendorff> That was the next thing I was going to ask about.
       <heycam> without knowing how chrome js works, it's hard to know how to
                even do simple printf debugging
   <jorendorff> Of course anybody reading this--certainly if they happen to be
                running Firefox 4 on mac -- would like to watch this happening
       <heycam> yeah

Would you? Maybe we’ll do that in part 2. :)

       <heycam> will you be making a guided tutorial to fixing this bug?
   <jorendorff> Weelll, It depends on how much time I end up with :-\
       <heycam> I think UI stuff is a great place for new people to start
                working on, because it's very immediate
       <heycam> and you can see if things are working or not
   <jorendorff> i agree!
       <heycam> but, there's an awful lot of complexity in there
   <jorendorff> well, that's how it is
       <heycam> undocumented too :) 
   <jorendorff> but what you're showing people is how to ignore things rather
                than get overwhelmed
   <jorendorff> this is valuable
       <heycam> yeah, I think that's the key
       <heycam> ignoring things, plowing on
       <heycam> and if you miss important things, others will let you know
       <heycam> that's how I try to approach areas I'm unfamiliar with
       <heycam> I'll have a bash at it, post it for review, and learn what
                things I didn't know from review comments :) 
   <jorendorff> as in this case :) 
       <heycam> yeah
   <jorendorff> but that gets ahead of the story

We’ll get there in part 2.

Now about that life lesson.

You probably noticed Cameron has been tracking down the problem by randomly searching the code for words that might be relevant. This might not seem worth documenting. In fact it may seem a little embarrassing—you mean he didn’t know the code well enough to figure out where the bug was using only his enormous brain? But this is exactly what I think is most important about this story. What Cameron is doing requires some programming chops, and it requires the ability to navigate undocumented monster-infested waters—but it’s not magic.

You could do this.

Maybe you are not an expert in everything. Maybe (like me) you’re a shy person working in a complicated world with incomplete knowledge. How can you function like that? How do you know if you have anything to contribute? How can you get involved in new things?

Step 1: Don’t panic.

Step 2:

  • search for the answer
  • try something and see what happens
  • ask someone

To be continued.

Update: Part 2 is up.

Wanted: An extension for profiling Firefox

Firefox needs an extension that can produce very high-level performance profiling numbers with only casual effort.

We often get bug reports that say “Firefox is painfully slow on site X”. It takes rather a lot of effort just to direct this kind of bug to the right person, because it’s usually not immediately clear why the site is so slow. It would be awfully nice to be able to load a page and see not only how much time Firefox spends waiting for the network (something Firebug can already do) but also how much time we spend doing style resolution, reflow, frame construction, garbage collection, compiling JavaScript, running JavaScript, and so on. Even Boris Zbarsky, who’s probably as comfortable using a profiler as anyone I work with, says such an extension would save him time.

On Mac, you could get this information using dtrace. If you’re a programmer, you have a Mac, and you’re interested in a fun side project, please get in touch with Boris or me.