This is an example derived from discussion in ArrayDeletionExample, intended to show a generic HOF UseCase.
Imagine we have a complex, difficult-to-partition algorithm or process -- let's call it complexCustomisableAlgorithm (see below) -- which requires some context-dependent customisation. The canonical example is a sort algorithm -- the comparison function needs to be customised depending on the data types we need to sort -- but the same approach is applicable to a variety of situations.
In a business context, complexCustomisableAlgorithm might be, say, employee scheduling. The part needing customisation might be the part that determines whether a given employee can fulfil a given time slot. It's customisable because we might have a variety of different kinds of employees, time slots, and constraints that determine whether or not a given employee can work a given time slot.
// In this example, customisableBit is a function.
//
// Alternatively, it could have been a string representing
// some snippet of code to be EVAL'd, but then it would have
// to be syntax-checked and/or compiled n1 * n2 times.
// Do we really want to be performing O(n^2) worth of syntax checks
// and/or compilations if we don't have to?
//
function complexCustomisableAlgorithm(customisableBit) {
...complex but non-changing stuff...
for (i=0; i<n1; i++) {
for (j=0; j<n2; j++) {
customisableBit(i, j, somedata)
},
},
...complex but non-changing stuff...
},
// Here's a single implementation of the customisable bit
function customisedBit(x, y, data) {
...customised bit...
},
// Invoke a single customisation like this:
complexCustomisableAlgorithm(customisedBit)
Now what if we need to customise based on some dynamic data, i.e., we require a data-dependent series of customisations? (In a business context, this might mean (for example) generating a set of schedules, each one varying in some tuning parameter.) So, we need a HOF that returns a function. Like this:
// Return a customised (i.e., dependent on p and q) function
function customisedBitMaker(p, q) {
return function(x, y, data) {
...customised bit that needs x, y, data, p and q...
},
},
// Create and invoke them like this:
for (int p=0; p<q; p++) {
customisedFunction = customisedBitMaker(p, q)
complexCustomisableAlgorithm(customisedFunction)
},
Re:"Do we really want to be performing O(n^2) worth of syntax checks and/or compilations if we don't have to?"
Machine labor is usually far cheaper than human labor. And an EVAL version may be easier to "X-ray" to debug and log.
You appear to be stating that you believe the generation of a function inside a function to require more expensive developers than not generating a function inside a function, and that debuggers break when they encounter higher-order functions. Is that what you believe?
-
I don't think they have to be nested, but it's hard to know without knowing what you are trying to achieve. In other words, I'd have to look at the business requirements, not just mirror your specific implementation because my solution may not be one-to-one replacing Evals per each HOF. For example, there may be an interative approach comparable to how one can traverse a tree using interation and "link marking" instead of recursion. -t
-
You haven't answered my question. The requirements are precisely those stated above. Why would iteration be needed? What would you gain by using it?
-
No, they are not "precisely stated". "Difficult-to-partition", "context-dependent", "complex algorithm" have not been defined. Perhaps they are "difficult to partition" because you are doing something ELSE the hard way. Unless your claim is that HOF's are better for cleaning up existing HOF-messes. Our job is to make tools to solve real-world domain problems. In order to evaluate the value of the tool, it has to ultimately be compared against the real-world domain problem itself. Seeing only an intermediate piece is not sufficient. You may be trying to optimize for a rocket engine in a car when in fact a rocket engine is not the best engine for a car to begin with.
-
"Difficult-to-partition" is shown by example -- in the above, the customisable portion appears inside double nested loops. "Context-dependent" and "complex algorithm" are both treated as given, but if examples help, think "comparison function" and "sort algorithm", respectively. The C standard library's qsort function is a good demonstration of a non-HOF (but almost-HOF) similar solution to the same requirement.
-
You still have not answered my original question, so again: Do you believe the generation of a function inside a function to require more expensive developers than not generating a function inside a function? I.e., do you believe HOFs are continuously and irrecoverably "hard to understand" and therefore require specialist developers? Do you believe debuggers break when they encounter higher-order functions or that higher-order functions are more difficult to debug than alternatives?
-
Let's finish the forest before we focus on trees. What's a sample business need for this contraption? I'm not going to offer a solution until I understand the nature of the problem. I'm not going to try to compete with mere lab toys. (For one, it smells of unrealistic regularity in interfaces.) I will solve a business problem if you present a business problem. The above is an implementation of who knows what. The above is not a statement of needs.
-
Search the original text for "business context" to discover a business problem it solves.
-
Sorry, I don't see anything specific. If you want to illustrate a scheduling system, then describe the nature of the business, such as how many employees, How shifts are specified, who specifies shifts, what kind of UI is exceptable to them based on their education, etc. This would often include samples of the planning papers used for the manual version (or prior technique used). Is there a priority system, such as seniority-first, etc. This is one area I don't have a lot of coding/design experience in, by the way, other than seeing a few in action.
-
"complexCustomisableAlgorithm might be, say, employee scheduling." And indeed it might. Have you ever worked on employee scheduling? This shows an approach by which a generic scheduling algorithm can have a specific fitness function -- the bit that determines whether an employee can fulfil a particular slot, or whether an employee is best suited to fulfil a particular slot, or whether some other 'x' can fit 'y' in a schedule -- injected into it. This permits separation of scheduling algorithms -- of which there may be several and which may (and should) be generic -- from specific fitness functions. The example of customisedBitMaker() illustrates how trial schedules may be generated with varying parameters, so that the generated schedules can be statistically or manually evaluated later and the "best" one selected. Use of HOFs (or equivalent techniques) permit a high degree of decoupling, which makes it possible to disregard "the nature of the business, such as how many employees, How shifts are specified, who specifies shifts, what kind of UI is exceptable to them based on their education, etc." when implementing the scheduling algorithms and instead parameterise these for the users to define and select. The underlying scheduling algorithm -- and I must emphasise this -- is generic. It is a constraint solver; it doesn't care what the constraints are, nor should it. Not even the developer needs to care. That's for the user to decide, and the results of those decisions become (mostly) user-defined factors in the fitness function (the bit which is injected into the generic scheduler) but are of no concern anywhere else.
-
Why is it just Boolean? What about weights? But in the real world often other messy rules come into play, such as "Management promised person X extra priority on Tuesdays if he answers more than 30 customer calls and Lisa is not working that day". I doubt we can just plug in some generic routine to handle all constraint problems unless the kit becomes a language in itself.
-
It can be weighted instead of boolean; the above is just a generic illustration of the UseCase for HOFs. In scheduling, all the "messy rules" go into the fitness functions, which can be arbitrarily complex. The nice thing is that the scheduling algorithm itself remains generic and unchangingly independent of changes to the fitness functions.
-
-
Now then, do you believe HOFs are continuously and irrecoverably "hard to understand" and therefore require specialist developers? Do you believe debuggers break when they encounter higher-order functions or that higher-order functions are more difficult to debug than alternatives?
-
My experience is that strings are usually easier to debug than pointers, and info in intermediate work-tables is easier to debug than something that runs only in memory because we can search, sort, filter, group, etc. all that intermediate info which is difficult to do in a debugger unless it violates GreencoddsTenthRuleOfProgramming.
-
I can't imagine why you'd be seeing any pointers. What debuggers have you been using? Sounds like they lack the usual inspection capabilities that I'd expect of Eclipse, Visual Studio, and so forth.
-
It just dumps arrays etc. in some default presentation.
-
PHP? Have you tried xdebug? http://xdebug.org/
-
And what if power users want to tweak intermediate results? Who is managing these "fitness functions" anyhow? Who changes them? Where are they stored? What if most of it can be define parametrically instead of via functions such that the schedule managers don't need to specify functions?
-
How the fitness functions are stored, retrieved, who manages them and what the fitness functions do or how they do it is up to the implementation. Even if the user's view is a collection of parameters, from an implementation point of view the user's parameters will be processed in a fitness function. In terms of this pattern, that's all irrelevant -- as long as the functions return correct values and accept the correct parameters, they'll work. What goes on inside them is a black box. HOFs provide a way of generating and injecting these black boxes into another black box -- the scheduling algorithm implementation.
-
It it's truly easy to package up scheduling optimization using relatively simple interfaces, then it would be packaged into a commercial or general product by now and thus no longer be CUSTOM business software. The domain- or shop-specific aspects are what tends to be left over after easy-to-define "generic" services are factored into mass-market or generic products. Either you found one of the few untamed niches of such tools, our there are complexities that you are not seeing. I don't know enough about scheduling to help identify what you are missing. Perhaps I have not encountered it much because it's already done with purchased software. I once worked for a place that had a big customer call center, but I never got a chance to see what scheduling software they used for the staff. --top
-
What is shown here is a general pattern using HOFs to solve a category of problems. It is not an employee scheduling system, though it could be used as the basis for one. Employee scheduling is only one example of the utility of this pattern in a business context. You can almost always wave away a development problem by saying it's already available as commercial off-the-shelf software, but how did the vendor develop it so it could be put on the shelf? They probably used this pattern. Furthermore, even if the scheduling software is available off-the-shelf, this pattern might well apply: You purchase the implementation of the scheduling algorithm, but it's up to you to write the fitness functions that are appropriate to your business and inject them into the commercial scheduling algorithm implementation as shown above.
-
As for your not encountering scheduling because it's already done with purchased software, that's quite possible -- your company might well have purchased your scheduling software from my company.
-
Packaged Business Software is generally different than Custom Business Software. I won't make many claims or provide many anecdotes about packaged biz-ware from the developer side because I have never worked in that domain. However, I do notice that more and more packaged biz-ware comes with rule-building GUI's (RuleBuilderInface) to build rules so that power-users can manage the rules instead of (mostly) programmers. If it uses HOF's under the hood, the users may never even see, know, or care. -t
-
True, but rule-builders and user-defined expressions are orthogonal to HOFs. I know of no circumstance where a programmer's choice would be, "do we use HOFs, or do we use a 'rule builder'?" In fact, the two can be complementary. If HOFs are used as shown above to inject functions into a predefined algorithm, it's entirely reasonable for those functions to be evaluating rules loaded from a database.
-
Again, I'd have to look at specific requirements and what is typically done for such apps. I don't have any significant experience with automated scheduling algorithms and thus have no feel for say if there are a few popular algorithms used 98% of the time, or if there is a plethora that change often. Change management (maintenance) is probably a key issue. Without having or stating the reasons for given a ChangePattern(s), it's difficult to evaluate HOF's in terms of change versus say Eval or switch/case statements on "algorithm type" or finer-grained if/else on sub-algorithms or a RuleBuilderInterface or a combo, etc. -t
-
I often find that there are patterns in such algorithms such that a long switch/case list is not the best approach. HOF's are too big of a granularity of biz logic. Thus, nested IF's are usually better factoring (VariationsTendTowardCartesianProduct). It's a bit more difficult to do such factoring with HOF's because some kind of shared library must also be referenced or attached if we have shared sub-elements, mucking up the self-standing-unit ideal behind HOF's. Sometimes "soft walls" are more flexible and/or less e-bureaucracy. Like I said before, SeparationOfConcerns is often a myth or excessively ideal in the custom biz world. -t
-
What does "HOF's [sic] are too big of a granularity of biz logic" mean? Could you illustrate how you would replace the JavaScript-ish HOF-based code above with nested IFs? What do you mean by "[i]t's a bit more difficult to do such factoring with HOF's because some kind of shared library must also be referenced or attached if we have shared sub-elements, mucking up the self-standing-unit ideal behind HOF's?" Can you illustrate with an example?
-
Do you agree that it's fairly likely that a given non-trivial set of HOF's will need to share some common logic if we want reasonable duplication factoring? -t
-
Of course. HOFs can share common logic, just like any other functions in a given application or library. They're special only in accepting or returning functions, otherwise they are the same as any other function.
-
-
As for "SeparationOfConcerns is often a myth or excessively ideal in the custom biz world", if you avoid object-orientation, higher-order functions, and functional programming, how do you know whether SeparationOfConcerns is genuinely a myth, or merely a personal impression that results of avoiding tools and approaches that make SeparationOfConcerns possible?
-
It could be. I haven't found a way to make them clearly improve custom biz apps despite looking for such. IF YOU SHOW A NICE EXAMPLE of them making representative code from my niche easier to write/maintain, I JUST MAY CHANGE MY MIND. I may go, "Wow! look at that; it's reducing the number of places in the code I have to change for typical change requests, and without other downsides! I can count and see the reduction! 1...2...3...etc." I could highlight a code printout, maybe create a spreadsheet comparing the counts, and go up to a colleague and show them an objective and meaningful measurement of HOF's improving life. Is this possible, or only a pipe dream (no pun int.)?
-
I think my JavaScript example on ArrayDeletionExample is a good illustration of how you can do something in a few lines with HOFs -- code that will remain constant regardless of the number of divs to be updated -- that would be quite awkward and potentially take many lines of duplicated code without HOFs. A business-oriented example of precisely the same idea is automated stock buy/sell handling. Imagine that each "div" represents a stock. Instead of displaying divs, imagine that the code had to make a buy/sell/hold decision for each stock and do so asynchronously.
-
What's wrong with a ControlTable of processes to launch, similar to schedulers built into OS's? You said, "Oy Vey" or the like the last time I suggested it. Example layout:
table: scheduler
-----------------
title
processString // command or Eval string
processType // indicates whether a command-line or functional call via Eval
timerType // hourly, weekly, Nth x-day of the month, etc.
timerParameter1 // time, day, etc.
timerParameter2 // 2nd parameter, depends on the timer type
logResults // TRUE if logging process output
problemNofify // eMail addresses to notify if problems (optional)
finishNotify // eMail addresses to notify when finished (optional)
-
We can get fancier by chaining processes, limiting process time, etc. of course, but I'll stick with YagNi for now. Some may argue to have a different table for each "timer type", but this topic is not about table layouts.
-
You broke the YagNi barrier as soon as you wrote "... a ControlTable". Why the overhead of a ControlTable if it isn't needed?
-
Usually one is already using a database for a custom biz app such that one more table is an insignificant addition. Besides, one can use old-fashioned arrays if they really want a low machine profile. It's just easier to have all the standard DatabaseVerbs if somebody wants to search, sort, sift schedules or logs or what-not (and potential concurrency management if two+ people will be modifying schedules). Whether to use RDBMS tables or something else depends on the situation. That's where SystemsAnalysis comes in: Who, what, where, when, why, and how many.
-
By the way, watch out for that "command" you're passing to processString. That "command" might be considered a parameterless function... :-)
-
Not sure what you are getting at. "processType" indicates what it is. I adjusted the description to make that clearer.
-
What I'm getting at is that your "command" is essentially a function. You're passing functions to your "scheduler". Your "scheduler" is essentially a higher-order function, because it executes the "functions" that are passed to it via the 'processString' "parameter".
-
Oh oh, I smell LaynesLaw around the corner. "Eval" expressions would also be HOF's by that reasoning.
-
No, but you're coming close to something -- in a rather awkward way -- that could be simplified by HOFs. Of course, there are numerous places where it simply wouldn't be reasonable for your ControlTable to exist -- on the client-side, for example, which might be JavaScript or a lightweight mobile app.
-
But that's a case of "if you are stuck using such and such a tool due to legacy issues, then...". The business need is no longer the primary guiding factor (bottleneck), but specific equipment or tools dictated by the situation. Often one doesn't need a lot of JavaScript for internal applications I've found. Excess JS is a maintenance headache because it's a lot of tweaking to get the desktop-like feel that bosses want such that it becomes spaghetti code and more importantly, browser brand/version-specific. If one thinks about the design a bit more, often there is a JS-lite or JS-free way to do almost the same. One can use the HEAD/meta-refresh tags to make a page auto-refresh, for example, to display dynamic sales stats or what-not. And you can make independent sub-windows with different refresh rates similar to your demo using IFRAME and/or FRAMESET. No need for JavaScript. K.I.S.S. -t
-
Remember, JavaScript is just an illustrative example. HOFs are a facility that allow HofPattern to be easily implemented wherever it is warranted and HOFs are available. Yes, you can always find alternatives to using HOFs -- much of the history of custom business application development has taken place without them -- but that's no reason not to provide them. All things being equal, it's clear that code with HOFs is simpler and clearer than code without, as shown in my JavaScript example on the ArrayDeletionExample page. But, again, that's just an illustration. It applies equally to any other language that supports HOFs.
-
You keep claiming that, but you don't SHOW it from a business perspective in any clear way. You need to put in the context of a realistic custom biz app, and you need to show what is being measured/counted to claim "clearer and simpler". You were pushing ever toward a specific machine environment(s) to make your point, but now you seem to be backing away from that. If we are going in circles again, then perhaps it's time to take a break.
-
I have shown it, repeatedly, through the JavaScript example on ArrayDeletionExample and subsequent discussion. See the HOF code and the non-HOF code that immediately follows it? The distinction couldn't be clearer. I have shown it, repeatedly, through the JavaScript example above and subsequent discussion.
-
Please PageAnchor it. That's a long topic.
-
Why do you think I'm "pushing ever toward a specific machine environment"? Is it because I used JavaScript? I used JavaScript because it's highly readable, familiar to most developers and it supports HOFs, so it clearly illustrates the sort of thing that business application developers, targeting the Web -- as most now do -- develop on a daily basis.
-
You haven't described the biz need. I've described how to display independently updating windows without JS using HEAD meta tags and IFRAME or FRAMESET, if that's what you are "selling". (If you want actual HTML, please let me know.)
-
I haven't described the "biz need" for what? On the ArrayDeletionExample I explained, twice, that "I was tasked to address the situation where a large number of divs need to be updated asynchronously using AJAX so neither the page nor some large portion thereof need to be bulk-reloaded, and that's what I came up with. It could as easily be something to display live stock portfolio updates, or monitor live status of sales points in a retail store, or keep track of live shelf loading in a warehouse, balances of accounts in something, whatever. Etc." A HEAD meta tag on the whole page forces a whole page reload. IFRAME is only considered transitional in HTML5, and therefore deprecated; FRAMESET is obsolete in HTML5.
-
Browsers will have to support it. There's too much legacy stuff. And HTML5 allegedly offers a replacement, but we won't know until it's ready for prime-time. The page header (perhaps DOCTYPE) of an HTML page will allegedly be able to describe which standard to use to render. But this is exactly why I don't want to get into GUI nitty-gritty; this debate shouldn't be about client-side hardware/versions. Can't you please find a non-GUI demonstration scenario?
-
And new browsers may "break" your JS stack also. There's no guarantees in client-land.
-
Re: "A HEAD meta tag on the whole page forces a whole page reload." - Not if using frames. Each frame "page" can have an independent HEAD tag each with its own interval. You may say that requires "lots of web pages", but usually such is dynamically rendered in my experience; thus each frame would call the same (or a few) virtual pages with URL parameters given. For example, the sub-window variations might be:
Window 1A:
sales_stats.php?time_range=month&sort=location&report_type=compact&etc=1234
Window 1B:
sales_stats.php?time_range=day&sort=location&report_type=compact&etc=1234
Window 1C:
sales_stats.php?time_range=day&sort=location&report_type=detail&etc=1234
Window 2A:
sales_stats.php?time_range=month&sort=product&report_type=compact&etc=1234
Etc...
-
Now granted, there is a glitch in this approach in that HEAD refreshes cause the browser to make a clicking sound in some versions of Windows. It can be turned off by fiddling with with OS sound settings. This is a sufficient fix for a small group of users, but wouldn't be for a larger one. If we need to switch to JavaScript to avoid the clicking, then so be it. But I don't think the JS has to be as verbose/repetitious as you gave in your "alternative", but I'd have to experiment to prove it. But again, I want to get away from UI-heavy scenarios for the "HOF challenge" because it just turns into a low-level platform-specific techie fiddling session. (The browser environment is a fricken mess that needs a total overhaul in my opinion because bosses/users want desktop-like UI features, which HTML wasn't originally designed for; but that's another rant: LimitsOfHtmlStack)
-
What do you gain by avoiding HOFs, as you've done above?
-
In this case (assuming clicking isn't a problem), simplicity and reduced need for client-side scripting. JS tends to crash or cause versioning headaches, and is hard to debug on multiple platforms.
-
Clicking, unless you've got client-side machines without speakers, would almost inevitably be a show-stopper. As for simplicity, your solution is actually more complex. You've either got to rely on the code that generates the content for each panel to provide the appropriate HTML headers, or you've got to have separate code to generate the appropriate HTML headers and embed the content. The JavaScript solution requires neither, and the code is trivially simple. JavaScript may have once been unstable and caused versioning issues, but any popular browser released since IE5 has been stable and supported AJAX. JavaScript is now virtually ubiquitous -- and successfully so -- in dynamic Web sites.
-
I find JS-centric sites that I use tend to be unstable and rickety in both IE and FireFox. Yes, the programmers are probably "doing it wrong", but a technology that humans keep getting wrong should be avoided if decent alternatives exist. HTML-centric sites tend to "degrade" better (limp instead of die). If JS is the pinnacle of UI technology, then give me a damned ENIAC! (See below about timers-done-right.) Anyhow, this is turning into a battle over client and UI-centric technology, which shouldn't be the crux of the original premise.
-
AJAX-driven sites are not necessarily "JS-centric", and usually aren't because the very essence of AJAX is interacting with the server asynchronously -- and therefore relying on server-side code. But, you're right, this discussion doesn't belong here.
Are you looping through each possibility? What if the problem is too big such that we want to use a genetic algorithm?
No problem. Exactly the same approach applies. I have developed GA-based schedulers using precisely this idiom.
And the fitness calculation may require indexes/lookups to be sufficiency efficient. Pre-processing certain steps in aggregate may also make certain calculations more efficient. The assumption of an isolated calculation function may keep us from using Economies of Scale such as pre-sorting or pre-aggregating. It may be one of those "assume a spherical cow" moment. SeparationOfConcerns is often a myth or excessively ideal in the biz world.
It's perfectly reasonable for the scheduling algorithm implementation to pass (possibly mutable) data about the state of the scheduling process to the fitness function via a parameter. The 'somedata' argument in the code above is intended to illustrate that.
Achieving better SeparationOfConcerns in the face of problem complexity are what facilities like HOFs help us achieve. Indeed, much of programming -- and advances in programming techniques -- are about achieving looser coupling, tighter cohesion, and better SeparationOfConcerns.
I'm not sure why Eval expressions are out of the question performance-wise. A page full of independent sub-panels (Brady-Bunch-opening-style) isn't going to tax Eval processing. As far as I can tell, JavaScript's built-in DOM timer requires a HOF, and so we are stuck with that no matter what. But that doesn't mean we cannot manage specific processes using some other way, such as Eval expressions.
It may not be efficient to have a timer process for every panel under ANY approach, but rather go with a timer process (thread?) for each interval. For example, suppose we create one timer process each for the refresh intervals of 0.5, 1, 2, 4, 8, and 16 seconds. Thus, any new panel will be assigned to one of these six intervals, and any given interval may have multiple processes assigned to it. (There are different ways to allocate panels, but I'm fairly arbitrarily choosing a simple one for illustration purposes. The names chosen for panels here fit spreadsheet cell referencing conventions.)
This can be implemented by having 6 arrays for each interval. Adding a new panel could resemble:
// Add a new panel (pseudo-code)
// Parameters: panel ID, expression (for Eval), and the timer interval name
documentX.addPanel("B8", "foo(123);", "eight");
This would assign panel B8 the process of "foo(123)" to re-execute every 8 seconds so that the process for panel B8 gets executed every 8 seconds.
"addPanel()" would put the string and panel ID into a table-like array called "intervalEight":
intervalEight[rowID]['target'] = panelID; // B8 in this case
intervalEight[rowID]['expressn'] = evalExpressn; // "foo(123)" in this case
Every eight seconds, the eight-second timer process loops thru the "intervalEight" array and does an Eval on each expression and replaces the panel (a DIV or a frame) with the resulting HTML contents.
If 5 panels use eight-second intervals, then five Eval's are executed during each cycle. I don't see why this would be a resource problem. For our shortest interval, the half-second cycle, if we had 5 panels under this, then that's still 10 eval's every second, which is nothing to write home about still. If we have 5 panels each in all six interval categories, then that comes to about 25 eval's a second (and a rather crowded screen with 30 cells). If we had say 500 Eval's per second, then we are risking resource problems, but I don't see anything approaching even 100 per second for this kind of app unless something really unusual is being done.
It's probably not as efficient as using HOF's to "register" each process, but I don't see it being a bottleneck for a panel refresher browser-based app. If it needed video-game-like refresh rates, then we may have issues. But in that case, an org would probably want desktop applications and hire a video-game developer or the like, not a generic custom biz app developer.
This is not necessarily saying that using Eval is superior, but it appears to be a competitive alternative for the multi-updating-panel situation.
Assuming we don't consider the battery-power and CPU constraints of mobile devices -- for which any avoidance of processor-heavy compilation and/or syntax checking (which eval must do) is considered beneficial -- what do you gain by doing the above as opposed to the HOF-based approach?
Also, what do you gain by assigning '"foo(123);"' to some variable 'expressn' -- presumably to be executed later via eval(expressn) -- as opposed to assigning it 'function() {foo(123)},' and executing it as expressn()?
Not much here. I never claimed Eval (or other competitor techniques) were always a significant improvement over HOF's. Please review the initial claim in the chain. But I would point that mobile devices usually don't have room for 50 cells on their screens unless you are using micro-fonts. (I doubt they have the bandwidth to pull info from that many sources quickly anyhow.)
Why are you assuming the display is textual? It can easily consist of coloured graphs and the like. Mobile monitoring dashboards are increasingly popular, and whilst every effort is made to minimise bandwidth consumption by reducing over-the-wire data transmission, the value of having live monitoring is generally considered to be worth the cost of 3G/4G/WiFi.
Evals do have the advantage of being easy to display as text during debugging, and storing in cross-language tools, such as a database. The requirement didn't come up here, but it's one of those things that depends on the org's or app's particular details.
HOFs have the advantage of being source code, and thus are easy to display as text even during development. During debugging, they are no more difficult to debug than any other function. As for storing in cross-language tools, such as a database, that's almost never a requirement, though I've shown it can be done at http://dbappbuilder.sourceforge.net/docs/AnonymousAndFirstClassOperatorsInTutorialD.pdf Most end-user requirements demand data in the database; code is for the developers to worry about.
I already agreed during the "weather example" that there are occasionally times where hardware may make the difference in technique choice (although weather wasn't a biz app). In this case, you seem to be pushing for an extreme example in order "force" a hardware-centric requirement. Yes, if A happens and B happens and C happens at the same time, then it may make HOF's the clear winner. But nobody is looking for blue-moon exceptions to the rule because we all agree they exist. And HOF's have their own blue-moon problems. Thus, we have cases where HOF's run into problems, cases where both HOF's and Evals work just fine, and cases where Eval's won't work. (There are also non-Eval competitors to HOF's, as a reminder.) There frequency where only HOF's are a decent choice in biz apps appears to be rare, and your chosen scenarios don't seem to be making a good case that they are not rare. -t
HofPattern actually shows up frequently. Its apparent rarity is only because among the popular languages typically used in business application development, only JavaScript explicitly supports HOFs, so most programmers inevitably think in terms of alternatives rather than even considering HOFs. Of course, ObjectOriented languages often support creating FunctorObjects -- either explicitly or implicitly -- or trivially allow passing an object (and, therefore its associated methods) to some algorithm, and these are obviously used extensively in modern application development. It's only a matter of time before more languages will explicitly support HigherOrderFunctions -- this is inevitable -- which will result in the majority of developers recognising their efficacy.
You keep claiming "it" shows up frequently, but cannot seem to find very good examples, instead pushing into environment-centric restrictions. A decent GUI tool would give us better timer choices. This example is a slave to limitations/issues of the client-side environment, not about organizing custom business application code.
I've given examples: Timetabling, employee scheduling, logging. It also applies to costing, forecasting, logistics route-planning, or anywhere there is an indivisible algorithm that needs customisation -- i.e., HofPattern. However, popular business application development languages don't support HOFs, so we're not used to using them. We're used to either using workarounds, or using object-oriented approximations.
In VB-classic, I used to be able to add timer code by dragging a timer widget into the form, right-clicking to set the cycle duration (and other optional factors), and then double-clicking to open up the code snippet edit box and type something like:
myProcess01(7)
if foo.setting < 4 then
myProcess02()
statusBox.value = "done with 2"
end if
logThingy(99)
And then hit the save/close button. The timer then executed that snippet every cycle during run-time. (Multiple timers were possible per form.) Whether it used HOF's, objects, or gerbils under the hood was usually of no concern to me, the custom app developer. VB-classic sucked in many ways, but let's give them Kudos for what they did right (or for stealing the best ideas).
In textual form, it would ideally look something like this:
<!-- example: pond-72 -->
<timer name="timer01" interval="2.5" unit="seconds">
myProcess01(7)
if foo.setting < 4 then
myProcess02()
statusBox.value = "done with 2"
end if
logThingy(99)
</timer>
How is that different from, say, this?
timer01 = startTimer(seconds(2.5), function() {
myProcess01(7)
if foo.setting < 4 then
myProcess02()
statusBox.value = "done with 2"
end if
logThingy(99)
},)
- And it could have been done in OOP a certain way, and a "procedural" way using "sleep()". There's a lot of different ways to manage processes, state, and inter-process communication. I'm not sure what your main point is.
class myTimer inherits timer
constructor
interval = seconds(2.5)
end constructor
function main
myProcess01(7)
if foo.setting < 4 then
myProcess02()
statusBox.value = "done with 2"
end if
logThingy(99)
end function
end class
// The more compact initializer version is not shown
-
My point is that they're the same, differing only in syntax. The latter makes it visibly obvious that HOFs are used, but the former clearly uses HOFs as well. You've been a fan of HOFs all along; you just weren't aware of it!
-
What do you mean the "former" clearly uses HOF's? How do you know this? It could have been implemented with OOP or assembler under the hood, so how is hard-wiring it to HOF now a good thing?
-
How would you implement it with OOP or assembler "under the hood"?
-
Does it matter? This is not a compiler/interpreter-writer topic
-
It matters. If you've got a "start timer" function, and you pass it some executable context -- i.e., a function -- to run when the timer expires, you're passing a function to a function, right? So, what do we have when a function is passed to a function?
-
Again, that's implementation detail, or your personal interpretation.
-
No, that's what it is.
-
No. It can be represented as such, but that's not the same as "is".
-
[Now show us how you'd implement this example using your syntactically-cleaner timer design. -DavidMcLean]
-
No.
-
[That's tantamount to conceding that the higher-order-function-based design, already available and runnable, is in fact the best design possible to address the problem. If you don't think that's the case, please do counter this with a better design. -DavidMcLean]
-
Why is that? Do you see anything about it that prevents implementation? How are you measuring "best"? If Microsoft fixes that damned clicking, the HTML header "refresh" approach would work in existing HTML. Call Bill Gates if you want that, not me. Why again are we revisiting this issue? I never claimed it was "better", only sufficient competitive that we don't need HOF's. -t
-
[What's competitive? You haven't provided an actual solution that addresses the same problem as the original example, with or without higher-order functions. Until you do, there's not even anything you can claim is better than the above solution. -DavidMcLean]
-
If MS-IE didn't click upon refreshes, would the frame refresh solution be acceptable to you?
-
[Not really. It takes more code, said code is more complex, and frames aren't as flexible as <div>s. In addition, frames are deprecated in recent HTML versions. -DavidMcLean]
-
In the long run, everything's deprecated at some point in time. I don't care if it takes a little more code. It's good enough. You are being nitpicky. Again again, I don't want argue over specific client issues. Sometimes JS is disabled or crashed up on browsers such that mine would work on those browsers while yours wouldn't, if you want to get nitpicky. I'm talking general issues, not what specific clients support and don't support. I want to talk about Software Engineering in general, not client help desk and bugs.
-
[Your response would make a great deal more sense if I had said anything about specific clients. The fact that frames are deprecated has nothing to do with individual clients; it's a property of the HTML standard as published by the World Wide Web Consortium. As for "good enough", doesn't the fact that your solution takes more code make it, in your opinion, worse than a solution that takes less code? -DavidMcLean]
-
My ideal solution would not take more code, only the existing-HTML version does. I don't see the deprecation issue as important in terms of demonstrating what is possible. Again again again, I wish to focus on software engineering in general, not client/browser-specific issues. If you care, fine, but it misses my point. The current state of browsers is an ugly point in the history of UI's and the HtmlStack is flaming piece of rotting shit.
-
[Again again, as you put it, the fact that frames are deprecated is not a client/browser-specific issue. I suspect from your unfamiliarity with AJAX that you actually have no idea what the current state of browsers is; make sure you are familiar with HTML5, CSS3, and jQuery or Prototype.js before making sweeping claims about the current state of browsers. If you believe your ideal solution does take less code, that's great. Show it to us. -DavidMcLean]
-
A web browser is a specific type of client. I did not claim it would take less code than your example, only that it would be reasonably close. Clarity should sometimes override code size. Maybe I'll code up a fuller example, but not today.
-
[Yes, a Web browser is a specific type of client. That doesn't counter any of my points, however. Actually, you did claim your solution would take less code. You said your solution "would not take more code". By definition, that means it either takes exactly as much code as the above example or less code than the example. The former is seriously unlikely, so I have to assume your solution is going to take less code. Either way, we still need to see it. -DavidMcLean]
-
Note that the deprecated frames are due to be replaced by something else in HTML5. Whether Microsoft will make it have clicking sounds again or not is still open.
-
[The intended purpose of frames (layouts made of multiple pages, such as with a constant menubar on the left and a larger content pane) has long been addressed instead using a combination of CSS and server-side development. Using frames to refresh parts of the page has also long been addressed, in a more flexible and capable fashion, using AJAX. HTML5 isn't really bringing in anything new to replace frames, because everything frames can do is already done better by other techniques. -DavidMcLean]
-
If "done better" is true, then how does/will HTML5 deal with auto-refresh panels to replace the existing refresh directive? If we have to rely on scripting, that's a step backwards. HTML5 is still experimental. It may get dumped or trashed by the industry in the future.
-
The refresh pragma directive is still there to auto-reload pages for creating crude slide-shows and the like. Framesets are not in HTML5.
-
Then it's not equivalent because the entire page has to reload.
-
[Actually that is equivalent, because that's what the refresh pragma does: It makes the entire page reload. All that's been lost is the opportunity to abuse that feature for refreshing page sections instead, which is fortunately fully addressed in a cleaner and more flexible fashion by AJAX. -DavidMcLean]
-
It's removing the ability from HTML markup. That's a step backward. Fuck AJAX. AJAX is a hack to work around a mess, it's not the future I certainly hope.
-
[Is your rudeness necessary? AJAX is both flexible and capable, and removing features not related to semantic content markup is a step forward for HTML. -DavidMcLean]
-
I am being rude to technology, not you. When AJAX grows sentient it can write me a letter asking for an apology. And keep in mind that "flexibility" is not the only goal. The "Lisp civil war" already happened and Lisp-style flexibility lost, at least for CBA's. Get over it! Markup-based GUI's are the way forward.
-
[You're being rude to technology I like and more importantly that I benefit from daily, since the vast majority of recent Web apps employ AJAX functionality. Flexibility is important; if AJAX were less flexible, instead restricted only to work like your markup-centric idea on BradyBunchGridDiscussion, it wouldn't be able to produce a lot of useful Web-app functionality. AJAX's flexibility has absolutely nothing to do with Lisp, so discussing Lisp is a complete non-sequitur. -DavidMcLean]
-
You haven't identified any specific weaknesses of the idea.
-
[No, I have. It's presented on the page already. -DavidMcLean]
-
-
Within about 10%, okay?
-
[Alright. If you believe your solution can produce code within about 10% of the above example, that also is great. You will still need to show it to us, of course. -DavidMcLean]
I'm not sure what the VbClassic code-generation wizards and form painters have to do with this, but it's notable that event handlers are ideally implemented using HOFs.
Even if that was true, why should I, as a custom app developer, care? That kind of detail is a tool implementation detail that should be handled under the hood from my perspective. We are going backward in technology with primitive HtmlStack crap, which is the only reason it's a half issue.
Why should you care? Because you are, I presume, a programmer. These are the things programmers care about. If you don't care about programming, but (at best) endure it and ideally want all programming to be eliminated, then these discussions probably aren't for you -- you're looking for tools that not only eliminate HOFs, but which eliminate functions in general, loops, and IF statements too. Otherwise, why hide HOFs but not, say, loops?
There are MentalMasturbation projects we do on our own time, and there is being productive at work by not having to concern one self with minutia not related to the task. I understand that a given tool may prefer or even force it to be done one way or another, but that doesn't make it some kind of universal truth of superiority. If a given UI tool prefers HOF's, I'll consider HOF's. If it prefers OOP, I'll consider using OOP. If it prefers gerbils, I'll consider using gerbils. But that's missing the main target here: about how to better write and manage biz code, NOT how best to work with JavaScript or BrainFsck or whatnot. -t
Fair enough. I think what's been made abundantly clear is that HOFs are of value, even in custom business applications. When more business application development languages explicitly support HOFs, then we'll see that even more clearly.
"Support" and "force one to use" are not the same thing. You still haven't made a real case for them in terms of general code organization, rather relying on some specific API to "justify" them.
Eh? That very justification, "in terms of general code organization", is precisely what this page is for. It presents a general case for using HOFs to inject customisations into otherwise-indivisible implementations of algorithms.
You didn't compare it to alternatives, including alternative API's that one may be stuck with using due to circumstances, and didn't count or measure anything objective. If this is the best case you can make for HOF's for custom biz apps, then actually you've only made my case because you claim to have extensive C.B.A. experience and a whole world of scenarios to choose from, and this rigged thing is the best you can do. Thank You. --top
How is the above "rigged"? I have pointed out that the alternative is to inject an object, but that's essentially conceptually identical to a HOF. It adds only syntactic overhead to achieve the same end, which is to carry an external function (or possibly functions, in the case of an object) that carries some external state into the function that implements the algorithm. There are no other alternatives without the pattern itself disappearing. For example, you can partition the algorithm (which means it's no longer considered indivisible!) but for indivisible algorithms -- exemplified here using a double nested loop -- this obviously results in negative consequences. This is all obvious; I'm not sure what I can do to make it clearer. There's no need to count or measure anything, because the implications are self-evident. Anyway, what would I count? Inject a function = 0 awkwardness, but being unable to inject a function (or object) means partitioning the algorithm = 1 awkwardness? I'm certainly not going to iterate through every possible individual case -- that would be ridiculous -- hence my provision of a general pattern.
I'm not sure what you are talking about. Your head seems to be caught in the machine end of things. We are not talking about how to make interpreters/compilers. Why should it matter to me that it's "conceptually identical to a HOF"? The fact that you cannot measure anything of utility to a CBA developer is telling.
I'm not talking about "how to make interpreters/compilers", but how to implement algorithms -- you know, those things that custom business applications are made of, that do things like calculate timetables and employee schedules and figure out costing and determine vehicle routes and stuff -- so that the algorithm can be an indivisible unit for maximum performance and simplicity, but you can still customise it at run-time by injecting the customisation as a HOF (or object). I'll give you a basis for measurement: How would you handle that situation without HOFs or objects?
What situation? Are we starting a new scenario?
No, the same situation as HofPattern, i.e., an indivisible algorithm requiring customisation. How do you handle the customisation without HOFs or objects?
It depends on the details of the business requirements and environment.
No, it doesn't. This is an abstraction. And re-engineering the application so that you don't need the algorithm any more, or that you can buy the solution pre-made, is not a reasonable answer.
Not a good one. If you can't quantify the alleged improvement, then you are going to have a hard time being convincing. You may not like science, but it's good for you, like broccoli.
Many engineering considerations are not easily quantifiable but are trivially qualifiable. For example, we can easily see that structured code is qualitatively superior to using GOTOs, but this is not easily measurable. Regarding the pattern shown on this page, fortunately the case is easier to make -- there simply isn't a reasonable alternative. Historically, a typical procedural (i.e., non-HOF, non-object) solution would have required inefficiently (and probably awkwardly) partitioning the algorithm's implementation, or implementing it in such a manner that customisations would have to be embedded in it. Either is qualitatively inferior to injecting HOFs or objects into the algorithm's implementation. Obviously, experiments can be constructed to quantitatively verify this, but one can do a trivial gedankenexperiment to show it too. For example: How many times would the algorithm's implementation need to be changed to suit new scenarios? With HOFs and objects, it wouldn't -- customisations can be injected. Without HOFs and objects, it would have to be changed once per new scenario. If the number of new scenarios is 'n', then with HOFs and objects the number of algorithm implementations == 1, without HOFs and objects the number of algorithm implementations == n. 1 <= n. QED.
You haven't shown realistic change scenarios. You go out of your way to lodge the scenario into unlikely, vendor/client-specific corners, or assume one aspect is very stable while another is very dynamic without describing why it's that way in the environment.
Really? Can you show how and where I have made these mistakes?
Are you familiar with the C/C++ standard implementation of qsort? It's the quintessential example of what I'm describing. The generic, indivisible QuickSort sorting algorithm is implemented as a function qsort(), but it requires customisation: the comparison operation varies depending on the data type being sorted. So, the comparison operation is injected as a higher-order function. This means the qsort() implementation never needs to change; only the comparison operation changes to suit any scenario for which QuickSort is appropriate. HofPattern is a generic abstraction of this concept. Why do you think qsort() is implemented this way? How would you implement it so it doesn't use a HOF, and what are the implications?
And there are plausible WetWare theories on goto's versus blocks even if they are not quantifiable (I've written my own observations on goto's elsewhere). But I would never insist that such theories are iron-clad and insult those who claim they function well with goto's. What makes my WetWare happy may not apply to others. If you ain't got the science, man up and admit it.
It is almost impossible to sustain any reasonable engineering argument in favour of using GOTOs over structured programming, at least that doesn't devolve into supporting a style of programming favoured by at best a rapidly-vanishing handful of "old skool" developers.
And I have already agreed that HOF's may be a more efficient option in some situations, machine-performance-wise, but that it's usually not a bottleneck in practice for custom biz apps. I'm happy to make the machine slave away so that the human doesn't have to.
As illustrated with HofPattern, not only are HOFs more efficient machine-performance-wise, in some cases there is no reasonable alternative.
If the API forces you to use it, then yes. If an interface requires SQL, then one must interface with it in SQL. If it required Mayan hieroglyphics, then one must use Mayan hieroglyphics to interface. This should go without stating. This is getting frustrating; I'm holding back angry statements that are not meant for family viewing, but the pot is near boiling and sputtering out the edges. In my humble opinion, your scenario is rigged and we keep making the same arguments over and over. Unless you find something quantifiable and not tied to exclusive products, there will likely be no closure here.
Why are you reacting emotionally? Is it because your anti-HOF stance is emotional rather than practical?
What do you mean by "tied to exclusive products"?
How is my scenario rigged? And, if you feel it is rigged, do you feel qsort() in the C/C++ standard library is rigged as well?
This is more than just an API that forces you to use it. QuickSort (as implemented in the C/C++ standard library) requires customisation to be useful -- it needs a "compare" operation specific to the data being sorted -- and it is difficult to partition. If it could be partitioned easily, you could divide it into separate, semi-independent "blocks" and interpose customisations between them. Unfortunately, QuickSort -- like many algorithms -- defies being broken down into multiple semi-independent blocks. So, what are the alternatives?
- Force partitioning on the algorithm. Unfortunately, that makes it awkward to use because you have to properly place multiple "blocks" every time you want to use the algorithm. This is complex and error-prone. Typically, it also has significant performance impact.
- Create a new implementation of the algorithm for each scenario. Obviously, that's best avoided. It's less effort and there's less risk of introducing bugs if you implement and debug the algorithm once, rather than every time you need it.
- Inject customisation as an 'eval' string. This risks inadvertent code-injection, may involve awkward escape sequences to deal with embedded delimiters, requires code to generate strings dynamically, often has limitations in terms of capturing the originating context (i.e., no equivalent to closures), requires compilation and/or syntax checking on each iteration by the algorithm, and the generated strings can only be examined at run-time.
- Use HofPattern (or its object-oriented equivalent) to inject customisation as functions. Unlike 'eval' strings, HOFs are syntax checked and compiled only once, and can be debugged the same as any other function. They don't risk inadvertent code-injection, require no awkward escape sequences, typically capture their run-time context via closures, and require no dynamic code to generate anything because the code is written by the programmer, not the program, and are therefore constructed the same as any other static code.
Given the above, is there any reason not to choose the last option?
It's never been an issue in all the biz apps I've worked with. If the existing collations are not good enough, I create an additional column(s), real or virtual, to fine-tune the sorting using compound-column database sorting.
Indeed. Unless you write business applications exclusively in C or C++, you're unlikely to have used QuickSort. QuickSort is a specific found-in-the-wild example of the general HofPattern. Precisely the same principles and conditions that apply to QuickSort apply to a wide variety of business-oriented algorithms. Instead of QuickSort, it could just as easily be employee scheduling, timetabling, logistics routing, payroll tax calculations, costing, sales forecasting, or some other business-oriented algorithm. Of course, most of the popular programming languages for business application development -- except JavaScript, if you're doing client-side Web development -- simply don't support higher-order functions. That means of the four alternatives above, the last one is usually unavailable. So it's not surprising that you prefer the first three and are sceptical of the last one; it's almost certainly unfamiliar and therefore outside of your development comfort zone. Of course, that will inevitably change, as the value of higher-order functions -- for precisely the sort of pattern described on this page, among other things -- is virtually undisputed in the programming community, regardless of domain. So, we will see HOFs in future business application development languages.
You keep claiming that, but fail to show semi-realistic scenarios (a business setting) of them helping a lot for custom biz apps. The above looks pretty much to me like a repeat of claims already made. Ideally at least 3 biz sub-domains should be demonstrated, but I'll settle for one at this point as a start (not tied to specific API's or hardware). We just seem to have very different ideas of what we consider and/or accept as "good evidence". I don't know what to say. We are at an "evidence impasse" that seems unbreakable and are going around in circles repeating the same arguments hoping they finally stick a 7th time around or whatnot. I won't stop believing that GoodMetricsProduceNumbers (if the claim is intended to be "objective" [1]), and you won't stop believing in (what looks to me like) ArgumentByElegance. This issue is at a higher level than that of HOF's themselves. I suggest you encourage a different WikiZen with a different evidence presentation style to demonstrate the power of HOF's in CBA's. -t
I wish it were as simple as ArgumentByElegance! It's quite simply the case that for some indivisible algorithms, the four alternatives above are the only alternatives. Employee scheduling is a good example, as it typically consists of nested loops and needs to invoke a customisation -- the fitness function -- in the middle of them. So, much like the qsort() example above, in the simplest case the scheduling function signature winds up being something like schedule(Employees e, Slots s, FitnessFunction f) where 'f' is a function that returns a weighted indication (and sometimes just a boolean) that tells whether or not a given employee can fulfill a given slot, and f can vary under external conditions like whether we're generating a regular schedule or an overtime schedule. And, of course, the schedule() algorithm implementation, once written, gets used on a number of projects. In other words, it's a characteristic example of HofPattern. My other examples are exactly the same: an indivisible algorithm, and a need for customisation.
I'm skeptical because biz logic often involves lots of business "sub-parts". They cannot be easily summed up into compact "functions"; and managing the repeating patterns (commonalities) are often best served with something closer to set management (SetTheory) and/or nested IF statements: interweaving features or characteristics selected in a buffet manner, which often leads to declarative "switches", not functions. A list of functions or function-only-based interfaces is usually too blunt an instrument in such a setting. The granularity of functions is too large. In practice the useful variations or their representation will be on a sub-function level, perhaps closer to the parameter level. Something like PredicateDispatching is a better fit, but these usually leads to a single "god function", in which case HOF is no longer helpful since there is only one. Further, power users are often going to manage most of the variations/combo's via something akin to a RuleBuilderInterface for non-trivial implementations, not programmers writing functions. Conceptually it's a great idea that I wished worked, but just doesn't float in typical CBA settings. Maybe you need to invent "HOP" - Higher Order Parameters :-) You seem to be making some of the same mistakes that "taxonomy fans" sometimes make, thinking that the variations can be nicely mapped to a hierarchical taxonomy (sub-types) because trees are such a "clean and pure" organizational concept. Functions are potentially even "bluntier" than trees because trees at least have sub-trees in them for finer tuning. (Regarding employee time-slot scheduling; again, I don't have enough knowledge of that particular sub-field to comment or demonstrate. I suspect most co's buy pre-made software such that it's no longer in the CBA realm.)
How do you know you that your perceptions -- i.e., that repeated patterns are best handled with "nested IF statements", or that features should be selected in a "buffet manner", or that functions are usually "too blunt an instrument", and so on -- aren't simply the unfortunate result of your deliberate avoidance of certain programming techniques -- like higher-order functions, inheritance and polymorphism, and so forth -- that make it possible to efficiently, effectively, elegantly, and re-use-ably handle the complexity of programming custom business applications, regardless whether you're developing them in house or to sell to other companies as pre-made software?
Couldn't the same principle potentially apply to you with regard to dynamic languages (such as Eval) and database usage? If I am self-deceiving myself, I'm not aware of it. And you could fall victim to the same human weakness just as well. The best way to settle it is to create semi-realistic coded examples or scenarios, and then let the reader decide how relevant those examples and comments on those are to their own world. HowToSellGoldenHammers still applies. And I do agree that some OOP concepts have their place; it's just not as wide as many OOP proponents claim or used to claim (OopNotForDomainModeling). Yes, it's "nice" to have HOF's in one's programming toolkit, but I see no significant improvement from them for CBA, only minor incremental improvements for a narrow set of apps.
Could the same principle potentially apply to me? Could I fall victim to the same human weaknesses that all humans do? Could I be blinded by my own biases or preconceived notions, or be limited by comfortable familiarity, or let laziness cause me to roll back from steep learning curves and lose out on something helpful? Absolutely! It's why I continually read about new programming techniques, new development processes, and new programming languages, and try them whenever possible. It's why I continually revisit existing techniques, processes and paradigms to see if there's something I might have overlooked. It's why I search for and read published summaries of research into all aspects of SoftwareEngineering. It's why I constantly reflect on and re-evaluate my own programming, and ask myself whether my code is as readable, as maintainable, and as efficient as it could be.
As a result of that process, I've come to realise that HOFs are superior to evals, embedded case statements, or the first three alternatives I listed above. There are no downsides. The only objection I can possibly see is that HOFs are, for many programmers, something new that needs to be learned. But once learned, they're as easy to understand as any function -- or, for that matter, any other programmatic construct, like conditional statements and loops. Of course, every neophyte programmer had to learn about loops, and many find them to be the first big conceptual learning hurdle in programming. Is that a reason not to use loops? Similarly, because HOFs may involve a small learning hurdle, is that a reason not to use HOFs?
I would note that when I do start out using something very similar to HOF's, such as Eval'd expressions or SQL clauses, if there becomes many instances (variations on a theme), then certain patterns start to appear such that a declarative interface(s) starts to become apparent such that table switches/flags or configuration screens or RuleBuilderInterface techniques start to become of more utility, and gradually more of the management and creations of variations can be handed off to power users or junior programmers. If there remains only a few variations, then the technique used doesn't matter much because usually a low quantity of variations also means a low quantity of changes in the variations such that all the usual techniques either score similar, or are not a significant point of change anyhow because they contribute relatively little to the change pattern "scores" of the entire application. In short, with few variations, most of the technique choices are a wash or insignificant to the big picture. If there are many, then attribute-driven or declarative interfaces are best applied so that power users instead of programmers manage most of them. Now I may not know much about employee shift scheduling software techniques (mentioned above), but I'd be willing to bet that if we study the pattern of actual scheduling techniques variations in the field, the above dichotomy pattern would show itself. Eval'd expressions and SQL clause lists/tables are often quite useful for the prototyping stage, but as the app matures, less so.
Typically such medium-sized "expression lists" eventually evolve into roughly 3 to 12 "strategies", where each strategy has its own set of parameters/fields/switches that often differ in quantity and nature from other strategies. Sometimes some combo's of strategies are not mutually exclusive, which may complicate the UI a bit. In bigger variation pools/apps, there are often interweaving overlaps such that there is more of a feel of mix-and-match than the strategy->fields hierarchy of its smaller cousin. At this point, some kind of RuleBuilderInterface may be more appropriate if you don't want a combinatorial explosion of sub-screens.
Sorry, I don't see how the above represents an alternative to HOFs. You appear to be referring to broad architectural issues, which HOFs are not -- at least, not necessarily. They're often a small-scale technique on the same level of detail as conditional statements and loops. They're merely a way of injecting customisation into an otherwise closed place. E.g., you've got something like this:
function somethingUsedFrequently() {
for (i=0; i<n; i++)
for (p=0; p<i; p++) {
// ...bunch of code goes here...
// what happens here depends entirely on where somethingUsedFrequently is called
// ...another bunch of code here...
},
},
},
Do you really want to be change somethingUsedFrequently() every time it's used in a new place? What if it's used slightly differently dozens or even hundreds of times? What if the customisation is parametric, i.e., generated from some dynamic value? Is it better to do this...
function somethingUsedFrequently(algorithID) {
for (i=0; i<n; i++)
for (p=0; p<i; p++) {
// ...bunch of code goes here...
select on algorithID {
case "foo": fooFunction(p)
case "bar": barFunction(p)
case "glif": fooFunction(p) + barFunction(p)
case "bwep": barFunction(p) + 73
otherwise: myDefault(p)
},
// ...another bunch of code here...
},
},
},
...or is it better to do this?
function somethingUsedFrequently(algorithFn) {
for (i=0; i<n; i++)
for (p=0; p<i; p++) {
// ...bunch of code goes here...
algorithFn(p)
// ...another bunch of code here...
},
},
},
Note that in the second example, somethingUsedFrequently() need never change. It can be embedded in a library and remain constant, regardless of context. In the first example, somethingUsedFrequently() will need to be changed every time it's used in a new context. Furthermore, the functions passed to somethingUsedFrequently can be generated by a function, like this:
function algorithGenerator(x, y) {
return function(p) {
return splorb(x) * spleen(y) / p
},
},
for (q=10; q<10000; q++) {
fn = algorithGenerator(q, rand())
somethingUsedFrequently(fn)
},
Try that with case statements! I can't see any reason why case statements or eval'd expressions would even be considered as an alternative. The last example is so obviously superior -- and so obviously difficult with anything other than HOFs -- that I find it difficult to imagine how any counter-argument can be sustained.
Finally, to complete the equivalent to your case statement example, you'd probably have this:
function glif(p) {
return fooFunction(p) + barFunction(p)
},
function bwep(p) {
return barFunction(p) + 73
},
-
Creating lots of little functions can make code difficult to read and manage and compare similarities of implementation. I realize that everyone has different preferences, but that kind of thing doesn't work well for me.
-
You're attempting to justify a highly questionable practice. Composing lots of little functions from lots of little functions, and using lots of little functions to compose programs, is the essence of good programming. Monolithic coding is difficult to read, difficult to maintain, discourages re-use, and is prone to errors as it discourages unit testing.
-
There's a lot of unjustified claims packed into that paragraph. Lots of little functions results in one's eyes having to hop around like a frog on crack when reading such code. And it bloats up code with lots of repetitious parameter definitions. Further, it actually discourages re-use because one cannot see common ties because stuff is scattered. But I will agree that everyone's WetWare works different and is "bothered" by different things.
The above would be used like this:
somethingUsedFrequently(fooFunction)
somethingUsedFrequently(barFunction)
somethingUsedFrequently(glif)
somethingUsedFrequently(bwep)
Note that no case 'default' is needed, nor are run-time string comparisons needed to determine which operation to perform. Is there any benefit to the case-switch or nested if/elses here?
-
Like I said, often the interface grows variable. Named parameters are often used to provide a flexible interface into the function. These parameters, many of them sub-feature on/off switches, are what controls the variability. Functions (alone) cannot provide a competitively flexible interface to the function or API unless you live with the combinatorial explosion of AttributesInNameSmell. HOF's don't scale well in that regard in terms of providing a well-factored interface.
-
What do you mean by "HOF's [sic] don't scale well in that regard in terms of providing a well-factored interface"?
-
If the module/unit/function grows fairly complex such that the different techniques make a difference in terms of modification effort, then usually the interface to that module/unit/function also grows complex. It doesn't make sense to duplicate a complex parameter "list" to each and every HOF-supplied. The behavior is often "chosen" using the parameters, not a function or operation "name". A simple example is given in AttributesInNameSmell.
As a refresher, co-competitor techniques to HOF's include Eval'd expressions, conditionals (case-switch or nested IF/ELSE's), SQL clauses, OOP sub-classing, and RuleBuilderInterface(s). They are not necessarily exchange-able one-to-one, for in some cases multiple techniques may carry the load that is done all in one technique in another case. -t
Only eval'd expressions are a competitor. Injecting objects (is that what you mean by "OOP sub-classing"?) is equivalent to HOFs; it's not a competitor, it's a variant. RuleBuilderInterface(s) will need to be evaluated in code; that code is likely going to be in the function passed to some algorithm. Conditionals are obviously inferior in every respect, and I don't know how SQL clauses would apply; are you familiar with the overhead that invoking SQL queries represents? And, eval'd expressions are obviously inferior, for reasons noted above.
Saying sub-classing or "injecting objects" is "equivalent to HOF's" is something I disagree with. How do you define "injecting"? Anyhow, OOP is supported by most mainstream languages now such that your claim that people don't use HOF's because mainstream languages often don't support them appears to be a contradiction. And are you claiming that a typical RuleBuilderInterface is usually best done with HOF's?
Sub-classing and injecting are orthogonal. Sub-classing is about creating class definitions. "Injecting" is shorthand for "passing in from outside for use inside." HOFs and injecting objects are equivalent, but not the same. A function passed as a parameter typically implicitly captures its execution context as a closure; passing an object typically requires explicitly constructing that object with the desired context. In short, passing objects and HOFs can achieve the same goals. However, objects typically require more programming effort and HOFs are syntactically (and conceptually, for the most part) distinct from objects, so object-oriented programmers don't typically think in terms of HOFs even if they're explicitly creating FunctorObject's.
I'm not claiming that a typical RuleBuilderInterface is "usually best done with HOFs". I do claim that it's entirely appropriate and reasonable for a RuleBuilderInterface to be evaluated at run-time by some function, and for that function to be passed (injected) into another function, but that doesn't necessarily mean it should always be done that way.
Also, you don't seem to dispute that Eval can be used to create HOF-like behavior. I pointed out that I've used such on occasion, but mostly just for prototyping because when requirements settle down they are often best replaced with something else, and it's not for reasons of "type safety" and compiler checking (I prefer dynamic languages anyhow). Your claim that I don't try HOF's is thus diminished.
If you only use eval to create HOF-like behaviour, then you've tried HOFs precisely to the extent that someone who only eats worms can claim to have tried spaghetti.
For your employee shift scheduler, are there really so many algorithms that we need HOF's to manage them? What's wrong with a case statement:
fitnessDispatcher(algorithmID, p) {
select on algorithID {
case "foo": fooFunction(p)
case "bar": barFunction(p)
case "glif": fooFunction(p) + barFunction(p)
case "bwep": barFunction(p) + 73
otherwise: myDefault(p)
},
},
// I'm not using C's "switch" syntax because it's an abomination
We just have to add another CASE for a new algorithms/function.
Curious. It is precisely that "just have to add another CASE" that I try to avoid. Every change to the 'fitnessDispatcher' function, no matter how innocuous, risks breaking it or inadvertently altering one of the other cases. Why do that, when using HOFs eliminates that possibility entirely? What is gained by case statements? What do you lose with HOFs?
-
Bump-thy-neighbor can happen no matter what. There's going to be something next to it in most cases. Why is bumping X scored worse than bumping Y? Further, having them together can help one notice patterns for better re-factoring ideas, perhaps preventing what otherwise would be yet-another-function.
-
Algorithm implementations are usually shared. If bump-thy-neighbour occurs inside a shared algorithm implementation, it potentially breaks many applications, modules, or processes. If bump-thy-neighbour occurs outside a shared algorithm, at worst it affects one application, module, or process.
-
We cannot say whether the "bumped" item is "shared" or not without app specifics. Number of callers is only a rough metric of impact cost anyhow. Sometimes bumping something not related to a recent edit is harder to find or notice than one related. And the visual pattern benefit still stands.
Generally I find that such lists almost never get long unless the API or user interface is poorly factored. If you factor out the commonalities, then it grows into nested IF's and/or non-mutually-explicit behavioral conditions based on parameters or info from the database, etc. I don't know why this pattern happens, but it just does. Complexity just simply is rarely constrained to one dimension. It, eventually squeezes out into other directions or dimensions (such as parameter differences) if it keeps increasing. Rarely does one aspect get all the complexity or quantity increase while other aspects stay relatively sparse or simple.
You can prove me wrong by showing actual long lists and what each algorithm is. You don't necessarily have to implement each one, just describe what they are, such as "Algorithm X from Dr. Snaffew from Flubber U, Journal of Zog, May 2004."
I agree that with say something like sorting algorithms, there could be 50 or more algorithms in the wild. However, for a custom biz app, we may select a handful to cover a sufficient variety of performance and/or results trade-offs. The users will get confused if we list 50 in the pull-down list. Reality often culls extreme cases in such a way. GoldPlating is possible but often not wise nor budgeted. (In practice with CBA's, I usually use the database to sort and rarely have to do it in app code, but I'll humor the example for now.)
It's not the algorithms that vary significantly, it's the customisations that need to be injected into the implementations of algorithms that vary. For example, Dijkstra's Algorithm is the same whether it's finding the shortest path -- for, say, logistics planning purposes -- over a set of roads or a set of canals. However, we may wish to inject a customisation into the implementation of Dijkstra's Algorithm to allow for the fact that it's being used for roads in one context, and canals in another. Or whatever. The important thing here is the concept, not the specific case.
-
Well, biz apps are usually about specific cases. We don't build database engines we USE database engines. We don't build operating systems and device drivers, we USE them. Further, for traceability reasons, usually it's best to create an intermediate table or list using the value of concern, and then sort that list. We don't have to do it all one in shot. DivideAndConquer is often easier to trouble-shoot and provide further documentation for users and managers about how the results came about. You don't need to "handle" gazillion different "types", because you can re-project into one of the standard types in the intermediate table, and then run the sort.
-
Most programmers, regardless of domain, "use database engines" and "don't build operating systems and device drivers". Business applications, except for those that are essentially data-in/data-out, use algorithms just like any other domain. When algorithms are used, it is preferable to define them once and inject customisations. That certainly doesn't preclude providing mechanisms for logging at various stages.
-
There are different ways to "inject customizations", each with it's own tradeoff set.
-
Yes, and I covered those in the alternatives above.
Another example you often use is the comparing function for sorting algorithms. In practice it doesn't make sense to have gazillion functions, but rather have a collating sequence defined in a database or map file (character or symbol, and its sequence rank). You then add another parameter--the collating sequence name or table name--such that a lot of complexity becomes "absorbed" by (shifted to) the new parameter so that we don't need gazillion new functions and are thus not changing the CASE list very often (if that's what you fear). In theory you could use gazillion functions, but it's a case of AttributesInNameSmell. Most CBA scenarios, if factored properly, will grow some "width" with any increase in complexity, and the length (quantity of functions) growth will slow down. -t
The comparing function varies depending on the types being compared; i.e., one comparison for unicode ISO-8859-5, another for ASCII strings, another for integers, yet another for floating point values, yet another for scholastic exam grades, another for the lightness or darkness of baked bread, another for colours, etc. In other words, the collating sequence varies by type.
Okay, but a CUSTOM biz app is not going to need to be everything to everybody; it's usually going to be called on to do a specific job. (Again, databases are usually used for most sorting and have done the job just fine. This would be for some rare, special, and so far unidentified project.)
If it's just sorting, perhaps. Remember, the "comparing function for sorting algorithms" is an illustration of the general HofPattern.
Yes yes. We are in dire need of a semi-realistic specimen/scenario so we can move beyond toy or lab examples.
How would you refactor this into HOF's?:
// Example "Pete-82"
function foo(title, flag1=true, flag2=false, flag3=true, flag4=true) {
// values after are defaults if explicit is not supplied
behaviorCommonToAll(title);
if (flag1) {
if (flag3) {
blah(title, flag4);
},
moof();
}, else {
if (flag2 && flag3) {
znig();
}, else if (flag4) {
grob();
},
},
if (flag4) {
fible(title, flag1);
},
},
I wouldn't. I'd get rid of foo() -- as it appears to be trivially divisible, and therefore not an example of HofPattern -- and compose functionality as and where needed from behaviourCommonToAll(), blah(), moof(), znig(), grob(), and fibble(), because it appears flag1, flag2, flag3, and flag4 are essentially synonyms for which functions you want to call. Why not simply call the functions you want to call?
They are not synonymous because they affect different parts in different ways. And typically the feature flag and controller values come from the database, where user and power-user preferences and content attributes are stored. It's not in code such that it has to happen at run-time.
That's dynamic dispatch based on decision tables and the grammar represented by the user interface. As noted, there isn't an indivisible algorithm here, so HofPattern does not apply. [[I added emphasis, -t]]
Well, that's the most common general pattern of CBA's I see, which reinforces my suggestion that HOF's are not very helpful in CBA's.
That suggests the "CBAs" you write are primarily data-in/data-out and summarisation, sometimes called "reporting apps". Nothing wrong with that; there's a large market for such things. It also means you are, indeed, unlikely to need HOFs. You can probably build everything you need out of SQL and a procedural scripting language with conditionals, loops and procedures.
They are a variety of things, not merely "reporting apps" or I/O. It's a lot about "routing" in that the attributes/settings (as stored in the DB) control when and where things "show up" or are processed. For example, an input screen may have a flag for "This foo falls under regulation/policy X". That switch's value may affect a half-dozen or so conditionals along the business process chain, controlling whether certain actions are taken or not taken including which reports it shows up on, how it's categorized (including category validation/review), how it's billed & taxed, how long it's kept in the archive, etc.
But at least we seem to be coming to some semi-agreement, which is rare around here. --top
It sounds like there isn't a lot of (or any?) algorithm implementation, at least not in the SoftwareEngineering or ComputerScience sense. Depending on what development tools you use, you might see HOFs being used (either now, or eventually) in event handlers to implement callbacks, but outside of that, there's not much justification for them.
-
I'm still baffled by that statement. What exactly are "computer-sciency" algorithms? You seem to mean graph-chomping traveling salesmen optimization or AI-ish type of stuff perhaps. Maybe that's your specialty such that you see a lot of those. I don't, for whatever reason in 25 or so years in biz and management apps. The "algorithms" are fractured and interweaving as described above and control-switched via tables and/or CRUD forms with lots of switches and sub-algorithm selectors, not hand-coded functions. Why should I care about optimizing YOUR specialty and not mine? If HOF's help YOUR specialty, that's fine, but don't be a leaky-head and extrapolate that to everybody. -t
-
"Fractured and interweaving" code is precisely what results from attempting to divide an otherwise indivisible algorithm -- typically due to lack of FunctorObjects, lack of HigherOrderFunctions, or lack of application of either. Typical "computer-sciency" algorithms used in business are indeed pathfinding like A* and Djikstra's Algorithm, genetic algorithms for scheduling or optimisation, complex searching, various financial calculations, regression analysis, and so on. Data-input validation and reporting, though often intricate, tend not to be algorithmic in the ComputerScience sense.
-
Your 2-node classification of "algorithmic" versus "reporting" is over-simplistic. It's a lot more than "reporting", it's just not the stuff found in the "graph chomping/optimization" algorithms you describe. Biz apps often mirror, model, track, and manage actual domain "things", which may be contracts, products, lawsuits, etc. That's a lot more than mere "reporting". There may indeed be a thriving niche for "automated optimization" or the like, but it's not my niche nor one I have encountered much other than users using off-the-shelf products for such. (Some tools I worked on provide interfaces to facilitate manual optimization. In other words, visualization, reporting, and data entry tools for managers to monitor and control resources via their explicit decisions.) It's usually not "rocket science", except perhaps using domain knowledge in a smart, practical, and rational manner to improve the product. It's essentially bean counting where the beans have a lot of nitty-gritty domain rules associated with them, and the rules are generally known to and understood by the domain workers (although often not contained entirely in a single individual(s), but spread around).
-
Despite your claim that my classification is "over-simplistic", your description effectively confirms that my classification is correct. What you're doing is data-entry, validation, and reporting. Look at the words you use: "visualization" = reporting, "data entry tools" = data-entry, "reporting" = reporting, "bean counting" = data-entry + reporting, "domain rules" = validation, "mirror, track and manage" = data-entry + reporting. I'm not saying it's simple or easy, or that what you do doesn't require a lot of expertise. It does, I know this; I've done it too. It simply isn't algorithmic in the ComputerScience sense. There aren't identifiable algorithms: methods for solving a general class of problems.
-
But it's much more than just "reporting". The term "reporting" is just plain the wrong term for it. It's modelling business objects/rules, not JUST "reporting". Reporting is about the presentation side and says nothing about decisions and routing, for example. Reporting is only a component. Perhaps you are looking for a distinction between using "pre-documented" algorithms and "undocumented algorithms".
-
Modelling business rules (which is what business objects do) is either support for validation -- ensuring data is correct on input, or support for reporting -- ensuring data is presented as required. If routing is done and decisions made by automated processes that identifiably solve a general class of problems -- e.g., where a report is routed depends on some statistical evaluation of the contents of a data store -- then it is algorithmic. Otherwise, it may be procedural or rule-based but it isn't algorithmic.
-
Modeling a business process electronically is NOT synonymous with (just) "reporting" (in most cases). Where are you getting this term "algorithmic" as far as classifying software? If it's not commonly used, I suggest you find a different way to describe it outside of your organization. What about "automated decision making"? That's still a bit of a misnomer because any code with IF statements could be called "automated decision-making", but it's closer to the notion of what you describe.
-
"Modelling a business process electronically" sounds like simulation, which is highly algorithmic. It's not, however, what typical business applications do. Typical business applications allow data input, validate the input, and generate output aka reports. Routing is determining where the data input occurs or where the report gets sent. There is almost invariably calculation -- expression evaluation and the like -- but the algorithms that make it possible are already implemented for you and hidden from your sight. I suggest you see http://en.wikipedia.org/wiki/Algorithm for greater understanding, and then please demonstrate the algorithmic nature of your work by identifying -- by name -- the algorithms you implement or use. Algorithms have names, so that we can refer to them easily. See http://en.wikipedia.org/wiki/List_of_algorithms
-
Again, that's "pre-documented" algorithms versus "undocumented algorithms". That seems like the best description found so far. Or how about "cataloged" versus "uncatalogued"? However, that implies a central documenting source/authority.
-
Could you give an example of one of your "undocumented" or "uncatalogued" algorithms and explain what it does and how it works?
-
Do you mean an entire application? If you mean "parts" of apps, I'm not sure I can pull any one piece out by itself and have it make sense on its own. It's usually domain-specific. An example may be a "junk cleaner" whereby an organization periodically receives data from an outside org and the data has to be scrubbed before use. Various heuristics are developed based on experience to decide what can immediately and automatically be removed, and what needs to be flagged for further inspection by domain experts, who then have a UI to tell the system their decisions. A fancier version may have a RuleBuilderInterface so that the domain experts can enter and manage most of their own scrubbing rules.
-
No, I mean an entire algorithm. An application is typically more than just an algorithm. An algorithm in an application is clearly identifiable. It's the part that (say) given input <x> and input <y>, produces output <z> via the following steps...
-
I could draw a fairly arbitrary line around a process or group of processes, but again it won't make much sense out of the original context. I think you are anthropomorphizing "algorithms" or something. You are implying a distinct trait that is not really distinct. It's a UsefulLie at best, but a fuzzy one.
-
Maybe. Or, maybe your algorithms are poorly encapsulated or -- as I've suggested all along -- you don't really have algorithms in the ComputerScience sense, which is the sense documented at http://en.wikipedia.org/wiki/List_of_algorithms.
-
One can put a thicker "capsule" around such, but I'm not sure it changes anything in terms of this topic. CBA generally trends toward gluing and weaving those kinds of pre-packaged "algorithms" together to build something for specific needs. Using a database or search engine as part of an app is an example. We figuratively go to Radio Shack or Capacitor Land to get pre-manufactured parts to build custom machines for our customers. We are not the part makers for the most part. If we make parts via chicken-wire and bastardizing an Erector Set widget, it's for a specific request, not intended to be a generic industry standard.
-
I see. You don't write algorithms in the ComputerScience sense, and if you use them, their use is dictated by their authors. As I've suggested before, it's therefore doubtful you'll see much need for HOFs unless their use is dictated by the authors of the algorithms you use.
-
You mean like the @#&%! JS/DOM timer API?
-
Yes. What don't you like about it? It's simple and fast. What's not to like?
It depends on how you define "algorithm". All that damned code is doing something. Perhaps you lean toward certain niches or specialties that shape your view of what CBA "looks like", and vice verse. We all only live one life and cannot easily hop into others' shoes. CBA's do tend to be a little bit of everything: a little bit of parsing, a little bit of semi-AI, a little bit of statistics, etc. However, most of the time, none of these algorithm-centric processing portions are big or involved enough to use the kinds of patterns you seem to be talking about. You don't implement 15 different optimization algorithms; for management picks their favorite and you implement one or two and it stays that way for a good line time. If it does become a "big deal", such as a line-of-business process, then specialists are then brought in or commercial software is purchased for that sub-niche. -t
Yes, I'm well aware of the "specialists are brought in" factor, having been one of the specialists brought in on various projects of this sort. The algorithm-centric processing portions I've worked on have used the patterns I'm talking about precisely to avoid having to implement any given algorithm more than once, and that's independent of how "big or involved" they are.
Perhaps. I didn't see the specs, change analysis, etc. for those, so I cannot comment. Most of the times such comes up, I've seen it done by purchasing/renting existing software, not custom solutions. Maybe your niche is those semi-rare cases where no commercial product is available that fits sufficiently. I'm a "rank and file" CBA developer for the most part and see "typical" requests from that perspective. I've worked with specialists such as statisticians, accountants, scientists, engineers, GIS (mapping), and even an AI expert once. These are usually special needs that generally require more specialized experience and/or degrees. If the org asks me for something outside of my expertise, I'll gladly suggest they find a specialist. I don't say, "I wont do it", rather I tell them it's new territory for me such that there is risk of failure. Sometimes they let me experiment, knowing there's no guarantee, sometimes not. I just state the risks as best I can. -t
-
What makes you think the "niche" I work (or have worked) in is "semi-rare" and it isn't your "niche" that is, in fact, "semi-rare"?
-
If your job is primarily focused on integrating existing software, or hiring specialists to provide you with software -- i.e., you're doing software integration and UI development -- I'm not surprised you see no need for HOFs. Given your role, you probably don't need them, because other programmers are benefiting from them on your behalf. I suspect you'll be seeing them in UI event handlers very soon, if you're not seeing them there already, and the increasingly event-driven nature of even server-side development will probably soon make them unavoidable.
-
Your characterization of my experience is false, but that's getting off topic and just turns into an unverifiable anecdote fight. Why would a UI client need to expose or depend on HOF's to do common events? Whether one can use them or put them in such a tool, you have not identified a realistic need/scenario/UseCase for them to exist in such. If you are so experienced in CBA's, you should be able to produce such scenarios. I don't understand why you are unable to. It appears to me you are being evasive. I'm telling you it's getting really frustrating. Just present a UseCase and draft up something with AsciiArtGuiShorthand, and go through step by step what the HOF improves over the competition. Sure, it's a little bit of work, but it's less work then arguing page after page over vague generalities. It's not logical to me.
That's just based on my experience and hanging around other CBA's, who fulfill a role similar to mine, but in different organizations or departments. The specialists tend to be either in-house specialists, such as statisticians and GIS experts; or they are "rented" from the outside for say special high-speed communications systems.
More on the Pete-82 example (above) in SwitchCaseListVersusHof.
And if the GUI/UI/Webpage kit is done right, then the fact that the event "snippet" (EventDrivenProgramming) is an object or a HOF or an Eval'd text code snippet or an asteroid behind the scenes would be generally irrelevant to the GUI designer. In fact, it should be mostly declarative so that one is not locked into a specific app language. But that's probably another topic (some of which already exist, such as GuiMarkupProposal). About 95% or higher of GUI actions desired we already know the conventions for such that we can "hard wire" then into a declarative event framework, at least for CBA UI's. We don't need need imperative code for such except the for specialized cases. We mostly have to worry about such low-level issues with today's tool because they suck! They are not abstracting away the common repetitive grunt-work and interaction details. The web made us go backward in time with regard to GUI management, and it also froze the more mature desktop tools, such as VB, Delphi, and PowerBuilder because vendor focus turned to the web in the late 90's. -t
Nice rant, but I'm not sure what it has to do with the real world we work in, except to show you don't like it.
I will concede that HOF's may work better in GUI/clients/browsers based around HOF's. Is that what you want to hear? It seems a narrow victory to me, but if it makes you feel good, then have a badge.
Note that GUI/clients/browsers are merely places where code runs. If HOFs benefit there, they can benefit anywhere code runs.
Yes, being stuck with the damned HtmlStack is indeed "real world", at least in terms of tool choices. But I'm more interested in general patterns of software design of CBA's, not tweaking with or working around flaws in specific languages or browsers. That's help-desk shit.
Are your user-support specialists aware that you speak of them in such disparaging terms? Tsk. Tsk.
Oh, I certainly hope not :-)
By the way, apostrophes indicate possession, not plurality. The plural of "apostrophe" is "apostrophes", not "apostrophe's". Same with "CBAs" and "HOFs"...
There are different opinions on that practice. Acronyms have different rules than "regular" words.
Example: http://public.wsu.edu/~brians/errors/acronyms.html
Well. Fair enough, then.
Even as a generally "normal" programmer, I've found higher-order functions very useful, particularly when doing things like integrating the same internal data objects with external data structures. I can define a function which converts a given data object to an external representation, pass that to a component that does external posts, and separate the concerns beautifully. It's also worth noting that even such simple things as map, filter, and reduce are HOF's. Writing a filter expression in Ruby or lisp is far better than writing 20 lines of code to do the same thing imperatively in Java. -bh
Footnotes
[1] I believe that WetWare issues are very important to software tool choices even though WetWare has been difficult to objectively quantify so far. But at least I cut one some slack if they disagree with a given WetWare model used to judge a tool. I don't feel I can insist something is "better" using WetWare-centric evidence until the science of WetWare is advanced enough (at which point the brain model could take our jobs anyhow :-) BrainEvidenceModelConundrum.
CategoryBusinessDomain CategoryFunctionalProgramming