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 myProcess01(7) if foo.setting < 4 then myProcess02() statusBox.value = "done with 2" end if logThingy(99) ''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
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] * See BradyBunchGridDiscussion ''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, F''''''itnessFunction 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