QSA, the problem with ":scope", and naming

Lachlan and I have been having an...um...*spirited* twitter discussion
regarding querySelectorAll, the (deceased?) queryScopedSelectorAll,
and ":scope". He asked me to continue here, so I'll try to keep it
short:

The rooted forms of "querySelector" and "querySelectorAll" are mis-designed.

Discussions about a Scoped variant or ":scope" pseudo tacitly
acknowledge this, and the JS libraries are proof in their own right:
no major JS library exposes the QSA semantic, instead choosing to
implement a rooted search.

Related and equally important, that querySelector and querySelectorAll
are often referred to by the abbreviation "QSA" suggests that its name
is bloated and improved versions should have shorter names. APIs gain
use both through naming and through use. On today's internet -- the
one where 50% of all websites include jQuery -- you could even go with
element.$("selector") and everyone would know what you mean: it's
clearly a search rooted at the element on the left-hand side of the
dot.

Ceteris peribus, shorter is better. When there's a tie that needs to
be broken, the more frequently used the API, the shorter the name it
deserves -- i.e., the larger the component of its meaning it will gain
through use and repetition and not naming and documentation.

I know some on this list might disagree, but all of the above is
incredibly non-controversial today. Even if there may have been
debates about scoping or naming when QSA was originally designed,
history has settled them. And QSA lost on both counts.

I therefore believe that this group's current design for scoped
selection could be improved significantly. If I understand the latest
draft (http://www.w3.org/TR/selectors-api2/#the-scope-pseudo-class)
correctly, a scoped search for multiple elements would be written as:

   element.querySelectorAll(":scope > div > .thinger");

Both then name and the need to specify ":scope" are punitive to
readers and writers of this code. The selector is *obviously*
happening in relationship to "element" somehow. The only sane
relationship (from a modern JS hacker's perspective) is that it's
where our selector starts from. I'd like to instead propose that we
shorten all of this up and kill both stones by introducing a new API
pair, "find" and "findAll", that are rooted as JS devs expect. The
above becomes:

   element.findAll("> div > .thinger");

Out come the knives! You can't start a selector with a combinator!

Ah, but we don't need to care what CSS thinks of our DOM-only API. We
can live and let live by building on ":scope" and specifying find* as
syntactic sugar, defined as:

  HTMLDocument.prototype.find =
  HTMLElement.prototype.find = function(rootedSelector) {
     return this.querySelector(":scope " + rootedSelector);
   }

   HTMLDocument.prototype.findAll =
   HTMLElement.prototype.findAll = function(rootedSelector) {
     return this.querySelectorAll(":scope " + rootedSelector);
   }

Of course, ":scope" in this case is just a special case of the ID
rooting hack, but if we're going to have it, we can kill both birds
with it.

Obvious follow up questions:

Q.) Why do we need this at all? Don't the toolkits already just do
this internally?
A.) Are you saying everyone, everywhere, all the time should need to
use a toolkit to get sane behavior from the DOM? If so, what are we
doing here, exactly?

Q.) Shorter names? Those are for weaklings!
A.) And humans. Who still constitute most of our developers. Won't
someone please think of the humans?

Q.) You're just duplicating things!
A.) If you ignore all of the things that are different, then that's
true. If not, well, then no. This is a change. And a good one for the
reasons listed above.

Thoughts?

Received on Tuesday, 18 October 2011 16:42:59 UTC