DEV Community

Robin Heggelund Hansen
Robin Heggelund Hansen

Posted on

The case for replacing Array.slice

I recently did some work which required me to create a sub-section of an Array. This can be done by using Array.slice but doing so always gives me the feeling that there is room for improvement.

To explain why, let's start by looking at a small example:

Array.slice 2 5 someArray

It isn't immediately obvious to me what this does. I know it creates a sub section, but when reading this I always have to stop up and calculate what the result will be. Usually, because I don't use this function too often, I also have to look up the documentation to check if the from and to indices are exclusive or inclusive.

The conclusion is that this particular code will create a new array, containing the values of indices 2, 3 and 4 of someArray. This might not seem too bad when you actually want to extract a sub-section of an array from some index and to (but not including) another, but in my experience that is rarely the case.

Usually what you -- well, I -- want is either to remove the first couple of elements, or to remove the last couple of elements. Since slice is all we got, we've always got to consider what value to use for both arguments, which adds a slight, but unnecessary, mental overhead.

For instance, removing the first two elements is implemented as:

Array.slice 2 (Array.length someArray) someArray

This doesn't read as easily as Array.drop 2 someArray, but another problem is that it doesn't play well with pipelines. Removing the last element is easier as slice supports negative indices, although it is a little more cryptic than it has to be:

Array.slice 0 -1 someArray

Even if you actually want a true sub-section, I'd argue that it would be easier to understand the code if you expressed it as two separate operations, like this:

someArray
  |> Array.drop 2
  |> Array.take 3  
Enter fullscreen mode Exit fullscreen mode

or

someArray
  |> Array.drop 2
  |> Array.dropLast 2
Enter fullscreen mode Exit fullscreen mode

In summary, I believe slice is a bad fit for functional programming. Using functions which have a clear intent and an intuitive usage is a better fit, and so I believe slice should be replaced with take, takeLast, drop and dropLast.

Top comments (4)

Collapse
 
herteby profile image
Simon Herteby • Edited

I searched my js code for .slice, and I think in every single case it could have been replaced by a single one of the take/takeLast/drop/dropLast operations.

Ie. there wasn't even one case where I actually dropped both the beginning and end of a String or Array, the thing that slice is optimized for.

And having to use Array.length is especially ugly indeed.

Btw, if/when you do make this change, it'd be nice to make the APIs of Array, List and String match more (String currently has left/right/dropLeft/dropRight for example.)
They are all lists of stuff after all!

Collapse
 
michaeljones profile image
Michael Jones

Thanks for the article. I'd agree that I have to check the docs every time for these kind of methods. I agree that drop & take methods more usable.

I'm curious though, as you understand these data structures very well, if you do want to take a middle slice is there any performance penalty in doing two steps instead of one? I guess there must be but perhaps is minor? I'm not sure I can remember a case where I needed to take a middle slice but as I said, just curious.

Collapse
 
robinheghan profile image
Robin Heggelund Hansen

Fun fact: Both in 0.18 and the upcomming 0.19, slice is actually implemented internally as array |> sliceLeft from |> sliceRight to.

So no, no performance change. In fact, since drop and take wouldn't need to convert negative indices to positive indices, it would likely result in a minor performance boost.

Collapse
 
robinheghan profile image
Robin Heggelund Hansen

I don't think there went a lot of thought into it. It simply maps the javascript API, which at first glance is a reasonable thing for a language geared towards web development.