![]() |
jQuery Overloading Strategy -- What Not To Do
Just took a peek at the jQuery forums. One of latest posts:
http://forum.jquery.com/topic/jquery-and-textnodes | I've recently stumbled upon a weird issue - for a given ajax | response I would create HTML element and insert it into DOM, | however weirdly, my first textNode would be dropped. So I did | the test on newer version of jQuery, and here's mine | observation: | [...] | $(document).ready(function() { | console.log($("A<div>B</div>C<div>D</div>E")); | }); | Expected result: | | [<TextNode textContent="A">, div, <TextNode textContent="C">, | div, <TextNode textContent="E">] | | Received result: | | [div, <TextNode textContent="C">, div] The last text node is also dropped. This is the result of the method overloading approach and the `quickExpr` regex. Both of which still persist to this day. // A simple way to check for HTML strings or ID strings // (both of which we optimize for) quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, The first part of that expression, `[^<]*` says "0 or more characters that aren't `<`". So in essence, they deliberately drop text nodes. We've covered the problems with method overloading in numerous threads). All of the proposed solutions recommend strange hacks to get around this design. $("<jQfix/>"+response+"<jQfix/>").filter(":not(jQfix)"); Another comment tries to justify jQuery's behavior: "... jQuery in my opinion was very smart by simply removing those in such cases." Another poster states: | instead of doing: | | $(myhtml).appendTo(targetDiv); | | | do this: | | $(targetDiv).append(myhtml); And realizing that jQuery has two different ways of doing essentially the same thing, and they they work differently. The second approach goes through jQuery's long `domManip` function and then `buildFragment`. I've also told on many occasions that complicated methods lead to trouble. Function `buildFragment` goes through `clean`, which tries to either parse the HTML or use innerHTML and then attempting to normalize some of that, also calling `findInputs` which despite its name, returns undefined. It begins like so: | jQuery.buildFragment = function( args, nodes, scripts ) { | var fragment, cacheable, cacheresults, doc; | | | // nodes may contain either an explicit document object, | // a jQuery collection or context object. | // If nodes[0] contains a valid object to assign to doc There is more method overloading in a newly introduced function. Method `buildFragment` is new. So they're adding new functionality and relying on the same old mistakes. How do you describe the psychology that goes into that thinking? I'd call it insanity. And look just a bit down in `buildFragment`, they realize getting bit by problems of method overloading: | // Ensure that an attr object doesn't incorrectly stand in as | // a document object | // Chrome and Firefox seem to allow this to occur and will | // throw exception | // Fixes #8950 | if ( !doc.createDocumentFragment ) { | doc = document; | } What that comment means by "attr object" -- and it is horribly misleading -- is that if an object is passed in to create attributes, as in `jQuery('<input type="hidden" />', { 'class': 'test' });` that the initial call to jQuery will end up calling `buildFragment` and then passing it `{ 'class': 'test' }` as attributes and since `{ 'class': 'test' }` doesn't have an owner document, the whole thing falls apart. Now why would that happen, you might wonder. Sure, it is complicated and if anyone got lost reading that, it is understandable; the strategy and source code are overly complicated. jQuery is presented as a script that will help simplify browser scripting and smooth over the differences between browsers. Instead, it adds a lot of unneeded complexity that has, does, and will continue to cause problems. It is the tool of choice for the the uninformed. Instead, if one learns javascript and browsers then one can reasonably conclude that: 1) jQuery isn't needed 2) jQuery adds complexity that causes problems Creating something whose complexity exceeds that of the original problem will undoubtedly create more problems than is projected to solve. And that is exactly what jQuery does. It is a shortcut to failure. If the goal is to build high-quality web apps, then instead of using jQuery, learn the DOM, learn how browsers work, and learn to program using concise, well-named methods. Cornford on overloading: http://groups.google.com/group/comp....67fd2073ce031f Myself on J Resig's "banning" comp.lang.javascript: groups.google.com/group/comp.lang.javascript/msg/71999734c4116c52 COrnford, on attitude towards learning: http://groups.google.com/group/comp....a46c969b8d899a |
Re: jQuery Overloading Strategy -- What Not To Do
On Sep 10, 1:28*pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> Just took a peek at the jQuery forums. One of latest posts: > > http://forum.jquery.com/topic/jquery-and-textnodes > > | I've recently stumbled upon a weird issue - for a given ajax > | response I would create HTML element and insert it into DOM, > | however weirdly, my first textNode would be dropped. So I did > | the test on newer version of jQuery, and here's mine > | observation: > > | [...] > | $(document).ready(function() { > | * * console.log($("A<div>B</div>C<div>D</div>E")); > | }); > > | Expected result: > | > | [<TextNode textContent="A">, div, <TextNode textContent="C">, > | div, <TextNode textContent="E">] > | > | Received result: > | > | [div, <TextNode textContent="C">, div] > > The last text node is also dropped. This is the result of the method > overloading approach and the `quickExpr` regex. Both of which still > persist to this day. > > // A simple way to check for HTML strings or ID strings > // (both of which we optimize for) > quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, > > The first part of that expression, `[^<]*` says "0 or more characters > that aren't `<`". So in essence, they deliberately drop text nodes. > ....they care about the capturing group, or `(<[\w\W]+>)` and that can include internal text nodes, sandwiched between elements (or more like what looks like elements to them); only text nodes between tags are matched. That is: var match = quickExpr.exec("start <b>1</b> middle <b>3</b> end"); match[1]; // <b>1</b> middle <b>3</b> That capturing group matches neither "start " nor " end" but matches " middle ". It also matches invalid markup, quickExpr.exec("<a></b>")); I don't know what `quickExpr` means or what the author wanted it to do. Not to detract from the original topic of overloading and complicated methods, i.e. > We've covered the problems with method overloading in numerous > threads). That is the subject at hand. [...] -- Garrett |
Re: jQuery Overloading Strategy -- What Not To Do
dhtml wrote:
>> We've covered the problems with method overloading in numerous >> threads). > > That is the subject at hand. Do you think all overloading in JS is a problem? I agree that many of jQuery's overloadings are absurd, most prominently its main function `jQuery`. But I haven't found anything really wrong with the dual get/ set nature of a number of its functions. While I don't object to `getVal/setVal` a single function `val` also seems all right. Do you object? -- Scott |
Re: jQuery Overloading Strategy -- What Not To Do
Scott Sauyet wrote:
> While I don't object to `getVal/setVal` a single function `val` > also seems all right. While I don't object to `getVal/setVal`, a single function, `val`, also seems all right. (Missing commas that are important for readability.) -- Scott |
Re: jQuery Overloading Strategy -- What Not To Do
On Sep 12, 9:16*pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
> dhtml wrote: > >> We've covered the problems with method overloading in numerous > >> threads). > > > That is the subject at hand. > > Do you think all overloading in JS is a problem? *I agree that many of > jQuery's overloadings are absurd, most prominently its main function > `jQuery`. *But I haven't found anything really wrong with the dual get/ > set nature of a number of its functions. *While I don't object to > `getVal/setVal` a single function `val` also seems all right. *Do you > object? It becomes a problem when those writing the scripts don't understand the underlying behaviour of browsers. There are many questions on stackoverflow about fundamental browser behaviour, such as is it OK to just use selectElement.value rather than selectElement.options[selectElement.selectedIndex].value, that get responses like "just use jQuery: $(#selectElementId).val()". Which not only doesn't answer the OP's question, but actively discourages them from asking in the first place. A full explanation would include getting the value of a select element depending on the markup with links to relevant standards and the well known quirks in commonly used browsers. I would have thought that a full explanation is a better argument for using a library than a simplistic "just use it". Browsers are slowing converging on support for standards, and standards themselves are changing to provide more explicit support for what developers want to do (forget what users actually want, it's all about the developers, isn't it?). It will not be that long before behaviour will be sufficiently standard and basic functionality sufficiently complete that 3rd party libraries will not be required for most things. For example, script-based CSS selector engines are redundant in browsers with querySelector/All support, many transitions can now be performed purely in CSS, no doubt simple animations will follow. -- Rob |
Re: jQuery Overloading Strategy -- What Not To Do
On Sep 12, 4:16*am, Scott Sauyet <scott.sau...@gmail.com> wrote:
> dhtml wrote: > >> We've covered the problems with method overloading in numerous > >> threads). > > > That is the subject at hand. > > Do you think all overloading in JS is a problem? * The problems with overloading come down to typechecking woes and added complexity for what to do with the type found. Other twists include optional arguments, and even optional middle arguments, which requires reassigning and shifting things over. JQeruy adds an additional twist by examining the contents of strings passed. IF the argument is a string, if that string looks like something that can be matched by a very naive HTML regex, then try to build some HTML instead of selecting nodes. I.e. | if ( selector.charAt(0) === "<" For me, I'd rather see a function like `buildHTML`. THen again, I'm wary of a function that takes string, and then uses innerHTML, regex, and cloneNode to build HTML. I can't justify doing that in a general sense. I agree that many of > jQuery's overloadings are absurd, most prominently its main function > `jQuery`. *But I haven't found anything really wrong with the dual get/ > set nature of a number of its functions. *While I don't object to > `getVal/setVal` a single function `val` also seems all right. *Do you > object? > Methods that do more than one thing are more complicated. A get/set method, as you've described, does one of two things: 1) either return something or 2) have side effects are inherently more complex than methods that do one thing. The SOLID principles, and I'm thinking of SRP now, can keep code clean, simple, easy to understand, predictable. SRP is a good guideline for designing methods, generally. For methods that perform operations that are is tricky, the trickiness more apparent and not obfuscated by API design decisions. Depends why and how you do it. -- Garrett |
Re: jQuery Overloading Strategy -- What Not To Do
On Sep 12, 6:17*pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> On Sep 12, 4:16*am, Scott Sauyet <scott.sau...@gmail.com> wrote: > > > dhtml wrote: While I was writing alone, someone burst in and would not stop talking to me. Probably should not have posted then. Corrections below. [...] > A get/set method, as you've described, does one of two things: 1) > either return something or 2) have side effects. [inserted fullstop] That's --> inherently more > complex than methods that do one thing. > > The SOLID principles, and I'm thinking of SRP now, can keep code > clean, simple, easy to understand, predictable. *SRP is a good > guideline for designing methods, generally. For methods that perform > operations that are is -> "are", not "are is" tricky, the trickiness more apparent and not > obfuscated by API design decisions. > |
Re: jQuery Overloading Strategy -- What Not To Do
dhtml wrote:
> Scott Sauyet wrote: >> Do you think all overloading in JS is a problem? * > > The problems with overloading come down to typechecking woes and added > complexity for what to do with the type found. Other twists include > optional arguments, and even optional middle arguments, which requires > reassigning and shifting things over. The implementation of overloaded methods is of course problematic, and the only justification I can see for it is in *perceived* API simplicity. Of course an API that has val(/*optional*/ any) /* if `any` supplied, sets the value to `any`, otherwise returns current value. is not actually any simpler than one that has getVal() /* @returns Any. Gets the current value. */ setVal(any) /* @return undefined. Sets the current value to `any`. */ In fact, it'ss arguably more complicated. It's certainly harder to document well. But there is still some persistent feeling that the API with the single function is cleaner. My question is whether this vague and fuzzy feeling that the single- functioned API is simpler could ever be enough of a reason for complicating the implementation. I'm entirely mixed on this. I'm all for complicating implementation to simplify an API. But what about when the API isn't *really* any simpler? > [ ... ] >> While I don't object to `getVal/setVal` a single function `val` >> also seems all right. *Do you object? > > Methods that do more than one thing are more complicated. Yes, but so are objects that do more than one thing. The question is whether that complication is ever justified. > A get/set method, as you've described, does one of two things: 1) > either return something or 2) have side effects are inherently more > complex than methods that do one thing. > > The SOLID principles, and I'm thinking of SRP now, can keep code > clean, simple, easy to understand, predictable. *SRP is a good > guideline for designing methods, generally. SRP is a guideline for designing class of objects, not for defining libraries. Of course libraries can consist of classes that follow all of the SOLID principles. And there could be straightforward extensions of the SOLID principles to library design, but I tend not to use JS in a particularly object-oriented manner, so such considerations are often of less importance to me. > For methods that perform > operations that are is tricky, the trickiness more apparent and not > obfuscated by API design decisions. I almost always prefer a clean API to a clean implementation. > Depends why and how you do it. As always! :-) -- Scott |
Re: jQuery Overloading Strategy -- What Not To Do
On Sep 13, 4:31*am, Scott Sauyet <scott.sau...@gmail.com> wrote:
> dhtml wrote: > > Scott Sauyet wrote: > >> Do you think all overloading in JS is a problem? * > [...] > > The implementation of overloaded methods is of course problematic, and > the only justification I can see for it is in *perceived* API > simplicity. *Of course an API that has > > * * val(/*optional*/ any) /* if `any` supplied, sets the value to > `any`, otherwise returns current value. > > is not actually any simpler than one that has > > * * getVal() /* @returns Any. *Gets the current value. */ > * * setVal(any) /* @return undefined. *Sets the current value to > `any`. */ > Name 'getVal' is a contrived plastic example. Methods that are well- named, simple, self-documenting. Obviates the need for documentation. > In fact, it'ss arguably more complicated. *It's certainly harder to > document well. *But there is still some persistent feeling that the > API with the single function is cleaner. > Whose feeling? Can we stick to pros/cons? > My question is whether this vague and fuzzy feeling that the single- > functioned API is simpler could ever be enough of a reason for > complicating the implementation. *I'm entirely mixed on this. *I'm all > for complicating implementation to simplify an API. *But But an API to do what? what about > when the API isn't *really* any simpler? > > > [ ... ] > >> While I don't object to `getVal/setVal` a single function `val` > >> also seems all right. *Do you object? > > > Methods that do more than one thing are more complicated. > > Yes, but so are objects that do more than one thing. *The question is > whether that complication is ever justified. > Objects have more than one behavior. An object is a set of (hopefully well-named) properties and/or methods. Methods shouldn't. Take a panel, for example, might have "show" ahdn "hide". Now you could potentially make a method that does both: e.g. setDisplay(bShow); But what for? That just means that the API needs documentation, whereas someting like "show" -- do you get what that should do? With method overloading, as seen in jQuery, the approach is to try to figure out how to dynamically dispatch the desired behavior, and then do that in a dynamic environment (browser) where anything is expected to be passed in. It's the "setDisplay" on a grand scale, with host object, determination of string contents to dispatch behavior, all kinda thing. That's a terrible strategy for developing methods. Methods should know what type of parameter is going to being passed in. But especially in javascript where you have host objects of multiple environments, where typeof obj might be "object" in one env, "function" in another, "string" in yet another. And I can think of a couple of such methods that fit that criteria. Javascript methods that allow anything and everything to be passed in and then expect to be able to make determinations of what type it is, e.g. typeof it == 'object' fail on those expectations. Who remembers here when jQuery developers had problems with `typeof document.images`? Or the fighting of Safari childNodes crashes, "What is a Software Engineer" https://groups.google.com/group/comp...50886d0f?hl=en > > A get/set method, as you've described, does one of two things: 1) > > either return something or 2) have side effects are inherently more > > complex than methods that do one thing. > > > The SOLID principles, and I'm thinking of SRP now, can keep code > > clean, simple, easy to understand, predictable. *SRP is a good > > guideline for designing methods, generally. > > SRP is a guideline for designing class of objects, not for defining > libraries. * SRP is a design principle. It is for designing libraries. I suggest you do a little more research. Of course libraries can consist of classes that follow all > of the SOLID principles. *And there could be straightforward > extensions of the SOLID principles to library design, but I tend not > to use JS in a particularly object-oriented manner, so such > considerations are often of less importance to me. > Methods that do multiple things are inherently more complex and so harder to debug. And when the set of things being done is so complicated that it can't be explained, that's way off the deep end. That's the jQuery function. > > * * * * * * * * * * * * * * * * * ** * * * *For methods that perform > > operations that are is tricky, the trickiness more apparent and not > > obfuscated by API design decisions. > > I almost always prefer a clean API to a clean implementation. You can't have both? -- Garrett |
Re: jQuery Overloading Strategy -- What Not To Do
dhtml wrote:
> Scott Sauyet wrote: >> dhtml wrote: >>> Scott Sauyet wrote: >>>> Do you think all overloading in JS is a problem? * > [...] > >> The implementation of overloaded methods is of course problematic, and >> the only justification I can see for it is in *perceived* API >> simplicity. * >> [ ... ill-considered 'getVal'/'setVal' example removed ... ] > > Name 'getVal' is a contrived plastic example. Methods that are well- > named, simple, self-documenting. Obviates the need for documentation. Sorry, I wasn't thinking about it that way. I was thinking about jQuery's "val" function which is both an accessor and mutator for it's objects wrapping INPUT and SELECT elements. A cleaner example would be, say, `height`. It's certainly a debatable point as to whether the `setHeight`/ `getHeight` pair is more complicated than a single `height` function, but if nothing else, the latter has fewer symbols to remember. Perhaps it's slightly easier to learn with the `set/get` versions, but it's no easier to use, and the complexity of implementation is not significantly different. So my question was really whether you objected to that sort of overloading. Or perhaps even if you object as strenuously to that sort of overloading as you do to, say, the overloading of the main jQuery function. >> In fact, it'ss arguably more complicated. *It's certainly harder to >> document well. *But there is still some persistent feeling that the >> API with the single function is cleaner. > > Whose feeling? Can we stick to pros/cons? Mine. Why should I care about yours? :-) I really am talking about pros and cons. In one very naive way, it's almost tautological that an API with a single function is simpler than one with two functions. So there is at least one pro to an API that can be used this way: var r = new Rectangle(20, 10); alert(r.area()); // 200 r.height(15); alert(r.area()); // 300 alert(r.height()) // 15 over one that works like this: var r = new Rectangle(20, 10); alert(r.calculateArea()); // 200 r.setHeight(15); alert(r.calculateArea()); // 300 alert(r.getHeight()) // 15 Do you object to the single-function API? >> My question is whether this vague and fuzzy feeling that the single- >> functioned API is simpler could ever be enough of a reason for >> complicating the implementation. *I'm entirely mixed on this. *I'm all >> for complicating implementation to simplify an API. *But > > But an API to do what? Whatever. If I want to use an API to handle a certain facet of my system, I would rather have a simple API. If I want to read a file into a String using Ruby, it's as simple as text = File.read(file_name) In Java, I'd need to use about ten lines of code, invoking FileInputStreams, BufferedReaders, IOExceptions, StringBuilders, and so on. Ruby clearly has a simpler API for this. If I'm using an external API (even one I've written myself) in my code, I want the code using it to be as clear as possible, and that at the expense of how easy the API is to write. >>> Methods that do more than one thing are more complicated. > >> Yes, but so are objects that do more than one thing. *The question is >> whether that complication is ever justified. > > Objects have more than one behavior. An object is a set of (hopefully > well-named) properties and/or methods. Methods shouldn't. That's just restating your objection. Do you think overloading is never justified? > Take a panel, for example, might have "show" ahdn "hide". Now you > could potentially make a method that does both: > > e.g. setDisplay(bShow); > > But what for? That just means that the API needs documentation, > whereas someting like "show" -- do you get what that should do? Can `show` be animated? Do you need a parameter that describes what animation to use? How about the duration? And if it's animated, could I also supply a callback to run when it's done? If we have an API that uses `show` to handle a plain change to visibility, a simply animated one, or one that's animated with a followup callback, is this somehow more complicated than an API like this?: show() animatedShow("fadeIn", 600) animatedShowWithCallback("slideUp", 400, function() {doSomething();}) Yes, the implementation of a single "show" function to handle these possibilities is more difficult than any individual one of the above would be, but the total code is not likely to be much harder. This extended API is clearly more difficult to remember. I would argue that it's more difficult to use as well. > With method overloading, as seen in jQuery, the approach is to try to > figure out how to dynamically dispatch the desired behavior, and then > do that in a dynamic environment (browser) where anything is expected > to be passed in. It's the "setDisplay" on a grand scale, with host > object, determination of string contents to dispatch behavior, all > kinda thing. [ ... ] Yes, I really don't like that style. I think a great deal of jQuery's overloading is horrible. I just don't agree that all overloading is bad. > That's a terrible strategy for developing methods. *Methods should > know what type of parameter is going to being passed in. [ ... ] I have another case that I'm using a lot in my current project. var handleXYZ = function(param) { each(makeArray(param), function(item) { doSomething(item); }); }; I receive (from an external source) references that might be single elements of, say, Strings or might be an array of Strings. I write a single function to handle either case and use a `makeArray` function to handle them uniformly in my code. Would you suggest that I should have a separate `handleMultipleXYZs` function? Because the original source of these things is outside my control, using such would necessitate sprinkling `isArray` checks over all the code that calls these functions rather than centralizing it in the one function. Do you really object to that sort of overloading? > https://groups.google.com/group/comp...g/5392683d5088... One of the very first threads I read here! :-) >>> A get/set method, as you've described, does one of two things: 1) >>> either return something or 2) have side effects are inherently more >>> complex than methods that do one thing. > >>> The SOLID principles, and I'm thinking of SRP now, can keep code >>> clean, simple, easy to understand, predictable. *SRP is a good >>> guideline for designing methods, generally. > >> SRP is a guideline for designing class of objects, not for defining >> libraries. * > > SRP is a design principle. It is for designing libraries. I suggest > you do a little more research. Saying that an object should have a single responsibility does not carry over to the design of a library. I don't think it's easy to assign a single responsibility to C++'s Standard Template Library; there's just too much going on there. But the point is that a library is not an object. Yes, jQuery works with it's own objects which are essentially wrapped sets of DOM elements, but in the end, it's mostly a collection of functions that can run against such a wrapped collection. There would be little fundamental difference if these functions were stand-alone utilities that ran against arrays of DOM elements. In essence, don't try to think of the jQuery API as you would an object in an OO system; it's simply not that sort of interface. And a collection of functions does not necessarily have a single responsibility. >> [ ... ] > Methods that do multiple things are inherently more complex and so > harder to debug. But it's hard to draw the line between doing multiple things and doing one thing with multiple variations. > And when the set of things being done is so > complicated that it can't be explained, that's way off the deep end. > That's the jQuery function. [ ... ] ACK. >> I almost always prefer a clean API to a clean implementation. > > You can't have both? When you can, of course you should. But the two are often at odds. I will usually come down on the side of keeping the API cleaner and letting the implementation get uglier when necessary. Would you prefer the reverse? -- Scott |
| All times are GMT. The time now is 08:46 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.