Prev: FAQ Topic - Why does simple decimal arithmetic give strange results? (2010-03-31)
Next: Consolidate Credit Card Debt
From: nick on 1 Apr 2010 00:39 On Mar 31, 8:34 pm, David Mark <dmark.cins...(a)gmail.com> wrote: > nick wrote: > > > Cufon('h1')('h2')('h3'); > > It's completely ridiculous. And I mean that in the nicest possible way > (trying to save you some time here). Why? It seems pretty self-evident to me. Look at this code: myApp.keys.register ('w', panNorth) ('s', panSouth) ('a', panWest) ('d', panEast); // nearby... function panNorth(evt){/* ... */} function panSouth(evt){/* ... */} ... What else could it possibly be doing besides registering a bunch of key handlers? It works and it makes sense, so it's not entirely ridiculous. And, really, how is it any worse than something like this: myApp.keys.register([ ['w', panNorth], ['s', panSouth], ['a', panWest], ['d', panEast] ]); // nearby... function panNorth(evt){/* ... */} function panSouth(evt){/* ... */} This means the register function must be more complex, unless you want to register a single key handler like this: register([[key,func]]) So maybe there is a bit of overhead to the first method, but if you're just using it for a one-shot thing like registering key handlers or replacing fonts it seems to make plenty of sense.
From: Thomas 'PointedEars' Lahn on 1 Apr 2010 06:30 nick wrote: > David Mark wrote: >> nick wrote: >> > Cufon('h1')('h2')('h3'); >> >> It's completely ridiculous. And I mean that in the nicest possible way >> (trying to save you some time here). > > Why? It seems pretty self-evident to me. Look at this code: > > myApp.keys.register > ('w', panNorth) > ('s', panSouth) > ('a', panWest) > ('d', panEast); > > // nearby... > function panNorth(evt){/* ... */} > function panSouth(evt){/* ... */} > ... > > What else could it possibly be doing besides registering a bunch of > key handlers? It works and it makes sense, so it's not entirely > ridiculous. And, really, how is it any worse than something like this: > > myApp.keys.register([ > ['w', panNorth], > ['s', panSouth], > ['a', panWest], > ['d', panEast] > ]); > > // nearby... > function panNorth(evt){/* ... */} > function panSouth(evt){/* ... */} 1. It requires you to keep an external reference to the initial calling object as Richard has already explained. 2. Several function calls will be always more expensive than just one and the creation of an Array instance. BTW, few would consider spoiling the current execution context's namespace declaring functions when using Array initializers as anonymous function expressions would be readily available then. > This means the register function must be more complex, unless you want > to register a single key handler like this: register([[key,func]]) With the self-calling approach the register() method must be more complex instead; it must use a closure to work on the initial calling object when self-called. > So maybe there is a bit of overhead to the first method, but if you're > just using it for a one-shot thing like registering key handlers or > replacing fonts it seems to make plenty of sense. You don't know what you are talking about. Incidentally, not even the crappy jQuery promotes this ridiculous pattern, the chaining there goes $(...).method(...).method(...) instead (which is only slightly less inefficient, error-prone and hard to debug). PointedEars -- Danny Goodman's books are out of date and teach practices that are positively harmful for cross-browser scripting. -- Richard Cornford, cljs, <cife6q$253$1$8300dec7(a)news.demon.co.uk> (2004)
From: Richard Cornford on 1 Apr 2010 06:56 On Apr 1, 12:10 am, nick wrote: > On Mar 31, 7:53 am, Richard Cornford wrote: >> On Mar 31, 7:10 am, nick wrote: >> ... >>> I just discovered a weird side effect that I don't really >>> understand yet... I wanted a function to be able to chain >>> itself > >> That will not result easily comprehended code. The 'chaining' >> where an object is returned and methods called on that is poor >> enough when it comes to intelligibility but at least in that >> case you have the method names giving slight clues as to the >> process that is being undertaken. If you (and particularly >> habitually) start directly calling the return values of >> function calls in long chains there will be nothing left in >> the code making the calls that indicates what is going on; >> it will always be necessary to have familiarity with (all of) >> the functions being called in order to understand what is >> going on. > > Ah, but isn't this a subjective matter as well? There are subjective aspects to it (particularly the judgment), but it is not entirely subjective. Unfortunately the question often gets decided on a subjective basis; it is easy for me to understand so it must be easily understandable, where the individual is not considering what knowledge they are brining to their considerations that others may not be able to. The objective assessment would look at (only) the code itself and asses what could be learnt from that. (Obviously some foreknowledge must be assumed, like understanding javascript syntax, else attempting to understand javascript code is not a realistic expectation). > To me something like > this is easily understandable, if a bit esoteric: > > Cufon('h1')('h2')('h3'); Looking at this code itself we see a call to (what is assumed to be) a function, and then a call to whatever is returned from that first call, and then a call to whatever is returned from that. We might also observe a similarity in the arguments. That is all the information available in the code. In order to determine that this actually represents three calls to the same function it will be necessary to find the code for a - Cufon - definition, or the code for whatever function is assigned to - Cufon - at any given time. Otherwise (even if 'Cfon' were instead an Identifier that described what the function did) the nature/process of the second and third function calls remains unknown. It is not even hinted at by the code above, and that is an objective fact. >> In code authoring there are a range of possibilities when it >> comes to the comprehensibility of the code, ranging from the >> self-documenting (where variable/function/method names, and >> the use of such, pretty much state what is going on at any >> point) to the utterly obscure (or "elegant" as it is often >> called these days). Your plan seems to be aiming at the obscure. > > To the contrary, my plan aims at brevity I can see the brevity, but don't regard that as advantageous in itself. > and simplicity, That is a subjective judgment. I would not judge the above simpler than what follows. > both in the library itself and in the calling convention. As a general convention that is a frightening prospect. If you did this exclusively with functions that returned references to themselves then familiarity with the "library" might make this acceptable as then you would be able to assume that - x()()(); - represented a sequence of calls to - x -. But just one instance of a function that returned any other function and all instances of code like - x()()(); - start to need detailed examination before it can be understood. > While I agree that code like this may be less self-documenting, I would say approaching non-self-documenting. > it's also a lot less to type. Typing is a very overrated issue. Typing is not that difficult (having done so myself, it only takes an hour a day for a month to learn how to touch type (60+ words a minute)), and there are numerous tools and facilities of tools for aiding code entry (and even if some may need a little setting up, if code writing is your work (or even a significant pastime) the long term returns justify the initial effort). However, far more important than any assessment of the actual work involved in typing is the realisation that entering code is something you only do once, but reading code (with the intention of understanding it) is something that accompanies debugging, maintenance, modification and enhancement, and the appreciation that it is in maintenance that the majority of the software authoring expense lies. This is where it is important to attempt to step away from your own individual foreknowledge because there is no guarantee that someone maintaining code is going to have that same knowledge or appreciation of inner working of your code. You may know that the - Cufon - function returns a reference to itself, but the later maintainer won't know that until they have looked at, and understood - Cufon -. > Plus, as a user of the function, you can always choose not > to chain it... > > Cufon('h1'); > Cufon('h2'); > Cufon('h3'); Looking at this code, with exactly the same (absence of) understanding of the code that surrounds it, we again see three function calls, but here we can see good ground for expecting those to be three calls to the same function. There is information here that is absent from the previous example. Now replace - Cufon - with an identifier that makes an unambiguous statement about what the function does and maybe we don't even need to go an look at the function code in order to understand what this code (and the code shrouding it) is trying to do. <snip> >>> Anyway, the obvious fix is to avoid 'this' inside of >>> functions, > >> Solving the wrong problem. > > I'm not sure what you mean by that. The problem that you 'fixed' followed from the style you want to apply in using your code; the chained function calls. The correct problem to solve might be whatever it is that encourages you to attempt to adopt divergent programming styles that introduce new problems if adopted. > It solves the problem I was having, in that it allows my > script to function as intended. The problem it solved was > the one I meant to solve, maybe you meant it's the wrong > solution to the problem? If so, what do you consider the > right solution to be? No, I meant solving the wrong problem. Richard.
From: Dmitry A. Soshnikov on 1 Apr 2010 06:57 On Apr 1, 8:39 am, nick <nick...(a)fastmail.fm> wrote: [...] > > myApp.keys.register > ('w', panNorth) > ('s', panSouth) > ('a', panWest) > ('d', panEast); > Although it is less efficient by performance than passing an array, this approach seems to me quite elegant by code reuse. Dmitry.
From: nick on 1 Apr 2010 07:06
On Apr 1, 6:30 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de> wrote: > > 1. It requires you to keep an external reference to the initial calling > object as Richard has already explained. > What about arguments.callee? That's good enough for returning a reference to the same function. > 2. Several function calls will be always more expensive than just one and > the creation of an Array instance. Granted, but how much more expensive, and what's the tradeoff? If average joe web designer screws up the first example 25% less than the second, it might be worth those few extra milliseconds per page load. > > BTW, few would consider spoiling the current execution context's namespace > declaring functions when using Array initializers as anonymous function > expressions would be readily available then. > What? > > This means the register function must be more complex, unless you want > > to register a single key handler like this: register([[key,func]]) > > With the self-calling approach the register() method must be more complex > instead; it must use a closure to work on the initial calling object when > self-called. > this.register = function (key, onPress, onRelease) { if (!initted) init(); if (!onPress && !onRelease) me.unregister(key); callbacks[toCharCode(key)] = [onPress, onRelease]; return arguments.caller; } // or // this.register = function (key, onPress, onRelease) { if (!initted) init(); if (typeof key == 'array') { for (int i=key.length, i--;) (callbacks[toCharCode(key[i][0])] = [key[i][1], key[i][2]]) } else { if (!onPress && !onRelease) me.unregister(key); callbacks[toCharCode(key)] = [onPress, onRelease]; return arguments.caller; } } ....? > > So maybe there is a bit of overhead to the first method, but if you're > > just using it for a one-shot thing like registering key handlers or > > replacing fonts it seems to make plenty of sense. > > You don't know what you are talking about. Incidentally, not even the > crappy jQuery promotes this ridiculous pattern, the chaining there goes > $(...).method(...).method(...) instead (which is only slightly less > inefficient, error-prone and hard to debug). I don't know what you are talking about :) |