“Why are you doing this?”

One of the hardest questions for me to answer is, “Why are you doing
this?”
It’s also an excellent question, one that checks what I am
working on. I recently found myself asking this question when trying to use
something I’ve never tried to use before: weak references to DOM elements.

What are weak references?

For those of you coming from JavaScript-land, you know that once you hold
a DOM element as a property, it will last as long as the object you attached
that property to. (Depending on the usage, longer.) This is because XPConnect
generates a “strong” reference to the element, which through the magic of
XPCOM reference counting, requires the element not be deleted until all
strong references are gone – including yours. Weak references are different.
They are objects which hold a pointer to your real target, but they don’t
require the real target “stay alive”. In JavaScript pseudo-code, it looks a
little like this:

function getWeakReference(obj) {
var weakPtr = {
_realPtr: obj,
QueryReferent: function(aIID)
{
if (this._realPtr)
return this._realPtr.QueryInterface(aIID);
return null;
},
QueryInterface: function(aIID)
{
if (aIID.equals(Components.interfaces.nsIWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
return weakPtr;
}

There’s one thing this code can’t show you: Some time in the future,
weakPtr._realPtr could be destroyed, and set to null. That
doesn’t happen in normal code (thank heaven!). But with weak references, it
can happen at any time.

Why are you doing this?

There’s a long list of sub-projects and sub-sub-projects, etc., each of
which seems to require I look at something I hadn’t tried yet. Here’s the
current list, and how I started thinking (wrongly) I needed weak
references.

(Continued on the next page…)

  1. Existing XML and HTML editors do a fraction of “what I want to do”, and
    they’re not easy to extend to meet my vision. So I’m building my own
    extensible editor, Verbosio. That way, others can extend it any way they
    want. This is the classic “Scratch an itch” answer,
    especially since I think it would be really, really useful to others.
  2. One of these “What I want to do” items is is to take a template and
    build XML markup from it – say, a XUL grid from a grid template. So I
    need to write a language to define templates.
  3. Crafting a new language isn’t enough – you need a
    specification, an implementation, and test
    cases
    . These three verify that the markup templates
    language works, and the test cases become real examples of how to use the
    language. (Note: This paragraph deserves its own blog entry – you really
    do need a spec, implementation and test cases!)
  4. One key test of the template language is the ability to build a
    template. No templates in this language exist (it’s a brand new
    language), so no one (including me) can know how to write one without
    some help. Therefore, I need to write a tool to guide template
    construction
    in a separate XUL wizard window.
  5. In building templates, the user can copy, paste and edit in place the
    same basic code. (For example, you could have a template for ordered
    lists
    like this one, and each item would be a copy of basic list
    item
    elements.) It would be a key part of this template to mark
    fragments of code as “repeatable”, and provide controls for
    copying and pasting
    these fragments.
  6. A template author also wants to define minimum and maximum
    numbers of copies
    for the repeatable fragments, so my template
    construction wizard should support that.
  7. Updating a repeatable fragment’s minimum copy count requires
    its own specification, implementation and test cases
    . I
    struggled with this for months, until I thought of XUL’s
    broadcast/observer model.
  8. The broadcast/observer model is good, but the implementation isn’t
    flexible enough. I need to get and set both JavaScript properties
    and XML attributes
    . So I decided to re-implement the model with
    XML attributes.
  9. Observing attributes, setting properties and setting attributes are all
    trivial. However, observing properties directly on DOM elements isn’t.
    They don’t support Object.prototype.watch, which means I need to find
    some other way to detect changes. The simplest I can think of is
    timer-based observations of properties of the DOM
    elements, comparing previous values to current ones.
  10. This requires the timed observers ask the element for properties, but
    we don’t want the observers to keep the element around after the element
    would otherwise die. A strong reference keeps the element from dying.
    Therefore, timed observers should hold weak references to the
    element
    .
  11. I tried using Components.utils.getWeakReference(), but that quickly led
    to a crash. At Boris Zbarsky’s suggestion, I then tried the element’s
    GetWeakReference() method, which returns a nsIWeakReference
    object. Unfortunately, I didn’t see many examples of
    nsIWeakReference in use, so I figured I needed to
    write a testcase for nsIWeakReference objects from
    elements
    .
  12. In writing the XPCShell testcase, I found that DOM elements from the
    test weren’t being deleted (resulting in a nsIWeakReference
    object without a real element pointer). Forcing JavaScript garbage
    collection didn’t fix that, as this was a XPCOM cycle collector task.
    There’s also (currently) no obvious way to force XPCOM cycle collection
    from XPCShell, so I realized I needed to add XPCOM cycle
    collection to Components.utils
    .
  13. At which point I realized I couldn’t visualize the chain from “write a
    language to define templates” to “writing a testcase for
    nsIWeakReference”. It was just too much for me to see the connections. I
    asked myself, Why am I doing all this?

Hence why I started writing this blog article, to analyze my own planning
and determine if I really needed to do all the steps. In writing this, I
realized that I’d made an error in my logic. Everything from item 4 onward
takes place in a separate DOM window, in a wizard. That means the template,
the template editing code, the repeated XML fragments, the broadcast/observer
code, all of it, would not live very long. After the user finished
their work with the template, all these pieces of code would be inaccessible
to the user and to other components, and XPCOM cycle collection would
presumably clean them up.

Individually, each step in the list leads logically to the next one. Taken
as a complete picture, step 10 makes an incorrect statement, and nothing
after it matters. Timed observers do NOT need to hold weak references to the
element, since neither the element nor the observer will be around for the
rest of the application’s life.

However, items 11 and 12 would still be useful – perhaps not to me, but to
others. I still think they need doing, but considering the size of this
“requirements stack trace” — and the dozens of other things I have to get
working for Verbosio 0.1 “Proof of concept”, I’m not going to spend any
immediate time on them.

Conclusion

Why am I sharing all this? It’s a classic forest-for-the-trees problem. If
you find yourself writing code for this grand project, and doing something so
far from it you can’t see how you got there… maybe you need to step back
and write it all down. In this case, it helped me realize I was off-track.
However, if everything checked out, I would have gladly continued to work on
weak references, knowing I was still progressing towards my ultimate goal.
(Certainly, items 1 through 9 are still valid statements, and I should
continue working on “timer-based observations of properties”.) Writing out
this “requirements stack trace” can help you see if you went astray, and if
you did, tell you where to get back on track. If you didn’t go astray, it
gives you confidence that you’re doing the right thing.

Ideally, it shouldn’t take you very long to write it all out – say, 15
minutes for a fast typist on a computer. If it does take longer to write out
all the steps, you really do have a stack overflow to worry about, and you
should think about ways you can cut back to #1. Whether you find the path is
correct from start to finish, or has a flaw in it, answering the question,
“Why am I doing this?” is always useful.