This is the Electric Boogaloo in my series on discovering the functional and sexy aspects of Javascript within Ruby. For those of you who haven’t read Part I of this series, you should check it out, because I’ll be relying on a few of those concepts in the following blog.
Today, I want to explore the concept of currying, and borrowing code from other functions (or even entire functions) to write DRYer, more compact and elegant code. Brace yourselves:
Javascript - All Types of Curry
Before we delve into the depths of ruby madness, let’s wrap our heads around the concept of what it exactly means to borrow functions, and how it works in Javascript.
Javascript has three separate methods that all allow you to bend functions to your will (and to your specific purpose): Bind, Apply and Call. They each have their own limitations and purpose, so let’s go one by one and pick apart how each of these methods work.
The Ties that Bind()
Chances are, you’ve actually seen a good amount of the function .bind(), it’s a very common way to deal with the “this” problem in Javascript. In short, .bind() allows you to dictate what “this” will refer to inside the function at the time the function is called. From this property alone, you can probably guess how this will allow us to start borrowing functions.
When functions are written vaguely enough, operating on objects using primarily the “this” keyword, they become fairly easy to bend. Let’s take a look at an example:
1 2 3 4 5 6 7 8 9 |
|
In the function constructor we just defined, we managed to design the function costOfInventory so that it does not take any arguments, and only operates on properties attached to an object, referred to as this. Now we can use this function to refer to any object that has similar structure. For instance:
1 2 3 4 5 6 7 |
|
This gets even more powerful when you consider Javascript’s support for first class functions:
1
|
|
now wonkyWicket has effectively borrowed the costOfInventory function from the Widget constructor, and it can be called normally. BUT WAIT, there’s more! Bind can take additional arguments, and these arguments set default values for the arguments in function .bind() is being called on.
1 2 3 4 5 6 |
|
What the bind function is actually doing is creating a new function with default values in the place of the arguments that you defined in bind. This process is known as currying or partial function application. You substitute hard values for arguments, thus modifying the function.
Nuts right? And it gets even better when we start dealing with useful things like arrays and strings.
One important thing to note that will persist with us is that it’s not as simple as calling .bind(), there is a decent amount of prep involved. Being able to borrow or curry functions is something you have to think through from the beginning, almost like how a certain design principles have some upfront work, but make your life easier down the road.
I’m Call()in' you Out, Apply() Yourself!
The last two methods we are going to go over are .call() and .apply().
Truth be told, these functions are very similar to .bind() but there are a few key differences. Let’s start with the differences between .bind() and .call().
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Here we begin to see the difference between these two very similar methods. They both set “this” with their first argument and set subsequent arguments in the method with their next parameters. However, .bind() returns a new function, whereas .call() immediately evaluates the function it’s called on with it’s special parameters.
.apply() is more similar to .call() than .bind(). In fact, the only difference is in the way .apply() is called.
1 2 3 4 5 6 7 8 9 10 |
|
As you can see, the arguments passed through .apply() must be passed in an array. This is useful for functions where the arguments being passed in are more flexible or optional.
A Ruby in the Rough
As we’ve spoken about before, Ruby can play functional with the big dogs, and as it’s evolved as a language, it’s gained even more functional properties. We’re going to explore a few ways of replicating this awesome functionality from Javascript.
Waddya Mean Modules?!
The first method of sharing methods between classes is one we are all pretty familiar with. A Module is a different type of object that can mix methods into another class. Much like binding this to a function, the Module and Class need to share certain functionality to begin with.
1 2 3 4 5 6 7 8 9 |
|
As long as a class has a name attribute, it can easily become “Greetable” by using the following code:
1 2 3 4 5 |
|
Now person has the methods #say_hi and #say_bye!
I won’t delve too far into Module functionality, since it’s pretty well covered, but this is a peek at how Ruby can share methods between classes. Much like Javascript leverages the “this” keyword to allow for code that is applicable in many scenarios, Ruby’s “self” keyword affords similar functionality in it’s Object Oriented design.
Call me Ruby?
Turns out that Ruby has it’s own version of .call() and unsurprisingly it’s strongly related to the Proc class. Any proc accepts a message of .call as a command to run the code inside the proc, so simply put, it’s a way of running a proc. Given that Procs don’t arity check (unless they are lambdas), this can be used to replicate some of the usefulness of .call() or .apply(). However, as of Ruby 1.9.3 there is one slightly more useful function.
Keep Calm and Curry On
Ruby gained full partial function application support when it added the .curry function. In 1.9.3 .curry could be called on any proc or lambda and it would return a new proc or lambda that had one of it’s arguments set with a specific parameter. If this functionality is still a bit fuzzy, ponder the following code.
1 2 3 4 5 6 7 |
|
This bit of metaprogramming is pretty straightforward, but we can break this down a bit further using #curry.
1 2 3 4 5 6 7 |
|
When we called #curry on #do_math we set the first argument (the operator) and store the resulting function in a new variable. We can even take this a step further.
1 2 |
|
As you can see, the potential here to dry up code is enormous. If one designs their functions properly, one function is powerful enough to write plenty. However, the key word is “design”, it takes a lot of planning or refactoring in order to achieve this next level DRYness.
Final Note
As of Ruby 2.2.0 there is now a way to call curry on any method (instead of just on procs and lambdas). It looks something like this:
1 2 3 4 5 6 |
|
If you’d like to read more, check out the documentation on 2.2.0’s method class - there is lot’s of other cool functional aspects there.
Resources
You know, because god knows I didn’t learn this on my own.
- Javascript is sexy
- Stackoverflow Answer
- Good blog on apply and bind
- How I even learned about Currying
Lastly, RUBY CURRY