Continued from NodeJsAndHofDiscussion ---- Pseudo-code for an example OOP-based UI periodic refresh API implementing something similar to the "grid" of BradyBunchGridDiscussion: - t class timer { // base library class attrib period: real; // seconds between repeats method stop() {...} method onRun() {} // place-holder to be overridden, runs every period } class uiRefresher inherits timer { // refreshes a given UI element with content from URL attrib element; // HTML element ID, usually a DIV attrib url; // URL to refresh with method onRun() { // set the target element to the contents of the URL via DOM calls ... } } // sample usage x = new uiRefresher(period=1.0, element="DivX", url=myUrl01); y = new uiRefresher(period=2.5, element="DivY", url=myUrl02); z = new uiRefresher(period=2.0, element="DivZ", url="google.com"); ... if (someCondition) { x.stop(); // example stoppage } // HTML ...
... [I assume this is a work-in-progress? It's not yet executable JavaScript (nor executable anything), and I'd expect some discussion of what it's proving. -DavidMcLean] I believe that's a new requirement. It's demonstrating that it would be possible to get similar functionality via OOP if the base libraries supported such a class instead of the current HOF-based one it does. ["some discussion of what it's proving" is new-ish, although it's implicitly necessary since you don't intend to prove your original claim (reduced or equivalent complexity to the first-class function design). The desire for executable code - preferably executable JS - isn't new. As we've said already, to achieve executable JS, you are free to extend the libraries with object-accepting (or codestring-accepting, if you wish to argue for eval()) versions of the base functions, which will not be counted in our assessment. -DavidMcLean] I'm not understanding your point. Parsimony is not always the overriding goal; there are multiple goals involved in choosing a design, especially maintenance grokkability. (I suspect Eval would be relatively compact, but I won't entertain that further.) [Yes, parsimony isn't necessarily the overriding goal, but you originally claimed that an eval() approach would not have higher complexity than a first-class-function approach. I don't demand that you adhere to that claim, but if your goal differs, ''specify what it is'', and ''show how your code meets it''. -DavidMcLean] That depends on the specific situation (project). I cannot make that determination at this point. Project X may be better with objects, and project Y may be better with Eval. That is, SystemsAnalysis. [Then go ahead and do that. We already have a project here. Determine what'll work best with it, implement that in JavaScript (with a couple of wrappers around the standard library, if needed), and show us how it's best that way. -DavidMcLean] Is the above pseudo-code not clear enough? What needs to be fleshed out? [The above pseudo-code is not executable enough, nor is there any explanation of what it's proving. What's your goal here? How does this code meet it? -DavidMcLean] Sorry, I am not going to make an executable one anytime soon. Not sure it's even possible using what JS supplies (or doesn't), but I don't want to limit the discussion of timers to JS; it's too specific to focus on. I don't care about JS specifics, that's not the issue because the discussion shouldn't be language-specific nor UI-specific. And you already asked what the goal was; I gave the best answer I can. I will answer SPECIFIC questions about the above pseudo-code. If you don't have any specific questions, then I guess we are finished. * [Of course it's "even possible" using what JS supplies - even setting aside the trivial TuringComplete part, JS is an object-oriented language. You can implement things using objects in it. And I asked both what your goal ''is'' and how your code ''meets it''; the former was answered in a (reluctant, roundabout) sense, but you've made no attempt on the latter. -DavidMcLean] * You guys asked to see the OO version. I supplied one. That's your goal, not mine. And since you seem to know how to implement it, why don't ''you'' code it since ''you'' wanted it and ''you'' want it implemented. QED. Done! Shower then bed. * [We asked to see alternate versions, such as an OO version, because you claimed there would be equivalent or lower complexity than a first-class function version. Your goal should be to prove equivalent or lower complexity, but if you have some other goal you think more important, that's fine - just be clear about what it is and how your code meets it. -DavidMcLean] * Where did I claim "equivalent or lower complexity"? If I did it was a mistake. I did talk about more familiarity and grokkability to typical programmers since they already know OOP, but we don't have any way to "prove" how typical programmers will react to either design such that we are yet again stuck in an AnecdoteImpasse. - t * [On ArrayDeletionExample. The exact quote is "I don't believe EVAL is necessarily higher" - which implies equivalent or lower complexity, since those are the only three options - and that's when you were asked to demonstrate the claim by converting the code from first-class functions to an eval() approach. We're on OO now, of course. So, if you're not trying to show your OO version has equivalent or lower complexity, what ''are'' you showing? I'd assume it's to do with familiarity. How does your code demonstrate that property, relative to the original version? -DavidMcLean] * It's my estimate that programmers would find it more "natural" and familiar. Like I said above, I don't have any solid evidence to present; it's purely a judgement based on experience and observation. And likewise, you don't have any direct evidence for your view of programming mental handling of each either. * [Fair enough. Why not say that up-front, when I asked about the example's goal? -DavidMcLean] * I thought we had explored that issue in a heated way before ''in general'' with regard to what typical developers are familiar with versus HOF's. Perhaps it wasn't heated enough; I should have used more personal insults to make it more memorable. * [Or perhaps you should simply have specified what your example is intended to show, given that what you intend to show differs from what you originally claimed and were originally asked to prove. How exactly do you believe your presented solution would be more familiar to developers than the original, currently-working approach? What aspects afford greater familiarity? Also, your implementation as presented is incomplete - even if it were executable, it's still not solving the original problem, which involves an arbitrary number of simultaneous intervals, each of which must fire off an asynchronous request to populate its associated DOM element. Care to flesh out the remainder such that, were the code executable, it would actually have the same functionality as the original JS example? -DavidMcLean] * In my personal observation of the field, OOP is used roughly 50 to 1 per HOF's. In JS it's a bit more even, but often because the existing API's require them or are built more heavily around them. But few I know particularly like that approach. JS's oop is awkward and often hated in the field. I'm just calling it as I see it. If your eyes witness something different, so be it. I'm tired of arguing over that; it gets fucking old after 20 odd times. * [Is your rudeness necessary? It's certainly true that OO -- being an entire paradigm -- is used more often than higher-order functions -- a single language feature. That's not addressing my question, though: What aspects of ''this particular solution'' will afford greater familiarity than setTimeout(f, 30) would? Developers are extremely familiar with calling functions, and to do OO in JS you're already working with first-class functions anyway. Why would this be any more familiar? Also, your implementation as presented is incomplete - even if it were executable, it's still not solving the original problem, which involves an arbitrary number of simultaneous intervals, each of which must fire off an asynchronous request to populate its associated DOM element. Care to flesh out the remainder such that, were the code executable, it would actually have the same functionality as the original JS example? -DavidMcLean] * Because OOP sucks in JS, HOF's may actually be better in comparison ''in'' JS. What's better, a crippled bicycle or a top-of-the-line unicycle? * [You're mistaken. OOP doesn't suck in JS. It could certainly be a little more powerful -- IoLanguage adds MultipleInheritance to the model for example -- but it's hardly crippled. -DavidMcLean] * Okay, "crippled" was the wrong word. "Awkward" would be more appropriate, such as peddles toward the rear instead of beneath the seat. * [I suppose to a mild extent. The significant reduction in awkwardness compared to complex class-based models outweighs the awkwardnesses of JavaScript's own design in my mind, though. It's certainly not so horrendous as to make it not worthy of consideration. -DavidMcLean] * How are you measuring "complex"? * [Number of components. Prototype-based OO systems have only objects, which delegate to objects, which delegate to objects. Class-based OO has objects, which are instantiations of classes, which delegate to classes. Additionally, the latter implies you lose certain useful functionality, such as the ability to override a method on one specific instance, which some languages try to solve to avoid losing that power. RubyLanguage does so, for example, by adding a hidden "eigenclass" to every object instance which can hold per-instance methods (and therefore making the system even more complicated than pure prototypes would!). -DavidMcLean] * This is essentially the LISP argument all over again: most abstractions with the fewest language idioms. GreatLispWar redux. * [Sure, I guess so. Is that relevant? More idioms do imply more complexity, regardless of whether or not the added idioms are worth the added complexity. -DavidMcLean] * Languages best designed for the target audience are not necessarily the most parsimonious in a notational and expressive sense, based on my observation of the field. We are dealing with imperfect beings in the field. * [Reasonable, but again, is that relevant? I'd hardly claim JavaScript the most parsimonious of languages; what's your point got to do with the subject of discussion, exactly? -DavidMcLean] * How is fitting typical developer WetWare NOT relevant to selecting the most productive tool/language/design? That's the context I thought we were discussing. If there is another context, I missed it. * [Well, the context right here is a digression into "is JavaScript's OO crippled/awkward/otherwise uncool, and hence not good enough to provide an alternative to higher-order functions, therefore rendering JS not a good testing ground to compare the two options?". I'm saying it isn't. -DavidMcLean] Ponder this, how would ''you'' make a '''generic "timer" class'''? I don't really care about how it's implemented (unless it violates physics or POSIX or something). The implementation shouldn't matter because we are focusing on timer users, not writers (application authors, not SystemsSoftware authors). ''Personally, I'd probably define something like ''setTimeout(function, milliseconds)'' where ''function'' is a function, and ''milliseconds'' is the number of milliseconds to wait before ''function'' is invoked once. If I wanted it to be invoked every ''milliseconds'' milliseconds, I'd call it ''setInterval(function, milliseconds)''. That's about as generic as you can get. :-)'' No no no. The goal is to make an OOP interface to ''compare it to'' an FP and/or JS version. ''I know. It was a joke -- I described the DOM functions that are currently available.'' -------- '''Possible Enhancements''' Note that a fancier timer class may have a "start" method also for optional delayed starts. To keep the example simple, I'm assuming it starts automatically once it's instantiated. Another possible enhancement is a "repeats" attribute. If it's not set or zero or less, then it repeats forever (or until "stop" method called). [Self-call approach? What are you talking about? -DavidMcLean] Nevermind, I thought setInterval was relatively new such that it should be avoided to not risk browser version problems. But that's not the case. I removed mention of it. Anyhow, the OOP approach is better modularization in my opinion because it packages the 3 operations together: setTimeout (repeats=1;), setInterval(default or repeats is zero or null), and clearInteval(x.stop();) In JS they are floating around independently, which is '''anti-modularization'''. - t [Having all four (there's also clearTimeout(), which doesn't see much use but does also exist) in the global namespace rather than in some "timers" module is certainly anti-modularisation. I'd attribute that to the historical lack of a built-in module system in JS - a problem which has since been addressed using the "module pattern" and the introduction of a true module system in ECMAScript 6. The global namespace really isn't ''that'' polluted, of course:] $ node > Object.keys(this).length 34 * (FireFox gives me 430. FF-additions? - t) * [Ah, yes, client-side JS has rather more in the global namespace by default. It differs depending on where you look at it, since client-side scripts tend to add more names to the global namespace; on about:blank I get 184. (I just checked about:blank in Chrome and got ''seven''.) JavaScriptSucksInBrowsers definitely still applies to an extent. Tools like Browserify and RequireJs mitigate this particular issue, however. This is a digression, anyway - global namespace pollution is orthogonal to "OO versus first-class functions", since neither tool precludes the use of modules and related techniques. -DavidMcLean] [But certainly it'd be tidier to have timers.setTimeout() and such. I think I'd disagree with bundling setTimeout and setInterval into one "repeats"-configurable function for reasons of ZeroOneInfinity: It's overwhelmingly common to need either a single repeat or an indefinite number of repeats, yet quite rare to need any other specific number. If you do need to repeat n times, you can always use setInterval and a closed-over counter variable. -DavidMcLean] If we are making a generic timer, then I wouldn't feel confident assuming that a fixed number is uncommon. It's difficult to predict usage patterns up front. A possible use case: to avoid polling the networks overnight etc., we may want to limit the polling to a few hours so if somebody leaves their seat for the day or vacation, we don't keep taxing the network and server overnight. Yes, one can manually code such limits, but why not roll it into the existing interface? Well, that's my design choice if asked. - t [Hmm. setInterval() with a limit on maximum executions is certainly useful to have - conflating it with setTimeout() still seems conceptually messy to me, but if the functions were bundled up in a module rather than loose I suppose adding an extra would be reasonable. It's not exactly hard to implement it yourself, of course (for instance, below). -DavidMcLean] timers.setLimitedInterval = function(f, t, n) { var id, i = 0; return id = setInterval(function() { f(); if (++i >= n) clearInterval(id); }, t); }; Re "conflating", it would be interesting to take a poll to see if developers prefer to perceive them as two separate operations or merely a variation on the same thing. [True. Of course, conflating two things which are most appropriately viewed as variations on the same thing is precisely the right course of action ("conflating" doesn't necessarily mean "inappropriately conflating", after all). I'd argue that "repeat this indefinitely many times" is really quite different from "do this, later", just as loops and function calls are distinct, but I wouldn't go so far as to forbid a design that does conflate the "do once, later" and "repeat many times" facilities. -DavidMcLean] -------- For "Eval" versions of the JS functions, replace the "function" parameter with a string parameter, which is the code to be evaluated. [Yep, of course. That's easy to implement http://gigahard.mine.nu/~david/eval_timeout.js and might not even be necessary, since at least in some versions of JS the core timers can also accept a string of code. The question, however, isn't whether you ''can'' provide the same core functionality through another mechanism, but whether doing so can be as concise, clear, and flexible as the first-class function design. Thus, a simple "change the core libraries like so" statement isn't really sufficient; if you want to prove anything about the relative effectiveness of the possible interfaces, that demands ''use'' of each, such as by converting the actual original Brady Bunch example to an equivalent implementation using evaluated strings or object-oriented techniques rather than first-class functions. -DavidMcLean] Why don't you do it if you want to see it done? I'm highly skeptical it would resolve anything such that I am not motivated. [I'm already quite familiar with the weaknesses of evaluated-string approaches, as I noted a while back in TopOnAbstraction, and from those practical weaknesses I'm confident in asserting that the first-class function approach is a better solution for all such issues. You seem to think otherwise. Why ask me to prove your claim? Why not try to prove it yourself? You might succeed in convincing me, or you might learn something about those weaknesses firsthand. - DavidMcLean] Those situations appear to be rare blue-moon circumstances or an attempt reinvent RDBMS or OS's (BigIdea). I don't want to get into another "requirements frequency" debate. LetTheReaderDecide if those design patterns fit their own org or needs. (I personally believe you are committing the sin of PersonalChoiceElevatedToMoralImperative.) ''You mean use of exec() is "rare blue-moon circumstances or an attempt [to] reinvent RDBMS or OS's"? If that's your claim about HOFs then it must be, because HOFs can be used in virtually every case where evaluated-strings are used but without demonstrating any of the weaknesses of evaluated-string approaches.'' Learn to use PageAnchor''''''s. I have no idea what example you are referring to and don't understand why you expected I'd just be able to read your mind. ''I'm not referring to any particular example. I'm responding to your comment on "evaluated-string approaches", i.e., where you construct a string, pass it to the exec(), eval(), whatever-it-is function, and it executes the code in the string. It's a flawed technique; HOFs can accomplish the same thing in a TypeSafe fashion, with compile-time syntax checking, without having to invoke the interpreter/compiler on each execution, and without risking the errors or code injection (if external data is involved) that can occur when constructing a string at run-time for execution.'' But there are cases where they are dynamically generated (akin to QueryByExample perhaps) or stored in a database or a different sub-system outside of our run-time environment. I never claimed "Always use X instead of Y". HOF's have multiple competitors, and which is the best, ItDepends on the situation. URL's can be viewed as a kind of "Eval" string; they allow a wide variety of systems and devices to talk to each other. We can't compile the whole web. -t [First-class functions can be dynamically generated as readily as any other FirstClass value. Storing code you plan to execute outside your control is tremendously dangerous - if you're planning to run code from a database, you ''must'' take extreme precautions to ensure the code you get is safe. Whitelisting the code you plan to accept may be the only sure-fire method, and if you're doing that you may as well just store an identifier in the DB and use a dictionary to match it to the relevant code. URLs are exactly unlike to-be-evaluated codestrings: Most importantly, barring implementation bugs such as buffer overflow, a URL cannot execute arbitrary code and therefore does not admit to nearly as much security risk as strings of code do. -DavidMcLean] Can you demonstrate the first sentence? "Can be" says nothing about total resources used (machine/code/humans). And again again again, I'll consider such pros/cons on a case by case basis. [I can certainly demonstrate it. Indeed, the "Brady Bunch" example demonstrated it. You can create a new function just as you create any other value, with a literal - you can also use operators that combine existing functions, just as you'd use + to combine numbers. Here're a couple of JavaScript functions that generate functions dynamically:] // function composition: compose(f, g)(x) = f(g(x)) function compose(f, g) { return function() { return f(g.apply(null, arguments)); }; } // the classical "accumulator" function often used to show how closures work: function makeAccumulator(y0) { var y = y0; return function(x) { return y += x; }; } var a = makeAccumulator(5); console.log(a(1)); // prints 6 console.log(a(3)); // prints 9 [There's a "base set" of valuable function-transforming operators, which typically includes composition and PartialApplication; JavaScript comes with an implementation of the latter (Function.prototype.bind) and the former is easily implemented above or can be picked up from a utility library like Underscore. For the many operations that aren't ubiquitous enough to earn a place in such a library, manual implementation is hardly complicated, as you can see from the above demonstrations. -DavidMcLean] * I don't know what actual issue this is intended to solve. * [Nothing. It's just showing that functions can be constructed dynamically just as any other FirstClass value would be, as you requested; I haven't actually applied the transformers given to actual issues in the above example. However, composition often sees use in systems with a functional bent - HaskellLanguage prominently features it and encourages "point-free programming" based entirely on composition and other function-transformers, as does JayLanguage, and composition can often be cleaner than an inline function literal in JavaScript too. makeAccumulator() is almost entirely a toy, merely to demonstrate the way closures work; the behaviours it relies upon are of great value for a wide array of purposes, however, including the callbacks that form the basis for NodeJs, InternalIterator processing (for instance, the weather-data example on ArrayDeletionExample touches on the fact that particular functors can accumulate state internally, such as to average over more than two points), the "module pattern" as well as OO-with-private-members in JavaScript, and so on. -DavidMcLean] [If by "such pros/cons" you're referring to the security issues I raised, they absolutely should ''not'' be considered on a case-by-case basis. You can ''only'' guarantee that the code in the database is safe (without whitelisting it) if it's completely impossible for end-users to modify the code-related sections; that precludes you from offering certain features, such as "enter an expression to calculate this business logic", through eval(). It also demands your database be impregnable, requiring greater care to avoid SqlInjection and other such dangers. Finally, if users aren't allowed to modify the code, then there's fundamentally no difference between storing code and simply storing a function name or other identifier. Additionally, if your intent is CrossToolTypeAndObjectSharing, you ''can't'' put actual code in the database since it's hardly going to be cross-language-compatible; a function identifier by contrast can be handled appropriately by different tools on different platforms. -DavidMcLean] Ignoring "case by case basis" is a rather stubborn position. But anyhow, I prefer to focus on specific realistic scenarios rather than over-analyzing generalities. [Ignoring a case-by-case basis ''for security'' is a rather safe position. You can't look at each aspect of your solution and think "hmm, should this be secure or not?". You make it all secure. Always. And if you want to consider specific realistic scenarios, sure. Cite one specific realistic scenario for storing actual code snippets in a database. Let's see if it's really better handled with eval() than with alternate approaches. -DavidMcLean] We store source code in file systems, why is that "less evil" from a security standpoint than storing it in a database? I wish the two would merge myself. [It isn't. But storing source code in a file system or database that you ''let end-users write to'' very, very dangerous without taking the proper precautions. -DavidMcLean] Who said anything about end-users? [I did. Did you read my discussion of the security issues involved? -DavidMcLean] Yes, it's obtuse. Anyhow, I don't want to get into a debate about general security here. I'll consider each situation on it's own merits. If you don't like that, you don't have to hire me. Done. [Fine, then let's not touch on security. Setting aside any security questions, when would you want to store actual code snippets in a database? Why would doing this and then evaluating them with eval() be preferable to storing merely identifiers in the database? -DavidMcLean] I don't have an example largely because the reasons to use HOF's are also rare in my profession such that considering alternatives to something rare means that the chances to need to consider alternatives to it is likewise rare. [Then why argue against them and for alternatives, if you never need to use either? -DavidMcLean] GUI event and timers are perhaps a case where OOP and HOF's are competitors. I personally like the OOP versions over the HOF versions, in part because you have more options for packaging together related methods and attributes. (I've also considered XML-based GUI's, but that's another topic.) OOP has more initial syntax, but also provides the little class framework on which to build on. HOF's are kind of loners. [Sure, but why argue for one over the other if your need to use either is so rare you lack examples? -DavidMcLean] I didn't see GUI's in general in the original HOF bragging lists, but if you want to include GUI's, be my guest. However, I do not want to focus on any one particular programming language, except perhaps as an sample. If you want to talk ''just'' about JS clients, then I am not interested at this time because that's not a good "test" of GUI's in general. I don't disagree that using a JS-flavored GUI tool probably works better with JS; that's pretty much a no-brainer. [I'm speaking generally, not of GUIs. If in your experience the need to use higher-order functions, or an approximation such as DependencyInjection, is so rare that you have no examples to present when asked, why are you arguing against higher-order functions and for practically everything that sort of vaguely gives you the same functionality? What do you use any of these features for? If it's nothing, why argue for one approach over the other, given you have no way to know which works better? -DavidMcLean] You are '''overloading the developer's mental toolkit'''. Why have 4 kinds of monkey wrenches when 3 are good enough a vast majority of the time in a given shop/niche/domain? I believe AreWeBiasedTowardLaborIntensive is in play. ''I'm curious what evidence there is that a "developer's mental toolkit" can be overloaded, but if it does turn out to be an issue, I'm sure a domain-specific language -- intended for the domain that doesn't need a fourth "monkey wrench" -- would be appropriate. Of course, general-purpose programming is diverse and unspecific, so having a well-stuffed toolbox -- prepared for needs both common and rare -- is beneficial.'' I don't have any direct studies on such and you have no counter studies such that we only have anecdotes versus anecdotes. You should know this already; please stop reinventing that issue; your repetition is annoying and text-bloating. And remember it's not just the mind of ''one'' developer, but about average and typical teams or future maintenance developers. This risk/reward staffing situation to a business is explained in GreatLispWar. ''"Average and typical teams" are usually taught the languages they use. Typical language education teaches all the features of the languages they teach. Thus, "average and typical teams" will know how to use "4 kinds of monkey wrenches" if the languages they use have "4 kinds of monkey wrenches". Therefore, since modern languages support HigherOrderFunctions, it is logical to conclude that "average and typical teams" will use HigherOrderFunctions -- if not today, they certainly will when "average and typical teams" have been taught to program in language implementations that support HigherOrderFunctions.'' I disagree. We've had this discussion already somewhere, I just don't remember where. Developers in the field, as I see it, come from diverse backgrounds and degrees, and often valued for their domain knowledge or people skills as much as any technical ability. ''End-user computing, especially where computing is its primary function -- data entry and reporting, usually -- frequently favours domain knowledge and people skills over technical skills, because the technical challenges are fairly minimal compared to the business and political challenges. As the technical challenges grow -- for whatever reason -- the more programmers educated in SoftwareEngineering and/or ComputerScience tend to be hired.'' I generally agree, but we probably disagree where the tipping point is where an organization is better off switching from mid-brow programming to high-brow programming. It's rare for candidates to be masters of all three of technical issues, domain issues, and people/communication issues such that hirees tend to be a compromise between these. Even if they find one in a particular situation, they cannot depend on the followup person to be of such caliber when the original lucky find leaves. They have to target average, not "lucky". ''In some organisations, average is "hard-core Haskell hacker". In other organisations, average is "can slowly edit a spreadsheet as long as the formulae are simple and there are no macros."'' Okay, we agree ItDepends.