Photo from Louis Hansel in Unsplash
Sources
- Why Functional Programming Doesn't Matters
- Why OCaml
- Real World OCaml
- Algebraic Data Types
- Hindley-Milner Type Inference
🟣 A New Perspective on Programming
Don't take me wrong, we do great things on the Web, and there are a lot of smart people working on it but I started to feel that I needed more within programming from a year ago.
Curiosity lead me to system's level programming languages, I learned some C and C++ in the university, but I wanted something less intimidating than C or Rust and more performant than JavaScript or Python, in other words, something in between.
So I learn a bit of Zig (in my opinion a wonderful programming language), I enjoyed it but I felt the trade-off between fine-grained control and rapid productivity, so... I needed something else.
🟣 The "Aha!" Moment
I used to hear Developer Voices, a YouTube channel directed by Kris Jenkins, and one day I heard a conversation between Kris and a guy, Leandro Ostera, about this programming language called OCaml 🐪, to be honest I didn't get much, I just heard about functional programming here an there and this catchy phrase "OCaml my Caml!" that I didn't get 😆 but by listening Leandro I realized that he also experienced this "should be more out there" sensation, so I felt connected, and to my surprise the programming language he talked seems to be in the sweet spot I was looking for: something performant and expressive without much sacrifices.
So I used my spare time to learn about OCaml, tried it a little bit and after some time I'm still in love and I want to share with you some of the reasons I think it's especial:
- It's elegant and effective in the real world.
- It has a friendly community of very talented people.
- There are some companies that express such confidence in the language that built their entire organizations in OCaml's shoulders.
🟣 The Five Pillars of OCaml
You might be thinking, "I can do all of this in my current language." And you're probably right. But let me ask you: how confident are you in the code you just wrote? Would you bet your company's critical system on it?
At least in the TypeScript world, we often add state machine libraries to gain a high degree of confidence and predictability, but that means extra dependencies, complexity, and more things that could break.
With OCaml, that confidence comes built-in, the language itself is your safety net:
- Performance: It offers native compilation and static typing without sacrificing expressiveness.
- Correctness: It helps you deliver what you intended with safety and reliability baked in.
- Dexterity: It gives you the power and agility to get things done quickly, efficiently, and safely.
- Functional It's easy to reason about.
- Practical When purity introduce complexity OCaml introduce simplicity.
Let's see how this works in practice.
🟣 Performance: Speed Without Sacrifice
OCaml is a compiled, statically-typed language that offers a rare combination of high-level expressiveness and raw performance.
- Its native code compiler produces fast, optimized executables.
- It provides zero-cost abstractions, so you can write elegant and declarative code without a performance penalty.
- Its predictable garbage collector is ideal for low-latency systems.
In other words, OCaml let you focus on your business logic without a performance penalty.
🟣 Correctness: Your Built-in Safety Net
Thinking in Edge Cases
I mentioned before that as web developers we gain confidence using state machine libraries, OCaml in another hand, give you the same with two built-in features: types and pattern-matching.
For example: OCaml's compiler forces you to consider edge cases from the beginning:
let my_favorite_language (my_favorite :: the_rest) = my_favorite;;
(* Warning 8 [partial-match]: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[] *)
You're encouraged to handle all possibilities using pattern matching, a powerful feature that's like a switch statement on steroids.
let my_favorite_language languages =
match languages with
| first :: the_rest -> first
| [] -> "OCaml" (* A sensible default! *)
Making Illegal States Unrepresentable
This is OCaml's superpower. Imagine you have a shape type:
type shape =
| Circle of float
| Rectangle of float * float
When business requirements change and you need to add a Triangle, you simply update the type:
type shape =
| Circle of float
| Rectangle of float * float
| Triangle of float * float (* base, height *)
The compiler then becomes your assistant, pointing out every function that doesn't yet handle Triangle.
let area shape =
match shape with
| Circle radius -> Float.pi *. radius ** 2.
| Rectangle (width, height) -> width *. height
(*
Error (warning 8): this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
Triangle (_, _)
*)
Now your business logic is encoded directly in the type system. Once you fix the compiler errors, you can be confident that the code is correct.
🟣 Dexterity: Power and Agility
Type Inference That Helps, Not Hinders
OCaml provides strong typing without the verbose annotations. Its powerful type inference system deduces types for you, letting you focus once again in your domain.
let sum x y = x + y;;
(* val sum : int -> int -> int = <fun> *)
When you make a mistake, the error messages are your friend.
let add_potato x = x + "potato"
(* Error: This expression has type string but an expression was expected of type int *)
You get the benefits of strong typing with the feel of a dynamic language, giving you the agility to refactor and build with confidence.
🟣 Functional: Easy to Reason About
It's very easy to reason about an OCaml program:
Everything is an Expression
In OCaml, almost everything is an expression that returns a value. This includes not just calculations but even conditionals.
(* Definitions are like permanent assignments *)
let num = 3
let sum x y = x + y
(* Even conditionals are expressions that return a value *)
let result = if condition then "this value" else "that value"
Functional to the Core
OCaml encourages a functional style, which leads to more predictable and maintainable code.
-
Immutability by Default: Once a value is defined, it can't be changed. This eliminates a whole class of bugs related to unexpected state changes.
let pi = 3.1 (* pi is now 3.1 *) (* pi = 3.1415 <- This would be an error *) let pi = 3.1415 (* This creates a *new* value for pi *) -
Higher-Order Functions: Functions are treated like any other value. You can pass them as arguments, return them from other functions, and store them in data structures.
(* 'List.fold_left' takes a function as its first argument *) let sum lst = List.fold_left (fun acc el -> acc + el) 0 lst Purity: A pure function's behavior depends only on its inputs. This makes functions easier to reason about, compose, and test because there are no hidden side effects.
🟣 Practical When Need It
While OCaml encourages purity, it's also pragmatic. In situations where controlled mutation can simplify code, OCaml provides a clear and expressive way to handle it, for example allowing to access a reference outside it's normal scope:
let next =
let counter = ref 0 in
fun () ->
incr counter;
!counter
🟣 What This Might Mean for You
OCaml is, in my opinion, the only language out there that has the right balance between: performance, expressiveness and practicality.
🟣 Why This Matters
OCaml's sweet spot is in high-predictability, high-reliability, and high-performance systems. This is why it's trusted in production by companies in the most demanding fields:
Finance: Jane Street
Developer Tools: Docker
Web Services: Ahrefs
Blockchain: Tezos
The pattern is clear: when failure is not an option, OCaml becomes the option.
But although the previous is true, as in OCaml expressiveness and performance is not an important trade-off we could build more systems in it.
🟣 Let's Explore Together
If any of this sparked your curiosity, I'd love to explore it with you. I'm building small things, writing about my journey, and learning in public.
Let's stay in touch. Let's keep growing.
Thank you.
Top comments (0)