Skipping Regexes in ES6 is Nothing Compared to Skipping Boolean-Comparison Warts

Posted Saturday, September 19th, 2015 at 3:10 pm

Yesterday, Wes Bos tweeted about ES6’s startsWith(), endsWith(), and includes() methods. He said it was “[t]hree less JavaScript Regexes you’ll have to write”.

Which is true, but I feel it misses the point. I mean, the regexes for initial match and final match are really not that hard, and the regex for plain inclusion is, well, basically the bare form of any regex: put slashes around it, and you’re done.

The coolest thing about these new methods isn’t the ability to change /^foo/, /foo$/, or /foo/ into just plain foo. That’s a savings of at most three keystrokes, and fairly little cognitive load. No, the coolest thing about these is not having to add != -1 at the end of them!

I think looking at it as “not having to write regexes” is really missing the point. In fact, I’m going to dust off something I wrote on a private Livejournal, back in 2007:

When doing regex matches on strings, I’m sick and tired of writing things like:

if (some_string.search(/some_regex/) != -1) {

In particular, it’s the bold part I object to. And for what it’s worth, there’s a similar wart in PHP, where searching for a substring requires the construct:

if (false === strpos($haystack, $needle)) {

In both of these languages, the problem is that the function or method that’s doing the searching isn’t returning a strict Boolean, but it is being evaluated in a Boolean context. PHP’s strpos() returns the position at which the needle starts in the haystack string (which may be zero if the needle is right at the beginning of the haystack), or FALSE if the needle isn’t there. JavaScript’s string.search() method similarly returns the position at which the matched text starts (which, again, may be zero), or -1 on failure.

And both of these languages evaluate zero as false in a Boolean context, so that you can find the text you’re looking for (right at the beginning of your string) and have the if statement claim it’s not there.

Perl avoids this entire problem by simply making a binding to a pattern match return Boolean, and not bother giving you the position. (To be honest, you hardly ever need the actual position.) And maybe I’ve been spoiled by years of writing things like:

if ($some_string =~ /some_regex/) {

…but, honestly, I think Perl is getting it right and the other two are getting it wrong.

So that’s what I wrote back in 2007. At that time, of course, PHP and Perl were both more significant; I wouldn’t mention them nearly as much today. Which is a bit of a shame, because the analysis of how too much information makes life harder is still apropos, and Perl still gets it right in a way that various other languages don’t.

The ES6 methods help fix that, because they just return Boolean, instead of getting all fancy-pants and giving you the position where the match was found. (In fact, back in 2007, when everyone was using Prototype.js and the idea of messing with built-in objects’ prototypes wasn’t as unfashionable as it is now, I pondered adding a function called “contains” to the String prototype in my company’s standard JavaScript library. And check it out; Firefox and Chrome have a String.includes() method, which used to be named contains() at least in Firefox.

But they still only take a case-sensitive string to search for, not a regex. Which makes me sad.

Post a Comment

Your email is never shared. Required fields are marked *

*
*