Not so easy functional programming in JavaScript

Introduction

JavaScript allows for operating on arrays in a functional way, e.g. using filter or map functions. As an argument for these functions we can pass lambda expression or function reference. Is there a difference between them? The answer is yes.

What’s the problem?

In our project we are building a mapping using String.fromCharCode function. To simplify the usage of this function looked similar to:

[66, 67, 68].map(v => String.fromCharCode(v))

When we run this code with node we received [ 'B', 'C', 'D' ], but when we decided to refactor it to use function reference the result was different:

> [66, 67, 68].map(String.fromCharCode)
[ 'B\u0000\u0000', 'C\u0001\u0000', 'D\u0002\u0000' ]

What happened?

To find the reason for this behavior, let’s first play with function String.fromCharCode alone:

> String.fromCharCode(66)
'B'
> String.fromCharCode([66, 67, 68])
'\u0000'
> String.fromCharCode(66, 67, 68)
'BCD'

String.fromCharCode deals with various types and numbers of arguments.

Now, let’s examine the function map:

> [66, 67, 68].map(v => v)
[ 66, 67, 68 ]
> [66, 67, 68].map((v, u) => [v, u])
[ [ 66, 0 ], [ 67, 1 ], [ 68, 2 ] ]
> [66, 67, 68].map((v, u, w) => [v, u, w])
[ [ 66, 0, [ 66, 67, 68 ] ],
  [ 67, 1, [ 66, 67, 68 ] ],
  [ 68, 2, [ 66, 67, 68 ] ] ]

map, like many other array functions, passes always three arguments to function. First is the current value, the second is the index of the current value and third is the whole array.

It means that passing String.fromCharCode to map function under the hood looks like this:

> [66, 67, 68].map((v, u, w) => String.fromCharCode(v, u, w))
[ 'B\u0000\u0000', 'C\u0001\u0000', 'D\u0002\u0000' ]

and it is equal to the initial example.

Conclusion

We must be careful when we want to use a function that can take more than one argument, but we want to pass only the value. We have to pass the function as a lambda expression:

> [66, 67, 68].map(v => String.fromCharCode(v))
[ 'B', 'C', 'D' ]

or create another function which ensures that only the first argument will be passed to desired function:

> const useOnlyValue = f => v => f(v);
undefined
> [66, 67, 68].map(useOnlyValue(String.fromCharCode))
[ 'B', 'C', 'D' ]
You May Also Like

Simple HBase ORM

When dealing with data stored in HBase, you are quick to come to a conclusion, that it is extremaly inconvenient to reach to it via HBase native API. It is very verbose and you always need to convert between bytes and simple types - a pain. While I wa...When dealing with data stored in HBase, you are quick to come to a conclusion, that it is extremaly inconvenient to reach to it via HBase native API. It is very verbose and you always need to convert between bytes and simple types - a pain. While I wa...

Distributed scans with HBase

HBase is by design a columnar store, that is optimized for random reads. You just ask for a row using rowId as an identifier and you get your data instantaneously. Performing a scan on part or whole table is a completely different thing. First of all, it is sequential. Meaning it is rather slow, because it doesn't use all the RegionServers at the same time. It is implemented that way to realize the contract of Scan command - which has to return results sorted by key. So, how to do this efficiently?HBase is by design a columnar store, that is optimized for random reads. You just ask for a row using rowId as an identifier and you get your data instantaneously. Performing a scan on part or whole table is a completely different thing. First of all, it is sequential. Meaning it is rather slow, because it doesn't use all the RegionServers at the same time. It is implemented that way to realize the contract of Scan command - which has to return results sorted by key. So, how to do this efficiently?

Using Eclipse snippets for faster JUnit test creation (with Mockito!)

I'm using this snippet to create a template of new unit test method supporting BDD mockito tests. This is a good example for adding static imports to a class from snippets.@${testType:newType(org.junit.Test)}public void should${testname}() { ${staticIm...I'm using this snippet to create a template of new unit test method supporting BDD mockito tests. This is a good example for adding static imports to a class from snippets.@${testType:newType(org.junit.Test)}public void should${testname}() { ${staticIm...