Dear Language Designers: Please copy `where` from Haskell

TLDR: where allows to extract part of your code and give it a a new name, not like a local variable or a private function.

Hero

I wish more languages would copy the where construct from Haskell. Don’t get confused by where from SQL; it has a totally different semantics.

What is where in Haskell

If you are not familiar with the Haskell syntax, here is a short snippet with an explanation. The following code is taken from here, with minor changes.

1: quickSort :: Ord a => [a] -> [a]
2: quickSort []     = []
3: quickSort (p:xs) = quickSort lesser ++ [p] ++ quickSort greater
4:    where
5:        lesser  = filter (< p) xs
6:        greater = filter (>= p) xs

The above function sorts a given list and returns a new list. You can read the code line by line like this:

1 Function quickSort takes a list of type Ord and returns a list

2 In case of an empty list, an empty list is returned

3 In case a list with items is given, we call the first element of the item p and the rest of the elements xs. Then, we return a new list, which is created using three lists:

  • quickSort lesser which calls our quickSort function with some elements called lesser
  • A new list containing only p (the first element)
  • quickSort greater which calls our quickSort function with some elements called greater

4 Well this is the gist of the whole article, our where keywords gives the missing definitions for lesser and greater. What follows are definitions of lesser and greater which are only valid for the quickSort function.

5/6 lesser is defined as the result of xs (rest of the sorting) filtered to keep only elements which are smaller than p. greater on the other hand keeps only elements larger or equal to p

If you want to understand more, read the Where!? chapter from Learn You a Haskell.

How is where different from a private function or local variable?

where is just syntactic sugar around a private function (imho). You can extract a code-fragment and give it a new name. That name is only valid within the function.

You could do the same with private functions, but then it is not guaranteed to be used solely by quikSort.

The difference between local variables and where is the former gives the definitions first and then usage, while with where the definition comes later. I found that way more readable than with local variables.

Potential where in Java

Take this example to calculate the age. Taken from here:

public static int isAdult(LocalDate birthDate, LocalDate currentDate) {
  if ((birthDate != null) && (currentDate != null)) {
    return Period.between(birthDate, currentDate).getYears() >= 18;
  } else {
    throw new RuntimeException("wrong input");
  }
}

Now, imagine if Java had a where keyword, the above snippet could be transformed to:

public static boolean isAdult(LocalDate birthDate,
                              LocalDate currentDate) {
  return validInput ? age >= 18 : throwError

} where validInput      = (birthDate != null) && (currentDate != null)
        age             = Period.between(birthDate, currentDate).getYears()
        throwError      = throw new RuntimeException("wrong input");

Obviously, I made up the syntax. We could argue if one is better than the other and waste our time mutually, but that is not the point. This function now becomes easier to read. The where syntax gives us the possibility to name each snippet, which makes code easier to read (imho).

How about where in JavaScript?

Let’s look at another example. This time, I was looking for a function in an actual project. One which was which I didn’t understand at the first glance. Then found the following one. I guess it is supposed to implement a (buggy) infinite scroll.

function triggerLoadMoreForPaging(container) {
  const thresholdInPercent = 30;
  let triggered = false;
  console.log("track scrolling");
  container.addEventListener("wheel", (e) => {
    const howMuchScrolled =
    Math.abs(container.scrollHeight - container.clientHeight - container.scrollTop) / container.scrollHeight;
    if (howMuchScrolled < thresholdInPercent / 100 && !triggered) {
      console.log("Trigger load more event");
      triggered = true;
      loadMore()
    }
  });
}

Image in an alternative future, we could have something like this. As said before, I would not focus on if one is better than the other. Rather, I want to point out which one is more readable.

function triggerLoadMoreForPaging(container) {
  let triggered = false;
  console.log("track scrolling");
  container.addEventListener("wheel", (e) => {
    if (hitScrollThreashold && !triggered) {
      console.log("Trigger load more event");
      triggered = true;
      loadMore()
    }
  });
} where thresholdInPercent = 30
        scrolledTop        =  Math.abs(container.scrollHeight - container.clientHeight - container.scrollTop)
        howMuchScrolled    =  scrolledTop / container.scrollHeight
        hitScrollThreashold = howMuchScrolled < thresholdInPercent / 100

Summary

Lately I have been doing more Elixir and JavaScript and sometimes, I wished those languages would introduce the where keyword from Haskell. I hope you take this as food for thought.