Hi,
The naming of the methods in the Selectors API specification has been
heavily debated. I understand the reason for this debate. There is a
long history of bad naming (XMLHttpRequest, AJAX, etc.) and there is
clearly a desire to avoid that again. However, it's virtually
impossible to come up with the perfect name, since everyone has a
different opinion of what that may be.
My rationale in resolving this issue has not depended upon the majority
opinion. Arguments based on nothing more than personal preference have
not been given much weight, simply because everyone has different
opinions and it's impossible to rank one above another. All arguments
based on logic, reasoning or technical issues have been taken into
account and judged on their own merit, not the credentials of the people
making the arguments.
With that in mind, and given that the arguments that have been put
forward are sometimes mutually exclusive, please understand that
whatever the final decision, it is simply not possible to please
everyone, but I hope we can all accept it.
*Rationale for Naming Principles*
A short name is important for several reasons. Since these methods are
designed, and behave, as a superset of the existing getElementsBy*
methods, it is likely that their use will significantly replace the use
of previous methods.
Based on evidence from many widely used JS libraries, and other
feedback, we know that authors generally prefer shorter names over
longer names. This is particularly true for methods that will be
frequently used.
Not only does a shorter name reduce the amount of typing, it can help to
improve the readability of the source code, which in turn makes code
easier to maintain. Given these reasons, I have concluded that, within
reason, short names are a fundamental requirement that must be adhered to.
Ideally, the chosen method names would be relatively clear and
unambiguous with regards to their purpose, usage and return value.
However, this must be put into perspective; the names do not need to
describe these aspects perfectly.
One of the few names that meets this specific requirement perfectly is
getElementsByGroupOfSelectors, but that name is clearly too long. An
appropriate balance needs to be found between clarity and convenience.
With a somewhat intuitive name, it is expected that frequent use by
authors will alleviate any remaining concerns about the constant need to
refer to documentation arising from any ambiguity in the name. For
example, despite the name being completely non-descriptive, many authors
frequently use $() as an alias for document.getElementById() without the
need to constantly lookup what it means.
The name must not clash with any existing DOM API, nor be too similar to
an API that could cause confusion amongst authors. It is also somewhat
important to choose a name that is less likely to clash with a future
API, though this is difficult because it is impossible to predict the
future. It can, however, be helped by choosing a relatively unambiguous
name. For example, choosing selectAll() as one of the names would cause
significant confusion because the name is commonly associated with, and
very similar to, text selection APIs.
For the two methods, it is desirable that the chosen names are somewhat
related to each other. However, because there is a need to maintain
code readability, the two chosen names cannot not be too similar to each
other because it would reduce maintainability of code.
It has been argued that the chosen names should be in line with the
conventions of existing DOM APIs, including:
* getElementById
* getElementsByName
* getElementsByTagName
* getElementsByTagNameNS
* getElementsByClassName (proposed in HTML5)
The convention is to use getElement* for methods that return a single
node and getElements* for methods that return multiple nodes. However,
given that we need two separate methods for these APIs, this is not
desirable as it conflicts the need for readability.
For example, choosing getElementBySelector() and getElementsBySelector()
would not be good choices because they only differ by a single
character. This would make it easier to make a mistake by typing the
wrong method, and also make it more difficult to recognise the error
when debugging code.
There is precedence for not following this convention for similar
methods. DOM Level 3 XPath defines the evaluate() method for evaluating
XPath expressions. (Although, that method is slightly different because
it has a variable return type.)
In addition, Microsoft's .NET uses selectSingleNode() and selectNodes()
for their proprietary XPath implementation. Unfortunately, this also
means that those and similar names cannot be used for these APIs.
*Summary of Naming Principles*
* Short
* Somewhat descriptive of the functionality
* Clear, concise and relatively unambiguous
* Avoid clashes with other APIs due to ambiguous naming
* Easy to type (can't rely on autocomplete)
* Easy to read
*Rejections*
The following names have been rejected for the reasons detailed below.
* match() matchAll()
* matchSelector() matchAllSelectors()
* matchSelectors() matchAllSelectors()
match() is already used for regular expressions matching on Strings in
ECMAScript and it is considered better to use a less ambiguous name. It
is also not clear whether match() would return a single or multiple
elements, without having to assume based on the other being matchAll().
The matchSelector/matchAllSelectors variants have been rejected because
the names seem to be misleading. They create the impression that the
former matches against a single selector and the latter against multiple
selectors, instead of returning single and multiple results, respectively.
* select() selectAll()
* selectOne() selectAll()
* selectFirst() selectAll()
* selectSingle() selectAll()
* selectSingleNode() selectNodes()
* selectNode() selectNodeList()
These select*() variations are either in direct conflict with, or very
similar to, existing APIs, and their use would result in confusion
amongst authors.
* get() getAll()
* getOne() getAll()
These were rejected because they are not descriptive at all, and they
are too ambiguous. They were not well received by almost anyone.
* getElementBySelector() getElementsBySelector()
* getElementBySelectors() getElementsBySelectors()
* getElementByCSSSelector() getElementsByCSSSelector()
* getElementBySelector() getElementListBySelector()
* getElementBySelectors() getElementListBySelectors()
* getElementByGroupOfSelectors() getElementsByGroupOfSelectors()
* getElementByGroupOfSelectors() getElementListByGroupOfSelectors()
These were all rejected because they are far too long. While they are
very clear and mostly follow the established convention, they are not
concise and do not satisfy the length requirement.
* nodeBySelector() nodeListBySelector()
* getNode() getNodes()
* getNode() getAllNodes()
* getNode() getNodeList()
* getNodeBySelector() getNodeListBySelector()
* getNodeByExpr() getNodeListByExpr()
* getBySelector() getBySelectorAll()
These variants using node instead of element were rejected for a few
reasons. Selectors only select elements, not all types of nodes, and it
doesn't seem likely that selectors would be extended to select
non-element nodes in the future. These also break the established
convention of using getElement, and there is no reasonable justification
for doing so in these cases.
* css() cssAll()
* cssQuery() cssQueryAll()
* matchCSS() matchCSSAll()
Selectors aren't just for CSS, as this API clearly demonstrates.
Although there is a common association between selectors and CSS, there
is no reason to encourage this misconception. The names create the
impression that they deal with CSS styles, rather than selecting elements.
Although there has been a previous JavaScript implementation of cssQuery
in the past, this is not considered sufficient justification for using
the ambiguous name.
*Candidates*
After careful consideration, I've narrowed down the remaining options to
these seven pairs.
* matchSingle() matchAll()
* matchOne() matchAll()
* getElement() getElementList()
* getElement() getElements()
* selectElement() selectElementList()
* selectElement() selectAllElements()
* chooseOne() chooseAll()
These are summarised with their pros and cons below:
* matchSingle()/matchOne()/matchAll()
These names short, easy to type and easy to read. The choice between
matchOne and matchSingle would effectively come down to personal
preference. Although matchOne is shorter, it's not significantly better
than matchSingle.
The advantage of using matchSingle and matchAll is that there is an
existing JavaScript implementation of these methods in Dean Edwards'
Base2 library. While the implementation could be considered evidence in
support of these names, it must be noted that these names were
implemented simply because they were the names in the spec at the time.
The names aren't completely clear and unambiguous and it must be noted
that these names did not receive wide acceptance when they were put in
the draft, and so choosing these names probably wouldn't be the most
productive choice.
* getElement()/getElementList()/getElements()
The advantage of these methods is that they somewhat follow the
established convention, although not completely because they don't
specify BySelector (or equivalent). Given that these APIs are
effectively a superset of existing getElement* methods, it makes some
sense to use names that recognise that.
The problem with choosing getElement and getElements is that they are
too similar to each other, which reduces code readability, and so using
getElementList would be a workaround for that issue.
* selectElement()/selectElementList()/selectAllElements()
Overall, these names are relatively good. While they are not the
shortest alternative, they are not too long; they are relatively easy to
type and are easy to read; and they are clear and concise. By using the
word "select", which is easily associated with Selector, they are
somewhat more descriptive than the getElement variations.
One problem is the use of "select*" is similar to the .NET XPath methods
(selectSingleNode/selectNodes), though the use of Element instead of
Node reduces the confusion slightly. Those are also proprietary methods
that aren't used outside of .NET (The DOM3XPath standard uses evaluate()
instead.).
Several people expressed a preference for select() and selectAll(,
though they inevitably had to be rejected due to clashes and ambiguity
with the name. Using selectElement and selectAllElements instead seems
like a good compromise that solves the problem.
* chooseOne()/chooseAll()
The word "choose" is an alternative verb to the word "select"; however
it's a slightly more ambiguous term. While these are shorter, the
advantage of length isn't quite enough to sacrifice the clarity of the name.
*Conclusion*
After carefully considering all of these reasons, I have update the spec
to use selectElement() and selectAllElements(), based on the arguments
given above.
http://dev.w3.org/cvsweb/~checkout~/2006/webapi/selectors-api/Overview.html?content-type=text/html;%20charset=UTF-8
--
Lachlan Hunt
http://lachy.id.au/