W3C home > Mailing lists > Public > public-webapps@w3.org > October to December 2011

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

From: Alex Russell <slightlyoff@google.com>
Date: Wed, 19 Oct 2011 01:06:45 +0100
Message-ID: <CANr5HFW=F9kvLzQbqZuHABzyNtCFquv-yw72MjV8PnWDdX+dAA@mail.gmail.com>
To: Yehuda Katz <wycats@gmail.com>
Cc: Webapps WG <public-webapps@w3.org>, John Resig <jeresig@gmail.com>, Paul Irish <paulirish@google.com>, Lachlan Hunt <lachlan.hunt@lachy.id.au>
On Tue, Oct 18, 2011 at 9:20 PM, Yehuda Katz <wycats@gmail.com> wrote:
> I agree entirely.
> I have asked a number of practitioner friends about this scenario:
>   <div id="parent">
>     <p id="child"><span id="inline">Content</span></p>
>   </div>
>   document.getElementById("child").querySelectorAll("div span"); // returns
> #inline
> In 100% of cases, people consider this behavior *broken*. Not just
> "interesting, I wouldn't have expected that", but "who came up with that!?".
> In all cases involving JavaScript practitioners, people expect
> querySelectorAll to operate on the element as though the element was the
> root of a new document, and where combinators are relative to the element.
> We already knew this was true since all JavaScript libraries that implement
> selectors implemented them in this way.

Great example.

> I also agree that the name querySelectorAll (like getElement(s)By*,
> requestAnimationFrame, addEventListener, and most other DOM APIs), are
> simply too long to use in day-to-day usage. This results in the need to use
> libraries for day-to-day browser development simply to reduce this
> borderline-comical verbosity.
> I like find and findAll, as jQuery has a `find` which invokes the selector
> engine. As to whether jQuery would benefit from the improvements, the
> existing jQuery implementation (Sizzle) of the selector engine when qSA is
> available is
> at: https://github.com/jquery/sizzle/blob/master/sizzle.js#L1150-1233
> There are a few categories of extensions:
> Speeding up certain operations like `#foo` and `body`. There is *no excuse*
> for it being possible to implement userland hacks that improve on the
> performance of querySelectorAll. This may be the result of browsers failing
> to cache the result of parsing selectors or something else, but the fact
> remains that qSA can be noticably slower than the old DOM methods, even when
> Sizzle needs to parse the selector to look for fast-paths.

This is likely implementation issues. Not, perhaps, apropos to this.
And in any case, if *today's* QSA is slower, then you're right. IIRC,
one of the (busted) justifications for the current API was that it
would allow re-use of the existing in-browser infrastructure, which
should indeed be fast.

> Fixing the implementation mistake in qSA that we're discussing here.
> Bugs in specific browsers.
> jQuery also handles certain custom pseudoselectors, and it might be nice if
> it was possible to register JavaScript functions that qSA would use if it
> found an unknown pseudo (this would make it possible to implement most of
> jQuery's selector engine in terms of qSA), but that's a discussion for
> another day.

Yeah, I'm afraid it will have to be.

> On Tue, Oct 18, 2011 at 9:42 AM, Alex Russell <slightlyoff@google.com>
> wrote:
>> 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 Wednesday, 19 October 2011 00:07:43 UTC

This archive was generated by hypermail 2.3.1 : Friday, 27 October 2017 07:26:36 UTC