Re: More questions about contextual reference nodes
On 4/13/11 5:43 AM, Lachlan Hunt wrote: I didn't think so, but then perhaps I misunderstand what the spec means by a native object. ECMAScript defines a native object as object in an ECMAScript implementation whose semantics are fully defined by this specification rather than by the host environment. So that would include things like Array, String, etc. Ineed. I don't think NodeList fits that definition, since it's provided by the host environment, not ECMAScript. That's correct. I also thought something like this would not be a native object either: function init() { ... } var x = new init(); That's a native object; the behavior of that set of operations is completely defined by the ES spec. JQuery more or less does that to create an object with custom properties, and then basically uses Array.prototype.push.apply(x, elms) to add the collection to that object. Right; jquery's got native objects there. It's nice so that cases where authors try to pass in an array of things that aren't nodes are handled well. The other alternative is just to accept a collection of anything, and iterate through it to find all the Element nodes, ignoring everything else. I don't see any reason to prefer the latter approach. I would really prefer we not do the latter. -Boris
Re: More questions about contextual reference nodes
On 4/13/11 6:20 AM, Lachlan Hunt wrote: Which conversion algorithm applies here? Is it 4.1.15. object, or 4.1.16. Interface types? http://dev.w3.org/2006/webapi/WebIDL/#es-object The latter, since Node is an interface type. -Boris
Re: More questions about contextual reference nodes
Lachlan Hunt: However, with the way in which the IDL is overloaded, it's not clear to me which of the two overloaded methods gets invoked when the parameter is null. The IDL says: querySelector(in DOMString selectors, in optional Element refElement); querySelector(in DOMString selectors, in sequenceNode refNodes); When the author invokes: x.querySelector(a, null); Does it invoke the method with refElement or refNodes? That is one of the unsatisfactory things about the way overloading is currently handled in Web IDL. In situations where null is a valid value for more than one overload, it needs to be described in prose, but only if it matters which of the two operations is considered to be invoked. See the blue box just below this footnote: http://dev.w3.org/2006/webapi/WebIDL/#distinguishable-interface-note Step 4 of the algorithm for the behaviour of Function objects that correspond to IDL operations http://dev.w3.org/2006/webapi/WebIDL/#es-operations says If S contains more than one entry, then the operation call is ambiguous. Remove all but one entry from S according to rules specified in the description of interface I, or arbitrarily if no such rules exist. Note that it is ambiguous if you have, say querySelector(in DOMString selectors, in optional Element refElement); querySelector(in DOMString selectors, in Node[] refNodes); since null is a valid value for both Element and Node[]. With querySelector(in DOMString selectors, in optional Element refElement); querySelector(in DOMString selectors, in sequenceNode refNodes); null is not a valid value for sequenceNode, so passing null calls the first of the two overloads. That is because in the overload resolution algorithm http://dev.w3.org/2006/webapi/WebIDL/#dfn-overload-resolution-algorithm step 3.2.2 only considers object, interface types, nullable types and array types when “null” is passed as an argument. -- Cameron McCormack ≝ http://mcc.id.au/
Re: More questions about contextual reference nodes
On 2011-04-13 04:43, Cameron McCormack wrote: Lachlan Hunt: This seems to differ from the algorithm given for T[], which requires that the object be either an array host object or a native object, which would not handle the JQuery case. The sequenceT type seems more generic than that as the algorithm seems to be able to support any object with a length and indexed properties. Why wouldn’t it handle the JQuery case? Isn’t it a native object? I didn't think so, but then perhaps I misunderstand what the spec means by a native object. ECMAScript defines a native object as object in an ECMAScript implementation whose semantics are fully defined by this specification rather than by the host environment. So that would include things like Array, String, etc. I don't think NodeList fits that definition, since it's provided by the host environment, not ECMAScript. I also thought something like this would not be a native object either: function init() { ... } var x = new init(); JQuery more or less does that to create an object with custom properties, and then basically uses Array.prototype.push.apply(x, elms) to add the collection to that object. The issue of whether you want to throw eagerly if passed an array with elements of the wrong type to an operation taking a sequenceT is an interesting one, which probably still could bear some more discussion. On the one hand, it helps ensure implementations don’t diverge based on when during the course of running the method these elements from the sequence are looked up. I could mean a lot of useless checks, though. It's nice so that cases where authors try to pass in an array of things that aren't nodes are handled well. The other alternative is just to accept a collection of anything, and iterate through it to find all the Element nodes, ignoring everything else. I don't see any reason to prefer the latter approach. -- Lachlan Hunt - Opera Software http://lachy.id.au/ http://www.opera.com/
Re: More questions about contextual reference nodes
On 2011-04-13 06:32, Cameron McCormack wrote: Lachlan Hunt: OK. Then I'm not sure what the practical difference between the Element[] or sequenceElement would be then, nor which one to use. ... the only difference is that with Element[] you can distinguish between null and an array of [length 0], while with sequenceElement you can’t. I don't think it's necessary to distinguish between null and length 0 here, since they both mean that there are no contextual reference elements. However, with the way in which the IDL is overloaded, it's not clear to me which of the two overloaded methods gets invoked when the parameter is null. The IDL says: querySelector(in DOMString selectors, in optional Element refElement); querySelector(in DOMString selectors, in sequenceNode refNodes); When the author invokes: x.querySelector(a, null); Does it invoke the method with refElement or refNodes? (Although, in this case, it shouldn't matter, since the algorithm I wrote to determine contextual reference nodes ignores null in either case) While i n: Let x be the result of calling [[Get]] on V with property name ToString(i). Set Ei to be the result of converting x to an IDL value of type T. This step can throw (as part of the conversion process defined for converting to type T); seems like that would involve throwing from the whole algorithm. Yep. Which conversion algorithm applies here? Is it 4.1.15. object, or 4.1.16. Interface types? http://dev.w3.org/2006/webapi/WebIDL/#es-object The former never throws, the latter will throw a TypeError. So am I right in assuming it's the latter? -- Lachlan Hunt - Opera Software http://lachy.id.au/ http://www.opera.com/
Re: More questions about contextual reference nodes
Lachlan Hunt: I reviewed WebIDL again, and I think I've started to understand the difference between sequenceT and T[] now. As I understand it, the algorithm to convert an ECMAScript object to an IDL sequence should work with any object that has a length property and indexed values containing Node objects. That is true for an Array of Nodes, NodeList, HTMLCollection and the above JQuery case, they can all be handled in the same way. Yes, that’s right. This seems to differ from the algorithm given for T[], which requires that the object be either an array host object or a native object, which would not handle the JQuery case. The sequenceT type seems more generic than that as the algorithm seems to be able to support any object with a length and indexed properties. Why wouldn’t it handle the JQuery case? Isn’t it a native object? I've updated and simplified the spec to handle the above case using the parameter sequenceNode. I still need to update the prose to say that while the collections may contain any Node, only Element nodes are added to the list of contextual reference elements. But the following cases should all work. Agreed, that works, according to Web IDL’s currenty definition of overloading. The issue of whether you want to throw eagerly if passed an array with elements of the wrong type to an operation taking a sequenceT is an interesting one, which probably still could bear some more discussion. On the one hand, it helps ensure implementations don’t diverge based on when during the course of running the method these elements from the sequence are looked up. I could mean a lot of useless checks, though. -- Cameron McCormack ≝ http://mcc.id.au/
Re: More questions about contextual reference nodes
On 4/10/11 4:30 AM, Lachlan Hunt wrote: Would it be useful, and is it possible to define the refElements parameter to accept any object that contains a .length and indexed properties, just like a JQuery object? Looks like this already got answered, but yes, sequenceNode should make that work. OK. Then I'm not sure what the practical difference between the Element[] or sequenceElement would be then, nor which one to use. I'm not either. That's why Cameron is cced. If using webidl array/sequence types, that would help with the iteration, but not the large allocation. OK, does that mean it's not really worth defining like that? I think this is an edge case we shouldn't worry about. Perhaps famous last words. Yes, I just checked and I think you may be right. The WebIDL algorithm to convert an ECMAScript array to an IDL value of type T[] iterates the array and says: While i n: Let x be the result of calling [[Get]] on V with property name ToString(i). Set Ei to be the result of converting x to an IDL value of type T. This step can throw (as part of the conversion process defined for converting to type T); seems like that would involve throwing from the whole algorithm. -Boris
Re: More questions about contextual reference nodes
On 4/10/11 12:02 PM, Lachlan Hunt wrote: I've updated and simplified the spec to handle the above case using the parameter sequenceNode. I still need to update the prose to say that while the collections may contain any Node, only Element nodes are added to the list of contextual reference elements. Looks like you now made that change too. The new text looks good to me. Thanks! What Firefox 5 will ship doesn't match this yet (because we don't actually have a sane webidl implementation yet), but that's why we're prefixing... ;) -Boris
Re: More questions about contextual reference nodes
Lachlan Hunt: OK. Then I'm not sure what the practical difference between the Element[] or sequenceElement would be then, nor which one to use. Boris Zbarsky: I'm not either. That's why Cameron is cced. If you are choosing between those two for the type of an argument, and you don’t have any way of getting an actual array host object Element[] (so will be passing in a native Array, or a NodeList, or…), and hence the method cannot cause a reference to a passed-in Element[] object to be kept, then the only difference is that with Element[] you can distinguish between null and an array of length 1, while with sequenceElement you can’t. While i n: Let x be the result of calling [[Get]] on V with property name ToString(i). Set Ei to be the result of converting x to an IDL value of type T. This step can throw (as part of the conversion process defined for converting to type T); seems like that would involve throwing from the whole algorithm. Yep. -- Cameron McCormack ≝ http://mcc.id.au/
Re: More questions about contextual reference nodes
Cameron McCormack: then the only difference is that with Element[] you can distinguish between null and an array of length 1, while with sequenceElement you can’t. Length 0, not 1. -- Cameron McCormack ≝ http://mcc.id.au/
Re: More questions about contextual reference nodes
On 2011-04-09 19:14, Boris Zbarsky wrote: On 4/9/11 6:27 AM, Lachlan Hunt wrote: There were cases in JQuery where the script wanted to iteratively run a selector on all nodes in a collection, and return elements that are descendants of those elements. This allows :scope to be used in those cases by passing the collection as the refNodes. There was previous discussion of this somewhere in the public-webapps archive. Hmm... ok. As a simple example of that, this works in JQuery: pspan/span pspan/span pspan/span script alert($(p).find(span).length) /script But is jquery's collection a JS Array? The object returned by the $() function isn't an array. It's a custom object that mimics the functionality of an array. This means that as currently defined, refElements could not accept a JQuery object as the parameter like so: var p = $(p.foo) Var a = $(a); a[0].matchesSelector(:scopea, p) This would instead require scripts to do this: a[0].matchesSelector(:scopea, p.toArray()) JQuery effectively defines .toArray() as a function that returns: Array.prototype.slice.call( this, 0 ); Would it be useful, and is it possible to define the refElements parameter to accept any object that contains a .length and indexed properties, just like a JQuery object? i.e. Can we make this work? var x = {} x[0] = el1; x[1] = el2; x[2] = el3; x.length = 3; a.matchesSelector(:scopea, x); I also have to include one for HTMLCollection, which doesn't inherit from NodeList. Yeah, that's broken... I wonder whether we can just fix that in Web DOM Core or something Yes, I'd like to fix it somehow. I'm not yet sure how. WebIDL says sequences are passed by value and arrays are passed by reference. So I suspect using an array is better here so that it doesn't have to create a copy. The by reference thing only happens for array host objects, which a JS Array is not. So the copy would effectively happen in either case, I believe, for JS Array. OK. Then I'm not sure what the practical difference between the Element[] or sequenceElement would be then, nor which one to use. Yes, I would like feedback about the best way to define this, particularly for Arrays. In particular, how to address the following cases. var ref = []; ref[0] = el1; ref[100] = el2; That will contain almost a million empty cells. Will iterating through that cause any unwanted performance issues? I believe my current Gecko implementation (using our existing variant facilities, since that's all we have to deal with overloads for the moment) will allocate a C array with 101 entries, then ignore it because not everything in the array is an Element. A DOM binding implementation using WebIDL arrays or sequences would allocate a C++ array with 101 entries, all of which except for the first and last are null. Then the actual implementation of the selectors API will walk this array and add only the first and last entry to the set of scope elements. I think. I'm pretty sure this is true for Array; the behavior for sequence is less clear to me. And maybe this can all be optimized in implementations, somehow... Ccing Cameron for his input. Should we require arrays to contain contiguous Elements and only iterate up to the first empty or non-Element cell, ignoring anything beyond that? If using webidl array/sequence types, that would help with the iteration, but not the large allocation. OK, does that mean it's not really worth defining like that? ref[1] = string; Should passing this now throw an exception, or should it just accept that ref[0] was an element and use that? Webidl array/sequence would throw in this case, I think. Yes, I just checked and I think you may be right. The WebIDL algorithm to convert an ECMAScript array to an IDL value of type T[] iterates the array and says: While i n: Let x be the result of calling [[Get]] on V with property name ToString(i). Set Ei to be the result of converting x to an IDL value of type T. Set i to i + 1. I think the second step in the loop should throw a TypeError if the object can't be converted to the correct type (Element, in this case). But WebIDL doesn't seems very clear about this, so I may be wrong. -- Lachlan Hunt - Opera Software http://lachy.id.au/ http://www.opera.com/
Re: More questions about contextual reference nodes
On 2011-04-10 13:30, Lachlan Hunt wrote: But is jquery's collection a JS Array? The object returned by the $() function isn't an array. It's a custom object that mimics the functionality of an array... var p = $(p.foo) Var a = $(a); a[0].matchesSelector(:scopea, p) ... Would it be useful, and is it possible to define the refElements parameter to accept any object that contains a .length and indexed properties, just like a JQuery object? i.e. Can we make this work? var x = {} x[0] = el1; x[1] = el2; x[2] = el3; x.length = 3; a.matchesSelector(:scopea, x); I reviewed WebIDL again, and I think I've started to understand the difference between sequenceT and T[] now. As I understand it, the algorithm to convert an ECMAScript object to an IDL sequence should work with any object that has a length property and indexed values containing Node objects. That is true for an Array of Nodes, NodeList, HTMLCollection and the above JQuery case, they can all be handled in the same way. This seems to differ from the algorithm given for T[], which requires that the object be either an array host object or a native object, which would not handle the JQuery case. The sequenceT type seems more generic than that as the algorithm seems to be able to support any object with a length and indexed properties. I've updated and simplified the spec to handle the above case using the parameter sequenceNode. I still need to update the prose to say that while the collections may contain any Node, only Element nodes are added to the list of contextual reference elements. But the following cases should all work. 1. Array of Elements document.querySelector(:scopea, [el1, el2, el3]); 2. NodeList document.querySelector(:scopea, el.childNodes); 3. NodeList converted to an array document.querySelector(:scopea, Array.prototype.slice.call(el.childNodes, 0)); // Conversion to an array is unnecessary here, but just showing that // it will work anyway. 4. HTMLCollection s.matchesSelector(:scope~a, document.images); 5. Objects with indexed properties, including JQuery var x = {} x[0] = el1; x[1] = el2; x[2] = el3; x.length = 3; document.querySelector(:scopea, x); x = $(.foo, .bar); a.matchesSelector(:scopea, x); a.matchesSelector(:scopea, x.toArray()); // Unnecessary converstion to array here -- Lachlan Hunt - Opera Software http://lachy.id.au/ http://www.opera.com/
Re: More questions about contextual reference nodes
On 04/09/2011 07:14 PM, Boris Zbarsky wrote: On 4/9/11 6:27 AM, Lachlan Hunt wrote: I also have to include one for HTMLCollection, which doesn't inherit from NodeList. Yeah, that's broken... I wonder whether we can just fix that in Web DOM Core or something If people are willing to implement that, certainly. -- Ms2ger
More questions about contextual reference nodes
I have two questions about http://www.w3.org/TR/selectors-api2/#determine-contextual-reference-nodes 1) What are the use cases for supplying more than one contextual reference node, exactly? It seems weird to allow more than one node to match :scope. 2) If we do want to allow the multiple node thing, can we please do it in IDL instead of the (currently pretty vague) prose? Something like: Element querySelector(in DOMString selectors, in optional Element refElement); Element querySelector(in DOMString selectors, in optional NodeList refElements); Element querySelector(in DOMString selectors, in optional sequenceElement refElements); or some such? It's not quite clear to me whether we want a sequenceElement or a T[]; that's worth checking. In either case, the prose will need to define what happens with the NodeList or sequence/array cases, but there will be no ambiguity about how one gets Elements out of what's passed in. The one difference is that in the array case if non-elements are present in the array an exception will be thrown. I think that's fine, myself. -Boris
Re: More questions about contextual reference nodes
On 2011-04-09 10:12, Boris Zbarsky wrote: I have two questions about http://www.w3.org/TR/selectors-api2/#determine-contextual-reference-nodes 1) What are the use cases for supplying more than one contextual reference node, exactly? It seems weird to allow more than one node to match :scope. There were cases in JQuery where the script wanted to iteratively run a selector on all nodes in a collection, and return elements that are descendants of those elements. This allows :scope to be used in those cases by passing the collection as the refNodes. There was previous discussion of this somewhere in the public-webapps archive. 2) If we do want to allow the multiple node thing, can we please do it in IDL instead of the (currently pretty vague) prose? Something like: I know the draft is quite poorly written with regards to how to deal with collections right now. Element querySelector(in DOMString selectors, in optional Element refElement); Element querySelector(in DOMString selectors, in optional NodeList refElements); Element querySelector(in DOMString selectors, in optional sequenceElement refElements); I also have to include one for HTMLCollection, which doesn't inherit from NodeList. But if that would be better, then yes, we can do that. It just makes the IDL 4 times longer, as that has to be repeated for each method of the 3 methods. Ive made this change now. I also dropped queryScopedSelector at the same time, since it wasn't able meet the original requirements that it was being designed for and so not worth keeping. or some such? It's not quite clear to me whether we want a sequenceElement or a T[]; that's worth checking. WebIDL says sequences are passed by value and arrays are passed by reference. So I suspect using an array is better here so that it doesn't have to create a copy. In either case, the prose will need to define what happens with the NodeList or sequence/array cases, but there will be no ambiguity about how one gets Elements out of what's passed in. The one difference is that in the array case if non-elements are present in the array an exception will be thrown. I think that's fine, myself. Yes, I would like feedback about the best way to define this, particularly for Arrays. In particular, how to address the following cases. var ref = []; ref[0] = el1; ref[100] = el2; That will contain almost a million empty cells. Will iterating through that cause any unwanted performance issues? Should we require arrays to contain contiguous Elements and only iterate up to the first empty or non-Element cell, ignoring anything beyond that? ref[1] = string; Should passing this now throw an exception, or should it just accept that ref[0] was an element and use that? For NodeLists, should it accept any NodeList and only use the Element nodes? e.g. element.childNodes may contain text or comment nodes. -- Lachlan Hunt - Opera Software http://lachy.id.au/ http://www.opera.com/
Re: More questions about contextual reference nodes
On 4/9/11 6:27 AM, Lachlan Hunt wrote: There were cases in JQuery where the script wanted to iteratively run a selector on all nodes in a collection, and return elements that are descendants of those elements. This allows :scope to be used in those cases by passing the collection as the refNodes. There was previous discussion of this somewhere in the public-webapps archive. Hmm... ok. But is jquery's collection a JS Array? I also have to include one for HTMLCollection, which doesn't inherit from NodeList. Yeah, that's broken... I wonder whether we can just fix that in Web DOM Core or something WebIDL says sequences are passed by value and arrays are passed by reference. So I suspect using an array is better here so that it doesn't have to create a copy. The by reference thing only happens for array host objects, which a JS Array is not. So the copy would effectively happen in either case, I believe, for JS Array. Yes, I would like feedback about the best way to define this, particularly for Arrays. In particular, how to address the following cases. var ref = []; ref[0] = el1; ref[100] = el2; That will contain almost a million empty cells. Will iterating through that cause any unwanted performance issues? I believe my current Gecko implementation (using our existing variant facilities, since that's all we have to deal with overloads for the moment) will allocate a C array with 101 entries, then ignore it because not everything in the array is an Element. A DOM binding implementation using WebIDL arrays or sequences would allocate a C++ array with 101 entries, all of which except for the first and last are null. Then the actual implementation of the selectors API will walk this array and add only the first and last entry to the set of scope elements. I think. I'm pretty sure this is true for Array; the behavior for sequence is less clear to me. And maybe this can all be optimized in implementations, somehow... Ccing Cameron for his input. Should we require arrays to contain contiguous Elements and only iterate up to the first empty or non-Element cell, ignoring anything beyond that? If using webidl array/sequence types, that would help with the iteration, but not the large allocation. ref[1] = string; Should passing this now throw an exception, or should it just accept that ref[0] was an element and use that? Webidl array/sequence would throw in this case, I think. For NodeLists, should it accept any NodeList and only use the Element nodes? e.g. element.childNodes may contain text or comment nodes. I think that's the right thing to do, yes. -Boris