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 ... <div id="divX"></div> <div id="divY"></div> <div id="divZ"></div> ...[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.
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
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 PageAnchors. 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?]
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.