DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Data
  4. Imperative vs. Declarative JavaScript

Imperative vs. Declarative JavaScript

In this corner, weighing in at 7 lines of code, we have an imperative JS function, and in this corner, coming in at a lean, mean 2 LoC, declarative! Let's get ready to rumble!

Cliff Hall user avatar by
Cliff Hall
·
Feb. 12, 19 · Tutorial
Like (8)
Save
Tweet
Share
20.32K Views

Join the DZone community and get the full member experience.

Join For Free

I was recently doing a JavaScript code review and came across a chunk of classic imperative code (a big ol' for loop) and thought, here's an opportunity to improve the code by making it more declarative. While I was pleased with the result, I wasn't 100% certain how much (or even if) the code was actually improved. So, I thought I'd take a moment and think through it here.

Imperative and Declarative Styles

To frame the discussion, imperative code is where you explicitly spell out each step of how you want something done, whereas with declarative code you merely say what it is that you want done. In modern JavaScript, that most often boils down to preferring some of the late-model methods of Array and Object over loops with bodies that do a lot of comparison and state-keeping. Even though those newfangled methods may be doing the comparison and state-keeping themselves, it is hidden from view and you are left, generally speaking, with code that declares what it wants rather being imperative about just how to achieve it.

The Imperative Code

Image title

Let's break down the thought process required to figure out what's going on here.

  1. JavaScript isn't typed, so figuring out the return and argument types is the first challenge.
  2. We can surmise from the name of the function and the two return statements that return literal boolean values that the return type is boolean.
  3. The function name suggests that the two arguments may be arrays, and the use of needle.length and haystack.indexOf confirms that.
  4. The loop iterates the needle array and exits the function returning false whenever the currently indexed value of the needle array is not found in the haystack array.
  5. If the loop completes without exiting the function, then we found no mismatches and true is returned.
  6. Thus, if all the values of the needle array (in any order) are found in the haystack array, we get a true return, otherwise false.

The Declarative Code

Image title

Note: Tip o' the propeller beanie to Michael Luder-Rosefield who offered this solution which is much simpler than the previous version which used reduce. 

That took fewer lines, but you still have to break it down to understand what it's doing. Let's see how that process differs.

  1. JavaScript isn't typed, so figuring out the return and argument types is the first challenge.

  2. We can surmise from the name of the function and the returned result of an array's every  method that the return type is boolean.

  3. The function name suggests that the two arguments may be arrays, as do the default values now added to the arguments for safety.

  4. The  needle.every call names its current value  el, and checks if it is present in the haystack array using  haystack.includes.

  5. The  needle.every call returns true or false, telling us, quite literally, whether every element in the needle array is included in the haystack array.

Comparisons

Now, let's weigh the relative merits of each implementation.

Imperative

Pros

  1. The syntax of the venerable for loop is known by all.

  2. The function will return immediately if a mismatch is found.

  3. The for loop is probably faster (although it doesn't matter much at the small array size we're dealing with).

Cons

  1. The code is longer: 7 lines, 173 characters.

  2. Having two exits from a function is generally not great, but to achieve a single exit, it would need to be slightly longer still.

  3. While the loop does iterate the entire length of the needle array, it has to be explicit about it, and we need to visually verify the initializer, condition, and increment inspection. Bugs can creep in there.

  4. Comparing the result of the haystack.indexOf call to -1 feels clunky because the method name gives you no hint about what it will return if the item isn't found (-1 as opposed to null or undefined).

Declarative

Pros

  1. The code is shorter: 2 lines, 102 characters.

  2. The function will return immediately if a mismatch is found.

  3. The result of a single expression is returned, so right away it's obvious what the function is attempting to do.

  4. The use of needle.every feels satisfying, because the method name implies that we'll get a true or false result, AND we don't have to explicitly manage an iteration mechanism.

  5. The use of haystack.includes feels satisfying, because the method name implies that we'll get a true or false result, AND we don't have to compare it to anything.

Cons

  1. The every call is probably slower (although it doesn't matter much at the small array size we're dealing with).

Conclusion

Both of these implementations could probably be improved upon. For one thing, and this has nothing to do with imperative vs declarative, the function name and arguments could be given clearer names. The function name seems to indicate that we want to know if one of the arrays is an element of the other. The argument names actually seem to reinforce that. In fact, we just want to know if the contents of the two arrays match, disregarding order. This unintended misdirection creates mental friction that keeps us from readily understanding either implementation upon first sight.

Aside from naming issues, it looks like the declarative approach has more pros than cons, so on a purely numerical basis, I'm going to declare it the winner.

Implementing declarative code is widely expected to enhance readability. How it affects performance is another question, and one that should certainly be considered, particularly if a lot of data is being processed. If there isn't much performance impact, then a more readable codebase is a more manageable codebase.

If you see other pros or cons I missed for either of these contenders, or take issue with my approximation of their merits, please feel free to leave your comments. And again, thanks to Michael Luder-Rosefield for doing just that on the Medium version of this post.

JavaScript code style Data structure

Published at DZone with permission of Cliff Hall, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Spring Cloud: How To Deal With Microservice Configuration (Part 1)
  • The Real Democratization of AI, and Why It Has to Be Closely Monitored
  • Multi-Cloud Database Deep Dive
  • The Top 3 Challenges Facing Engineering Leaders Today—And How to Overcome Them

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: