In this thread, we discuss asserts, not abstractions. Monad is an abstraction. (On the other hand, many people only see tests and forget about two other solutions, which are as important.)
As for throws/try-catch - beyond assertion use, they also report all problems that are outside your control (like IO failing due to HDD damage, or connection dropping). Those kinds of problems are here to stay.
Not as much elegance as it is about purity. Minimizing side effects is the number one way to reduce bugs.
It should be the number one guiding principle when creating out reliable software. Which means, you simply cannot use the primitive try catch or similar construct. Don’t break flow of control. Guide it to a terminal value instead.
These days, when I see try-catch and if-else constructs (which is in most codebases) it’s clear there will be bugs over the life of the application.
It’s fine, use them, but there is a world of greatness when you ditch these faulty constructs. Just like ditching OOP constructs. All built on false premises.
Monads, not even once.
For example, today I am working on a service that:
- uses a database
- calls external APIs
- publishes and consumes from a message broker
- interacts with local and remote filesystems over a variety of protocols
All of these things entail error conditions, most of which throw exceptions in the corresponding libraries. Sometimes they are converted to Either/Maybe, and sometimes they are wrapped in "native" checked exceptions.
The important bits:
1. The type system and compiler make sure the programmer has to deal with the error conditions at some point. From a programmer's perspective, a checked exception bubbling up the stack is not very different from returning a monadic object up the stack.
2. The core of the application is entirely pure. No exceptions (in both senses of the word). All side effects are pushed to the boundaries.
The real world of software engineering is enormously varied and each project faces a different set of legitimate constraints and objectives. It's more valuable to discuss how and when to use "assertions, throws, and try-catch[es]" than to pretend that they're universally superceded by some other construct.