3 ms·
Well-named intermediary variables often help tremendously with readability though. A language discouraging their use seems like the wrong trade-off decision to
by skrebbel 3y ago
Well-named intermediary variables often help tremendously with readability though. A language discouraging their use seems like the wrong trade-off decision to me.
- chii 3y agothat's because you have assumed that the code would _need_ such an intermediate variable, which is often the case in imperative code. I argue that if your code _does not need_ this intermediate variable, it makes the code even more readable as it removes more cognitive friction - having fewer things makes it easier to understand.
- Barrin92 3y agothe code doesn't need anything, people reading it do. Names are useful because they make intent explicit. Point free programming in functional languages is often overused. Stuart wrote a good blog post about this a few years ago. "All too often, however, I see the threading macros used in places where they make the code less clear. Early in Clojure’s public existence, there was a fad for “point-free” programming, a kind of code golf without any local variables. This is a fun exercise, but it does not lead to readable code, and I’m relieved that the enthusiasm for this style has worn off. What has remained is a tendency to use threading macros any place they can be made to fit. I think this is a mistake. Rather than making the code easier to read, it makes it harder, forcing the reader to mentally “unwind” the syntax to figure out what it does." https://stuartsierra.com/2018/07/06/threading-with-style https://stuartsierra.com/2018/07/06/threading-with-style
- skrebbel 3y agoIf you name your functions and transducers well, you tell the reader what’s being done to the data. If you name your intermediate data structures well, you tell the reader what the data means. Often, the transformations have generic names such as “unique” or “removeEmpty”, but the variables can get domain-specific names such as “validOrders” or “paidAccounts”. I’m a big fan of designing code in a datastructure-first way. If you get the datastructures right, the code itself is often easy to write and easy to read. This matches FP languages really well (eg immutability), but it doesn’t match long fluent chains/pipes of maps, filters and reduces well at all.
- bcrosby95 3y agoYou can name anonymous functions so your transformations can still have a domain related name associated with it, even if you're using standard library ones.
- skrebbel 3y agoIf you’re making a local anonymous function that you call in one place, just so that a generic function gets a more domain specific name, then you might as well just assign the result to a named variable, right? It’s the same benefit with less indirection.
- BoiledCabbage 3y agoYes those are frequently used in imperative languages, but they aren't really as needed in functional styles as functions end up being smaller and more powerful. The best analogy I can give is if you've used a fluent interface in Java or C# ( like Linq). Take a look at the two larger examples at the bottom of the link. It actually would hurt readability to try to add names for each of those intermediate stages. And since functions are usually smaller you end up frequently using functions as your readability helpers instead of defaulting to let bindings. Fluent interface - https://java-design-patterns.com/patterns/fluentinterface/#explanation https://java-design-patterns.com/patterns/fluentinterface/#e...
- thom 3y agoI think well-named functions or transducers are possibly better in many cases. I agree that long, complex pipelines of transformations aren’t good to stare at though.
- xmcqdpt2 3y agoThe problem with naming variables is that you then have to deal with their scopes in review. For example, the following Java Foo getSmallFoos() { return foo .stream() .filter(...) .collect(...) } is a lot more readable IMO than if each individual steps were named, especially because reusing stream steps is a runtime failure. Not having names is a good way to enforce linearity in the absence of affine types.