Composing Code: Striking a Chord with Functional and Object-Oriented Paradigms in R

Numbers around us
Numbers around us
Published in
10 min readJul 10, 2023

Conducting the Symphony: Understanding Paradigms in R

A symphony orchestra is a marvel of coordination. Various musicians, each skilled in their instruments, collectively produce a harmonious composition under the guidance of the conductor. This scenario isn’t too different from the world of programming. Just as a conductor navigates the orchestra through the progression of a symphony, programming paradigms guide us in structuring our code to yield efficient, maintainable software.

A programming paradigm is a philosophy, or style, that dictates how we write and organize code. There are several paradigms in the programming world, each offering a different perspective on how to approach problem-solving. The key paradigms include procedural, functional, object-oriented, and declarative, each playing their distinctive tunes in the software symphony.

The procedural paradigm, akin to a solo musician’s performance, focuses on step-by-step instructions. It’s all about performing one task after another in a particular order, like playing the notes of a music sheet from start to end.

The functional paradigm, more like an improvisational jazz band, views computation as the evaluation of mathematical functions, discouraging changing-state and mutable data.

The object-oriented paradigm, like a group of musicians, groups related variables and functions into objects, similar to different sections of an orchestra playing in harmony.

Lastly, the declarative paradigm, similar to a composer conveying intent without specifying technique, focuses on the logic of computation without detailing the control flow.

Within the vast expanse of data analysis, a prominent melody reverberates across the concert hall — the tune of the declarative paradigm. This paradigm focuses on what the program should accomplish without outlining how to achieve it. This concept manifests in the R symphony through packages like dplyr, where you simply declare your intentions to the data, and the package orchestrates the best approach.


library(dplyr)
starwars %>% filter(species == “Droid”)

However, the main stage of R belongs to the functional paradigm. Rooted in its origins in the S language, designed primarily for statistical computing, R has long danced to the rhythm of functional programming. In this paradigm, functions in R are first-class citizens, meaning they can be assigned to variables, listed, passed as arguments to other functions, and more. This encourages a style of programming where functions are the principal components of the composition.

In the upcoming sections, we’ll explore the solo performances of the functional and object-oriented paradigms. Stay tuned as we delve into the nuances of these fascinating approaches.

Solo Performance: Introducing the Functional Paradigm

Imagine a solo musician lost in the depths of their performance, each note a standalone entity, contributing to the melody but unaffected by its surroundings. This image paints a fitting metaphor for functional programming, where each function stands alone, independent, and unchanging.

In functional programming, functions are the stars of the show — the main melody of our solo performance. They don’t alter the state of the world around them. Instead, they take inputs and produce outputs, much like how a musician takes breaths and produces notes.

An essential characteristic of functional programming is that functions are ‘first-class citizens.’ This status means that functions in R can be treated like any other variable. They can be assigned to variables, stored in lists, or passed as arguments to other functions.

Take the following example:


# Function that adds two numbers
add <- function(x, y) {
return(x + y)
}

# Assigning function to a variable
my_add <- add
print(my_add(5, 3))

# 8

# Storing functions in a list
my_list <- list(“add” = add)
print(my_list$add(4, 2))

# 6

# Passing function as an argument to another function
apply_function <- function(func, x, y) {
return(func(x, y))
}
print(apply_function(my_add, 7, 1))

# 8

In this metaphorical solo performance, our musician — the function — performs its piece, the operation, without any concern for or impact on the other musicians. It hits its notes (returns its outputs) based solely on the breaths it takes (inputs it receives), creating a performance that’s both harmonious and predictable.

As we tune our instruments for the next act, we’ll switch gears and look at another member of our band — the object-oriented paradigm.

Harmonious Ensemble: Introducing the Object-Oriented Paradigm

Picture an ensemble of musicians, each equipped with a unique instrument, interacting with one another to create a synergistic melody. This is the spirit of the object-oriented (OO) paradigm — an orchestration of interconnected objects, each contributing its distinctive tone to the grand symphony.

Just like each musician in an orchestra, an object in OO programming is an entity equipped with specific information (data attributes) and abilities to perform actions (methods).

In R, a powerful way to implement OO programming is through the R6 system. Unlike other OO systems in R, R6 allows the objects to have reference semantics. This means an object can be modified in place, similar to how a musician can alter the melody while playing.

Let’s illustrate this concept using R6:


# Load the R6 package
library(R6)

# Define a Musician class
Musician <- R6Class(“Musician”,
public = list(
instrument = NULL,

initialize = function(instrument = “Violin”) {
self$instrument <- instrument
},

play = function() {
cat(paste0(“Playing beautiful “, self$instrument, “ notes.\n”))
}
)
)

# Create a new musician
violinist <- Musician$new(“Violin”)

# Test our object and method
violinist$play()

Playing beautiful Violin notes.

In this melody of code, each Musician object (musician) knows its instrument and can play it, creating a symphony as complex as the interactions between objects. As we progress in our concert of paradigms, we will see how this symphony harmonizes with the solo performance of the functional paradigm.

Duet or Solo: Pros and Cons of Functional and Object-Oriented Paradigms

In the realm of data analytics, whether to approach a problem as a virtuoso soloist (functional programming) or a harmonious ensemble (object-oriented programming) depends on the nature of the composition — the data and the tasks at hand. Both paradigms have their unique strengths and potential challenges.

Functional Programming: The Solo Virtuoso

Pros:
1. Purity: Much like a solo performance’s clear, unadulterated melody, functional programming, with its focus on pure functions, encourages simpler, more predictable code. This quality is ideal for data transformation and statistical tasks where clarity and predictability are paramount.
2. Modularity: Like a virtuoso moving deftly between different parts of a composition, the functional approach promotes modular code. This enables easy reuse of data processing routines and simplifies the testing process — key aspects in the data analytics pipeline.

Cons:
1. Abstraction: Just as a complex solo piece can be challenging for the untrained ear, the high level of abstraction in functional programming can be a steep learning curve, especially for data professionals new to programming.
2. Verbosity: The functional approach can be verbose, requiring more explicit data manipulation steps. This could make code harder to read and maintain, particularly in complex data transformation tasks.

Object-Oriented Programming: The Symphony Orchestra

Pros:
1. Organization: OO programming groups related data and functions into objects, like musicians in an ensemble. This can be particularly useful for creating complex data models or managing large-scale data systems in analytics work.
2. Encapsulation: Like the subtle interplay of instruments in an orchestra creating a beautiful, unified piece, OO programming hides complexity behind methods and objects. This allows data professionals to create custom data types that encapsulate complex behaviors, simplifying code and enhancing readability.

Cons:
1. Mutability: As in a live orchestra performance where unforeseen changes can occur, OO programming’s mutability can introduce unexpected behaviors in data analytics code if not managed properly.
2. Overhead: Using OO programming for simple data tasks might be like employing a full orchestra for a simple tune — overkill. The OO approach might introduce unnecessary complexity for straightforward tasks.

Choosing the right paradigm is like composing a melody, knowing when to allow the purity of a solo to shine and when to let the orchestra’s richness take the stage. Next, we’ll look at the fascinating harmony that emerges when these two paradigms play together in R.

Harmonizing the Paradigms: Conducting the Duet in R

Music reaches its peak when all elements harmonize perfectly, creating a magnificent symphony of notes. This concept rings true in R programming, where the virtuoso soloist (functional paradigm) and the orchestra (object-oriented paradigm) can produce a spectacular duet.

In the R language, both paradigms are more than mere audience members; they actively participate and contribute to the grand musical performance, making R a multi-paradigm language.

Consider the simple act of transforming data, a staple task in any data analyst’s repertoire. Let’s take the built-in “mtcars” dataset as an example. To compute the average miles per gallon (mpg) by the number of cylinders in the car engine (cyl), we might use the functional programming approach with the dplyr package:

library(dplyr) 

mtcars %>%
group_by(cyl) %>%
summarise(avg_mpg = mean(mpg))

# A tibble: 3 × 2
cyl avg_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1

In the above, the %>% operator pipes data through a series of functions (group_by and summarise). Each function receives the output of the previous function as its first argument, much like a soloist who skillfully weaves together successive musical phrases.

In contrast, object-oriented programming allows us to encapsulate related data and functions within an object. For example, using the R6 package, we could define a “CarAnalysis” class that encapsulates our data and the analysis method:

`library(R6)

CarAnalysis <- R6Class(“CarAnalysis”,
public = list(
data = NULL,

initialize = function(data = mtcars) {
self$data = data
},

avg_mpg_by_cyl = function() {
self$data %>%
group_by(cyl) %>%
summarise(avg_mpg = mean(mpg))
}
)
)

car_analysis <- CarAnalysis$new()
car_analysis$avg_mpg_by_cyl()

# A tibble: 3 × 2
cyl avg_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1

In this scenario, the “CarAnalysis” object is like an orchestra, coordinating different instruments (functions and data) to create a unified musical composition (data analysis).

The real beauty of R lies in its ability to harmonize these two paradigms. You could use functional programming for its clarity and simplicity in data transformations, and object-oriented programming to organize larger systems and abstract complexities. Such harmonious duet creates a more flexible, powerful symphony of data analysis.

In the next section, we’ll explore where to best apply each of these paradigms in the grand composition of data analysis.

Finding the Melody: Choosing the Right Paradigm for Your Data Symphony

Choosing between a virtuoso soloist (functional programming) and a symphony orchestra (object-oriented programming) is like choosing the right instrument for a particular piece of music — it’s all about the nuances of the melody, the nature of the composition, and the atmosphere you wish to create.

When writing an R script, consider the nature of your data and the complexity of the operations you wish to perform. Here are some broad guidelines to help you set the right tone for your data symphony:

1. Simple data transformations: If your task involves transforming data from one format to another, or applying statistical operations, consider using the functional programming paradigm. R’s dplyr and tidyr packages, among others, are excellent tools for these tasks. The clear and concise syntax can be akin to a solo virtuoso playing a soothing melody that resonates with clarity and coherence.


# Example with dplyr
mtcars %>%
group_by(cyl) %>%
summarise(avg_mpg = mean(mpg))

# A tibble: 3 × 2
cyl avg_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1

2. Complex data structures: If you’re working with complex data structures or large-scale data systems, object-oriented programming can be a more suitable choice. Like the different sections of an orchestra coming together to perform a complex symphony, the encapsulation and organization provided by OOP can help manage complexity.


# Example with R6
CarAnalysis <- R6Class(“CarAnalysis”,
public = list(
data = NULL,

initialize = function(data = mtcars) {
self$data = data
},

avg_mpg_by_cyl = function() {
self$data %>%
group_by(cyl) %>%
summarise(avg_mpg = mean(mpg))
}
)
)

car_analysis <- CarAnalysis$new()
car_analysis$avg_mpg_by_cyl()

# A tibble: 3 × 2
cyl avg_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1

3. Integrative tasks: For tasks that involve a mix of data transformations and complex operations, don’t be afraid to blend paradigms. Just as a musical composition can feature both a soloist and an orchestra, R allows for a harmonious blend of functional and object-oriented programming. This flexibility can be especially useful in larger projects, where different parts of your codebase may benefit from different paradigms.

In the end, choosing a programming paradigm in R is like composing a piece of music — it’s a creative process guided by the needs of your specific task. By understanding both the functional and object-oriented paradigms, you can choose the right approach to play a beautiful symphony on the vast keyboard of data analysis.

Like the grand finale of a symphony performance, where the conductor lowers the baton and the audience erupts in applause, we have now reached the end of our melodious journey through the programming paradigms of R.

In this performance, we explored two of the primary paradigms in R programming — functional programming and object-oriented programming. These paradigms, much like a virtuoso soloist and a harmonious orchestra, offer different methods for structuring our code and manipulating data.

Functional programming, with its emphasis on simple, stateless functions, was likened to a soloist, delivering a clear and coherent melody, best suited for simple data transformations. On the other hand, the object-oriented paradigm, akin to an orchestra, brings together different elements under a common structure, offering the perfect medium for managing more complex systems and larger data structures.

In R, the choice between these paradigms is not an either-or proposition. Instead, they can be used in harmony, allowing us to tap into the strengths of both to compose a symphony of data analysis that resonates with the specific needs of our projects.

With this understanding, we’re better equipped to choose the right paradigm and tools for our data analysis tasks, and to conduct our data symphony with grace and ease. As our performance concludes, the spotlight now turns to you, the reader, to take the baton and orchestrate your own masterpiece in the realm of R programming. Let the music play!

--

--

Numbers around us
Numbers around us

Self developed analyst. BI Developer, R programmer. Delivers what you need, not what you asked for.