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.
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 calledlesser
- A new list containing only
p
(the first element) quickSort greater
which calls our quickSort function with some elements calledgreater
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.