If you're asked, "What's the difference between Procedural and Functional Programming?" in an interview, there's no need to panic. In this post, we'll mainly discuss Functional Programming and what sets it apart from other paradigms.
FP, What?
Functional Programming (FP) is a declarative programming style that tackles complex problems through sequential functions. When we say "functions," we're not referring to the typical code we write daily but rather to mathematical functions. In FP, you write code without relying on shared state or mutable values.
- Imperative: You write “Hello Otabek” to a buffer, and then to the standard output...
there’s still a lot to say
- Declarative: You simply print "Hello Otabek":
print("Hello Otabek")
Immutability
You’ve probably heard it—one of the core concepts in FP is immutability. Once you declare a variable, you cannot change it. It’s like saying that all values are constants, not variables.
Imagine you're running a program and you know the variables you've declared will never change. Would you still use try-except or catch-throw statements? Of course not, because the variables never change, and bugs won’t appear (unless you write buggy code yourself).
Recursion
When we need to repeat a task or iterate through something, we often use loops (like while
, for
, etc.). But loops use variables, and they store state. This goes against the principle of immutability we talked about earlier. That’s where recursion comes in.
Recursion has a base case, which tells us when to stop calling the function. Each function call utilizes the stack data structure, following the LIFO (Last In, First Out) principle. When the base case tells us to stop, elements are popped from the stack in order to process results in the desired way.
# This function says hello as many times as you want.
def say_hello(times: int):
if times == 0: # base case, tells us when to stop.
return
print("Hello!")
return say_hello(times - 1)
say_hello(5)
Pure Functions
A pure function is exactly that—a function without side effects. If you provide the same input, it will always return the same output. There are no hidden changes happening in the background.
Pure functions are fast because they can be cached. Since they always produce the same output for the same input, there's no need to recalculate results. It’s simple, but believe me, it works wonders.
High Order vs First-Class Functions
One of the key concepts in FP is First-class functions. This means that functions are treated as first-class citizens—essentially, they can be passed as arguments to other functions or returned from functions. For example:
# You can use both regular or lambda functions
five = lambda: 5
six = lambda: 6
def add(x, y):
return x + y
add(five() + six()) # This is essentially 5 + 6
Another important concept is High-order functions. These are functions that can take other functions as arguments or return functions as their result. For instance:
# Takes a function as an argument
def apply_twice(func, x):
return func(func(x))
def add_two(n):
return n + 2
result = apply_twice(add_two, 5)
# func(func(x)) means calling the function twice
# add_two(add_two(5)) => add_two(7) => add_two(7) => 9
print(result) # Output: 9
Procedural vs Functional
Procedural programming is what we typically use when writing code—it involves variables, functions, statements, etc. However, in Functional Programming, the approach is fundamentally different. In short: it’s all about functions and immutability. 😉
Conclusion
I haven’t written about the pros and cons because the main points you need to understand about FP have already been covered. FP is filled with many terms that belong to the world of mathematics. If you're interested, dive into those topics; there’s a lot to learn. I think this post serves as a great introduction for anyone starting out.
Now, you’re ready to explain the difference between Functional and Procedural programming without hesitation. Cheers!