I Tried to Eliminate if. I Ended Up Putting match in My Language.
In 2024, I wrote a Qiita article whose title roughly translates to "The Plan to Eradicate if Statements." https://qiita.com/KentaroMorishita/items/6329d20fbc6f98f72864 Looking at the title now, it sounds a little dangerous. But I didn't literally want to remove if from the world. What bothered me was having to chase control flow when all I really wanted to do was distinguish between cases . I was…
In 2024, I wrote an article on Qiita titled "The Plan to Eradicate if Statements", which initially sounded dangerous. However, my intention was not to eliminate the "if" keyword entirely. I simply wanted to avoid navigating through control flow when all I truly wanted to do was differentiate between cases. In TypeScript, this looked like this:
let label: string
if (score === 90) {
label = "A"
} else if (score === 70) {
label = "B"
} else {
label = "C"
}
While nothing is inherently wrong with this approach, my main concern was the act of continually assigning values into "label". I preferred the classification of "score" into a "label" instead. This led me to favor ternary expressions:
const label = score === 90 ? "A" : score === 70 ? "B" : "C"
Nevertheless, as the cases multiplied, it became cumbersome to read. Consequently, I began creating my own "match"- and "when"-like abstractions using TypeScript. In retrospect, the moment I started mimicking language features with a library may have been a cautionary sign. Within Seseragi, it became simply "match". I preferred Seseragi's match not just because it was convenient, but because it functioned as an expression from the outset.
No temporary variable was needed to store the result— the entire function read as "classify a score into a String".
ADTs (Algebraic Data Types) made Seseragi's match even more appealing. With numeric conditions alone, TypeScript was sufficient. However, Seseragi's match truly shined when the value itself was an algebraic data type. For instance:
type Session = | Loading | Guest | LoggedIn String | Failed String
fn label session: Session -> String = match session {
Loading -> "Loading..."
Guest -> "Guest"
LoggedIn name -> `Hello, $name`
Failed message -> `Error: $message`
}
The type defines the possible states, and match handles those exact shapes. This made the code much easier to read than dealing with several booleans to figure out the application's state. Additionally, if I added a constructor without handling it, the compiler would turn it into an exhaustiveness problem. This approach closely aligned with what I was originally striving for when building match-like libraries in TypeScript.
I later realized that I had been trying to make branching behave more like producing a value in TypeScript. Now, I have a language with "match" in it. My philosophy didn't change dramatically; I just continued refining it until something I had forced a library to imitate became an ordinary language feature. As a result, Seseragi still includes "if" statements. The eradication attempt did not succeed. I believe this outcome was ultimately beneficial.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.