Using Functions to Abstract Away Complex Logic: Higher Order Functions - Part I

in Programming & Dev4 years ago

Interconnected Plugs
Photo by Claudio Schwarz | @purzlbaum on Unsplash

<p dir="auto">I <a href="https://peakd.com/hive-169321/@yokunjon/power-of-functions-as-an-explicit-statement" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">talked about how naming blocks with functions can abstract away general information and ease the mental process. Now, I would like to talk about how functions can create <em>complex yet easy to understand abstractions. <p dir="auto">Most languages distinguish a function from a <em>variable, which results in functions being more limited than variables. But, able to use functions in the place of variables is a <em>useful feat. This is known as <strong>"first-class citizen function support". <p dir="auto">In the early years of computer science; only high-level, functional languages had full first-class function support. But as processors and compilers improved, object-oriented and imperative languages also added support for it under the name of <strong>closures/lambdas/anonymous functions. While they are not <em>flexible as their counterpart, they are <em>sufficient to accomplish most of the tasks. So, learning them and using them to abstract information is a good investment. <p dir="auto">I'll use JavaScript as I did in my previous post. In JavaScript, there are 2 kinds of functions, <em>functions and <em>arrow functions. While functions can be both <em>named and be <em>anonymous, arrow functions can only be <em>anonymous. Arrow functions are mainly used for their shorter syntax, but actually, there are <em>subtle differences. We won't be talking about those as it is not in the context of this post. So, we can assume <code>functions = anonymous functions for the sake of this post, and apply the concepts to <em>both. <p dir="auto">Before starting out, I would like to point out my <em>preference, so it wouldn't interfere with the content. I prefer using named functions in global scope while using anonymous arrow functions for anything else. This helps me to spot general functions easily thanks to the function syntax. Here is the reference: <p dir="auto"><img src="https://images.hive.blog/768x0/https://i.imgur.com/leQbwIt.png" alt="My Preference" srcset="https://images.hive.blog/768x0/https://i.imgur.com/leQbwIt.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/leQbwIt.png 2x" /> <p dir="auto">So, the concepts I'll be using are not related to my preference, you can freely use your own style. That out of the way, let's start by talking about a common concept named <strong>higher-order functions. <p dir="auto"><em>Higher-order functions are the <em>functions that can <strong>accept functions as an argument, <strong>return functions when executed or <strong><em>both. Here are all of them as snippets: <p dir="auto"><strong>Functions as argument<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/MpBVPJ0.png" alt="Functions as argument" srcset="https://images.hive.blog/768x0/https://i.imgur.com/MpBVPJ0.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/MpBVPJ0.png 2x" /> <p dir="auto"><strong>Functions as return statement<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/y1WhZal.png" alt="Functions as return statement" srcset="https://images.hive.blog/768x0/https://i.imgur.com/y1WhZal.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/y1WhZal.png 2x" /> <p dir="auto"><strong>Both<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/9rVjbfg.png" alt="Both" srcset="https://images.hive.blog/768x0/https://i.imgur.com/9rVjbfg.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/9rVjbfg.png 2x" /> <p dir="auto">These might look daunting at first, but they all make sense and easy to understand. If you are unfamiliar with them, I <strong>suggest checking those out after reading all the post and try to figure them out. <p dir="auto">Let's start basic, imagine having a function like this:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/8dnE42V.png" alt="Wave function" srcset="https://images.hive.blog/768x0/https://i.imgur.com/8dnE42V.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/8dnE42V.png 2x" /><br /> As you can see, we can call it wherever we like, right? For example, we can use our function from another function like this:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/Ct2SRRu.png" alt="Calling wave from interact" srcset="https://images.hive.blog/768x0/https://i.imgur.com/Ct2SRRu.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/Ct2SRRu.png 2x" /><br /> Now, let's imagine that we need to add <em>a name argument in our functions:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/hZ12V5f.png" alt="Adding name argument" srcset="https://images.hive.blog/768x0/https://i.imgur.com/hZ12V5f.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/hZ12V5f.png 2x" /><br /> While this is perfectly okay, imagine that the next day our business requirements <em>changed and they expect <em>another interaction from us, named smile:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/wuiobVo.png" alt="Smile function" srcset="https://images.hive.blog/768x0/https://i.imgur.com/wuiobVo.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/wuiobVo.png 2x" /><br /> Now, we have to edit our interact function, but how? As our example is basic, of course, we could use wave and smile without the need to interact function. But that would defeat our purpose here, interact function might handle more things and putting those into wave and smile would complicate them further. Those functions should only be responsible for one thing, waving and smiling. <p dir="auto">We could also do something like this with string concatenation, but that also contradicts my previous statement.<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/9A1BIXz.png" alt="String concatenation" srcset="https://images.hive.blog/768x0/https://i.imgur.com/9A1BIXz.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/9A1BIXz.png 2x" /> <p dir="auto">And this also prevents us to use functions for more complex scenarios like this:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/Hi3gNwU.png" alt="Edge case" srcset="https://images.hive.blog/768x0/https://i.imgur.com/Hi3gNwU.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/Hi3gNwU.png 2x" /><br /> Of course, the answer is <strong>Higher-Order Functions! Unlike the fancy name, it is pretty <strong>straightforward. We just pass our function as a parameter and call the parameter as if it were a function (it is).<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/kylhrKw.png" alt="Interaction converted into higher-order function" srcset="https://images.hive.blog/768x0/https://i.imgur.com/kylhrKw.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/kylhrKw.png 2x" /> <p dir="auto">And to use it, it is simple as this: <p dir="auto"><img src="https://images.hive.blog/768x0/https://i.imgur.com/3C66MTM.png" alt="Full implementation" srcset="https://images.hive.blog/768x0/https://i.imgur.com/3C66MTM.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/3C66MTM.png 2x" /> <p dir="auto">This example might seem trivial, but there are countless places HOFs can be used to <em>adhere DRY principle and abstract out common concepts, like <strong><em>loops. <p dir="auto">We might have something like this:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/Fxx5iSO.png" alt="Foods and sugars example" srcset="https://images.hive.blog/768x0/https://i.imgur.com/Fxx5iSO.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/Fxx5iSO.png 2x" /> <p dir="auto">We have an <em>array of food objects, each having <em>sugar, <em>protein and <em>water properties. We would like to get just names and sugars from it and save those as <em>another array. To accomplish that, we can utilize a <em>for loop like that. But if we try to add another function like <em>getProteins, it duplicates a lot of code. <p dir="auto"><img src="https://images.hive.blog/768x0/https://i.imgur.com/c9gV7Pz.png" alt="getProteins function" srcset="https://images.hive.blog/768x0/https://i.imgur.com/c9gV7Pz.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/c9gV7Pz.png 2x" /> <p dir="auto">If we had a bug in that loop, we would also copy that. And without guessing from the look, understanding what's going on requires some processing in our brain. This is one of the main reasons we have bugs in our code, because most of the time we assume what code does, or precisely, what we expect from it; rather than actually processing. <p dir="auto">So, how can we abstract that? We need to look at what is important here, what we can abstract. There should be generic reasoning behind it. As we can see, this function loops over an array and gets each item, processes them and adds those to a new array. This has a name, <strong><em>mapping. So, we could create a HOF like this:<br /> <img src="https://images.hive.blog/768x0/https://i.imgur.com/w6GgMxF.png" alt="map HOF" srcset="https://images.hive.blog/768x0/https://i.imgur.com/w6GgMxF.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/w6GgMxF.png 2x" /> <p dir="auto">What have we done? Simple, we changed 2 things; we pass array we loop as a parameter and we used a parameter named callback, left the processing data part to it. We can use it simply like this: <p dir="auto"><img src="https://images.hive.blog/768x0/https://i.imgur.com/1HBEtNr.png" alt="map HOF with usage" srcset="https://images.hive.blog/768x0/https://i.imgur.com/1HBEtNr.png 1x, https://images.hive.blog/1536x0/https://i.imgur.com/1HBEtNr.png 2x" /> <p dir="auto">Not we just reduced the lines, we also abstract away mapping. Before, we had to guess or process what it does. But now, we can understand what it does simply by looking up to name, <strong>map. It maps, which means it loops the array, processes it and adds them in the same order, with one-by-one correspondence. Now we can use this function anywhere we like. If we had any bug in that, we only have to change that one function. This is so common, it is <strong><em>implemented in JavaScript ten years ago:<br /><span> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map <p dir="auto">There are other HOFs like this named filter, forEach, flatMap, reduce and the list goes on. I suggest checking them out. <p dir="auto">We talked about <em>first-class function support, <em>HOFs, how we can compose a <em>HOF that accepts parameters as functions and a <em>real-life example of that. Next, I'll be talking about <em>composing functions from HOFs, how it can be done and real-life example of that. Then, I'll talk about some <em>useful tricks that can be used with this knowledge. <strong>I don't know how many parts will be there, but <strong>this is the end of part one. <a href="https://codesandbox.io/s/using-functions-to-abstract-away-complex-logic-higher-order-functions-part-i-402pp" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Here is the code I used in this post. <p dir="auto">Thanks for joining me in my TED talk :D! Feel free to <strong>suggest or criticize. See you in the next part.