As I’ve started learning Javascript, I’ve had alternating moments of progressively confusing rage, soul-encompassing “wat”, laced with moments of being genuinely impressed by Javascript’s functional elements. It’s like eating your least favorite ice cream flavor mixed with your favorite sprinkles.
However, as I’ve delved deeper into some of these features, I’ve been inspired to go back to Ruby and see which of these features have equivalents, and I’ve been pleasantly surprised to see that more than a few do.
In this first part, I want to explore how Ruby handles First-class Functions.
What is a First-class Function?
When a programming language is said to have First-class Functions, it’s a way of saying that the language allows for functions to be treated like objects, and passed back and forth as arguments.
So when we pass in a function as an argument in JS, or even get one back as a return value, we are exploiting this incredibly useful function of Javascript. As seen below:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Strictly speaking, ruby does not support First-class Functions. Methods cannot be return values or held in variables. But methods are far from all Ruby uses to implement functions. And some of these functions have Javascript-y super powers.
Blocks and Yield
Nearly anyone who has touched Ruby is probably familiar with a block. It allows us to customize methods by passing in custom instructions that are executed somewhere within the method, using the yield keyword.
1 2 3 4 5 6 7 8 9 |
|
In this example we are actually passing a block into a method twice, first when we call #some_method and next when we call the #each method. This is almost like passing a function as an argument, except we define the whole function, and instead of calling it by name, it gets called when we use the yield keyword. It’s pretty much a regular closure and it even has the coolest property of a closure, which is access to the scope in which it was defined.
1 2 3 4 5 |
|
But there is one important difference, we have to write out the function, we still are not assigning it to a variable.
However, there is a way we can do that!
Procs! Procs Everywhere!
A Proc is how ruby wraps a function into an object, and best of all, they can be defined and saved to variables! This means that they can be called at will with the .call method.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
You can even pass that Proc back and forth into functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
So far so cool right?
So quick recap, both blocks and procs allow you to pass code into other methods. BUT, procs are objects, and blocks are not. Procs can be passed into methods as arguments, and can be called with the .call(), and blocks can only be passed by writing the whole block out, they must be called with the yield function, and each method can only have one block.
Now let’s go deeper
How Many Procs could a Proc Block Proc if we use the Unary Operator?
Let’s take a look at this piece of code.
1 2 3 4 5 6 7 |
|
The first thing you should know, is that the ampersand is also known as the unary operator, and it’s a means of turning Blocks into Procs and visa versa. In the above example, it is used to turn the block into a proc, i.e. make it an object. Once it’s an object, we can call object methods on it, and see that it is actually a proc. The unary also works in the opposite direction, turning procs into blocks which can then be passed into methods that need a block.
1 2 3 |
|
This allows us to save methods in variables and pass them into blocks with relative ease. But there is one more step to consider when looking at how
Mary had a little Lambda
Now there is one more way in which Ruby supports first class functions: lambdas. Lambdas are actually a lot like procs, but almost a different “flavor”. Lambdas can be passed back and forth, and are called similarly to procs, but they are declared slightly differently, and have a few other important differences.
1 2 3 4 5 6 7 8 9 10 |
|
There are two other key differences, which very much affect the way these are used.
Arity Checking
As we’ve seen with Javascript, sometimes languages do not care about whether the number of arguments you pass to a function match the number of arguments that function takes.
Similar to Javascript functions, Procs will not throw an argument error if they are passed a varying number of arguments, while Lambdas do enforce argument strictness (or in other words, they arity check). This makes procs a little dangerous, only in the sense that they will fail silently if you mess something up (like Javascript), but they are also more flexible.
Return of the Lambda
Procs and Lambdas differ in the way that they return values to where they are called. A Proc does not create it’s own “return scope”, meaning it almost becomes a part of the function that calls it. So if a Proc triggers the return keyword, it will short-circuit the rest of the method that called it.
1 2 3 4 5 6 7 |
|
Lambdas are different, they do create their own return scope, so if a lambda triggers the return keyword, it will exit the lambda code, but return to the method that called it.
1 2 3 4 5 6 |
|
Recap
So let’s recap, one of the cooler things about Javascript is that it supports First-class functions, which means passing functions to functions and having them return other functions (some of which also take and return functions). FUNCTIONS. Being passed back and forth. Forever.
Turns out, ruby ain’t no slouch. Though the traditional method of passing code to functions through blocks is pretty limited, we still have the options of procs and lambdas, which give ruby true support for First-class functions.
Resources
I took a lot of things from people smarter than I, here they are: Functional Programming Techniques With Ruby: Part II
JavaScript’s Apply, Call, and Bind Methods are Essential for JavaScript Professionals