DEV Community

Discussion on: Why you need the tap method

Collapse
 
blindfish3 profile image
Ben Calder

Interesting... but you need a warning that this is an anti-pattern:

Array.prototype.tap = function() {
    // ...
};

You should almost always avoid adding to built-in prototypes!

I also may have misunderstood the problem; but why not do everything in a single reduce?

const input = "732829320";

const valid =
    input.split('') // old-school conversion of string to array :)
        .reduce((sum, character, index) => {
          console.log(character);
          // assuming you're confident you're getting numerical values
          // in your string you can use `+`` instead of parseInt
          const digit = index % 2 === 0 ? +character : +character * 2
          return sum + (digit > 9 ? digit - 9 : digit);
        }) % 10 === 0;

console.log(valid);

If nothing else you can achieve the equivalent of your tap method with map:

.map(character => {
          console.log(character);
          return character;
        })
Collapse
 
aminnairi profile image
Amin

Hi Ben and thanks for your answer.

Interesting... but you need a warning that this is an anti-pattern:
You should almost always avoid adding to built-in prototypes!

Maybe I didn't quite catch all that was in your example but could you elaborate more on how is this an anti-pattern? I think it can greatly benefit to others reading your comment!

From my personal point of view, I don't think it is an anti-pattern as it is a feature of the language that, well used, can be really useful, powerful and cool to use! And by well used, I mean no overriding of existing prototypes, just augmenting the capabilities of the language as I said in this post. I also said that maybe they (the TC39 committee's people) will add a tap method but looking at what the proposals are here, I think we are good for a while since it is not even a staged feature (and probably never will, but I can dream, right? haha).

I also may have misunderstood the problem; but why not do everything in a single reduce?

That's a really great way of reducing the complexity of the problem. That clearly makes it shorter. But maybe harder to work on.

Unfortunately, that was not the point of this article as this was only a pretext to show how to use the tap prototype we built in this post. But I'll keep in mind your idea as it may serves me someday! Thanks for pointing that out. I'll update my post accordingly to explain clearly that this is not a production code.

If nothing else you can achieve the equivalent of your tap method with map:

You are correct! That's an another way of doing the tap method as an equivalent. But isn't it a bit of a mouthful though? Adding the tap method with the console.log call just between two map calls seems to me shorter, easier to work with especially when doing only debugging. If I ever forgot to put the last return at the end, I'll end up with two bugs (the one that I am looking for and this one). Plus it forces you to write two separate instructions as the console.log call does not return the called arguments (unfortunately).

I guess what I am trying to say here is that JavaScript is a wonderful piece of programming language and that it supports many programming paradigms. It's up to the reader to choose how he want to use this language. I'm just trying to show other opportunities of doing things but it absolutely does not mean that it's the best way of doing it. Maybe it won't suit you and that's fine to me.

Again, thank you for your comment. I'm taking notes of what you said to improve my article!

Collapse
 
blindfish3 profile image
Ben Calder • Edited

The reason for not extending built-in objects is well documented and founded on historical experience. It's a similar reason for avoiding global variables: you risk naming clashes and unexpectedly breaking code elsewhere in your application.

I'm not saying the approach is entirely without merit; but I think it's sensible to include a warning about this up-front so people understand the risks ;)

You do (later) add a guard; but you only talk about 'tap' being added to the language. But the problems come when you're working with multiple libraries; each of which extends the same native object with a same named function; each with a different implementation... Welcome to bug hell :(
Extending native prototypes happened a lot in the early days of JS; and people soon realised it was a really bad idea.

Understood on this being example code; and agreed that the solution does boil down to coding style ;)
The suggestion to use map() with a console log was included to show that there was a simple enough alternative to tap that didn't come with the risk of extending the native prototype.

And my comment wasn't meant as a criticism: it's a good article; and if nothing else highlights JavaScript's often misunderstood use of prototype-based inheritance.

Thread Thread
 
aminnairi profile image
Amin

Thanks for clearing that out!

I'm divided between showcasing a feature, but knowing this is a risky one that can be misused or not sharing something that could be useful for others. But in the end, I always end up sharing with the community! That's why I try to add as many guards as possible and experiment a little bit on my own. As shown in this article.

Agreed on saying that using this pattern in a library and sharing that with the OSS community can lead to several and critical bugs, that's why I personally never do that (mostly because I'm only working in a private community and rarely write entire modules for the OSS community, unfortunately!).

But this is a subject I would love to talk about for hours and would greatly deserve an entire post...!