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 form Haskell. Don’t get confused by where from SQL, that it totally different.

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] ++ qsort 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 is given, 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 form 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 fuction.

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 {
    return 0;
  }
}

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 ? yearsSinceBirth >= 18 :  throw new RuntimeException("wrong input");

} where validInput      = (birthDate != null) && (currentDate != null)
        yearsSinceBirth = Period.between(birthDate, currentDate).getYears()

Obviously, I made up the syntax. We could argue if one is better than the other and waste our time mutually.

How about where in JavaScript?

I was looking for a function 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 if one is better than the other. Rather, I want to point out which one is more readable (imho).

function triggerLoadMoreForPaging(container) {
  let triggered = false;
  console.log("track scrolling");
  container.addEventListener("wheel", (e) => {
    if (readyToTriggerScorll) {
      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
        readyToTriggerScorll = howMuchScrolled < thresholdInPercent / 100 && !triggered

Summary

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