Ruby is known to support the functional paradigm. This article is going to walk you through the Functional Programming page on WikiPedia, to revise the general concepts of functional programming and to explain how Ruby supports them.
According to wikipedia, a functional programming can be described as follows:
In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state. Functional programming has its roots in the lambda calculus, a formal system developed in the 1930s to investigate function definition, function application, and recursion. Many functional programming languages can be viewed as embellishments to the lambda calculus.
That's a clear definition, however and if it's not, the following walk through some concepts of functional programming should result in a better understanding:
In practice, the difference between a mathematical function and the notion of a "function" used in imperative programming is that imperative functions can have side effects, changing the value of already calculated computations. Because of this they lack referential transparency, i.e. the same language expression can result in different values at different times depending on the state of the executing program. Conversely, in functional code, the output value of a function depends only on the arguments that are input to the function, so calling a function f twice with the same value for an argument x will produce the same result f(x) both times. Eliminating side-effects can make it much easier to understand and predict the behavior of a program, which is one of the key motivations for the development of functional programming.
Pure functions support the mathematical definition of a function:
y = f(x)
1- A function should return the same exact value given the same exact input.
2- A function does one thing exactly(has one clear mission), it has no side effects like changing some other value or write to stream or any other mission rather than its assigned one.
In fact Ruby doesn't force you to write pure functions, but certainly it helps you to do so. Actually exercising yourself to write in pure functional style when possible helps you really in many ways:
1- It makes your code clean, readable and self-documenting.
2- It makes your code more "thread safe"
3- It helps you more when it comes to TDD.
Let's have a look on how Ruby helps you do Pure functional code:
Most of Ruby programmers know the
! symbol that comes at the end of method names like
merge! and many other methods. The
! symbol means: "Use it cautiously". However If you focus more, you will notice that most of time, the
! symbol means: "This is a method that has a side effect; it alters the object which is invoked on!".
As you can see, the
upcase! method is not a pure functional method cause it has a side effect, it changes the string itself. On the other hand, the
upcase method is a pure functional one as it returns the corresponding value with no other side effects.
On all hows, it's highly recommended that you stick to this convention of method naming when you code in Ruby.
Everything is evaluated as an expression in Ruby: literals, method calls, variables... even a control structure has a value. For example you can do this in Ruby:
But that is a weak use of Ruby's power, instead you'd better do:
Ruby returns the last expression value as the return value of the method invocation, so you don't need an explicit
Together, the auto returned value and evaluating code as expressions are indeed a big support for pure functional code as finally they both serve the fact of having a value out of your method.
Functions are higher-order when they can take other functions as arguments, and return them as results. This is done in Ruby using lambda and block logic. If you don't know how to use blocks, please do yourself a favor and visit this comprehensive article by Robert Sosinski.
Blocks in Ruby can help you do very nice things, one of them is ability to add control structure like syntax to your code. Check the following example, where a loop control structure is being defined:
Internal DSLs is also one of the nice things that you can achieve with block syntax in Ruby.
Currying and Partial Functions
Higher-order functions enable Currying, which the ability to take a function that accepts n parameters and turns it into a composition of n functions each of them take 1 parameter. A direct use of currying is the Partial Functions where if you have a function that accepts n parameters then you can generate from it one of more functions with some parameter values already filled in. Ruby 1.9 comes with support for this concept. check the following example:
For extended example about currying, check Ruby Currying blog post by me ;) .
Type systems and pattern matching
Pattern matching allows complicated control decisions based on data structure to be expressed in a concise manner. in simpler words, it's a data structure based matching. Pure functional languages should support this concept, however and afaik this is still not supported in Ruby, but there are several trials to add this concept. check this blog post by Eric Torreborre.
Strict versus lazy evaluation
Strict evaluation always fully evaluates function arguments before invoking the function. Lazy evaluation does not evaluate function arguments unless their values are required to be evaluated. One use of Lazy evaluation is the performance increases due to avoiding unnecessary calculations.
However as the following example shows, Ruby use Strict evaluation strategy:
The third parameter of the passed array contains a division by zero operation and as Ruby is doing strict evaluation, the above snippet of code will raise an exception.
Iteration (looping) in functional languages is usually accomplished via recursion. Ruby doesn't force you to recursion but it allows you to do so. However following recursion style has it's own tax: Performance.
Ruby 1.9 comes with some "tail call optimizations", more here.
1- As you can tell, Ruby helps you write in functional style but it doesn't force you to it.
2- Writing in functional style enhances your code and makes it more self documented. Actually it will make it more thread-safe also.
3- The main support for FB in ruby comes from the use of blocks and lambdas, also from the fact that everything is evaluated as an expression.
4- Ruby still lack an important aspect of FP: Pattern Matching and Lazy Evaluation.
5- There should be more work on tail recursion optimization, to encourage developers to use recursion.
6- Any other thoughts?