News for hackers. Stuff that matters.
Re:Lodash just declared issue bankruptcy and closed every is... by recursive on Saturday September 16, 2023 @11:23PM (#37541221)
reduce() abuse is a peeve of mine.
Re:Lodash just declared issue bankruptcy and closed every is... by earthboundkid on Saturday September 16, 2023 @11:37PM (#37541270)
I used to always use .forEach but now I use “of” as much as possible.
Re:Lodash just declared issue bankruptcy and closed every is... by yakshaving_jgt on Sunday September 17, 2023 @02:55AM (#37542232)
Map, reduce, and forEach are each for quite different things. When you say you always used to use forEach, are you saying that you used it for pure computations? Or is near enough everything you write effectful?
Re:Lodash just declared issue bankruptcy and closed every is... by virtue3 on Saturday September 16, 2023 @11:50PM (#37541358)
What got me to stop using reduce was when I and another sr. held a theoretical "gun" to a jr devs head and asked him what a block of code involving reduce did and they didn't have a clue. They were pretty bright; so I just threw it the towel at it being useful to the health of a large codebase after that.

Still love map. But reduce can feel very "code golf" real quick.

Re:Lodash just declared issue bankruptcy and closed every is... by yakshaving_jgt on Sunday September 17, 2023 @02:50AM (#37542206)
I’m confused. Do you not think that would have been a good opportunity to teach that person what folds are for?

Fold/reduce is fundamental. It’s weird to me that its use would be discouraged or outlawed somewhere.

Re:Lodash just declared issue bankruptcy and closed every is... by jrockway on Sunday September 17, 2023 @03:15AM (#37542358)
If your language has a `for` keyword, I would just say use the `for` keyword.
Re:Lodash just declared issue bankruptcy and closed every is... by yakshaving_jgt on Sunday September 17, 2023 @03:23AM (#37542403)
But why?

The language I use has various flavours of `for`. It also has various flavours of map and fold. It also has recursion.

They each do different things. Those differences are meaningful and useful. Why would you limit yourself to just using `for`?

Re:Lodash just declared issue bankruptcy and closed every is... by izietto on Sunday September 17, 2023 @03:46AM (#37542531)
It depends. It isn't the case for Ruby, for example.
Re:Lodash just declared issue bankruptcy and closed every is... by thesnide on Sunday September 17, 2023 @03:26AM (#37542416)
So. That. https://blog.pwkf.org/2022/09/18/always-optimize-for-dummies...

"Easy to read" means "easy for others". Current efficiency is usually borrowed on future one.

Re:Lodash just declared issue bankruptcy and closed every is... by tacitusarc on Monday September 18, 2023 @12:42AM (#37552313)
Which junior devs?
Re:Lodash just declared issue bankruptcy and closed every is... by WirelessGigabit on Saturday September 16, 2023 @11:52PM (#37541368)
How would you abuse reduce()?
Re:Lodash just declared issue bankruptcy and closed every is... by Too on Sunday September 17, 2023 @01:35AM (#37541843)
MDN even had to make a whole chapter to discourage overuse of it.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re:Lodash just declared issue bankruptcy and closed every is... by masklinn on Sunday September 17, 2023 @02:41AM (#37542168)
Using reduce to perform a map is a fun way to annoy colleagues.
Re:Lodash just declared issue bankruptcy and closed every is... by 5e92cb50239222b on Sunday September 17, 2023 @03:08AM (#37542309)
Or .map() as a for..of replacement. I always wanted V8/SpiderMonkey developers to make .map()/.reduce() "pure" in the sense of "optimizing away" the expression if its result is not assigned to anything, and see the world burn.
Re:Lodash just declared issue bankruptcy and closed every is... by Zababa on Sunday September 17, 2023 @07:56AM (#37544088)
I think .map() as a for...of replacement makes sense for simple cases. newArray = oldArray.map(el => aFunction(el)) is short, sweet and clean.
Re:Lodash just declared issue bankruptcy and closed every is... by orra on Sunday September 17, 2023 @08:14AM (#37544229)
It's definitely short, but are you doing it for the side effects? Then I find .map() misleading. I'd much prefer a .forEach(), or a for...of.
Re:Lodash just declared issue bankruptcy and closed every is... by masklinn on Sunday September 17, 2023 @08:20AM (#37544275)
If you’re mapping for side effects you deserve a good rap on the head.

The main value of “map” is to denote a 1:1 data transformation. Plus this gets very fraught with many langages mapping lazily, and some not guaranteeing the order of operation.

Re:Lodash just declared issue bankruptcy and closed every is... by pwdisswordfishc on Sunday September 17, 2023 @03:59AM (#37542621)
Use it at all, presumably.
Re:Lodash just declared issue bankruptcy and closed every is... by JuanPosadas on Sunday September 17, 2023 @07:47AM (#37544015)
I'm probably on the mild side of abusing it, I've never seen another developer on my team use it, but I also include self-describing variables for the values. If the reducer function itself is non-trivial, I've give it a name so the final product may look like:

    const idNameMap = itemList.reduce(toIdNameMap)
It should be intuitive that itemList is a list of objects familiar to the context of the code, and the result will be like:

    [{"id1":"Billy"}, etc.
Re:Lodash just declared issue bankruptcy and closed every is... by masklinn on Sunday September 17, 2023 @08:01AM (#37544123)
It’s really not clear to me what the transformation is, but from the naming and result it mostly looks like it’s an abuse of reduce and should be a map, possibly feeding into an Object / Map constructor / factory?
Re:Lodash just declared issue bankruptcy and closed every is... by yakshaving_jgt on Sunday September 17, 2023 @04:24PM (#37548962)
> It should be intuitive that itemList is a list of objects

…But how?!

I can't see how anyone could build an intuition for this opaque line and the example of its apparent result. It's confusing enough that `idNameMap` actually refers to a list (or array), and not a map (or object).

Re:Lodash just declared issue bankruptcy and closed every is... by da39a3ee on Sunday September 17, 2023 @02:23AM (#37542078)
Yes. In Scala people seem to say it's the idiomatic way to sum a list of numbers which never felt right to me. It just seems to much code to look at for that.
Re:Lodash just declared issue bankruptcy and closed every is... by yakshaving_jgt on Sunday September 17, 2023 @02:45AM (#37542182)
It definitely is the idiomatic way. How would you do it otherwise? Recursion?
Re:Lodash just declared issue bankruptcy and closed every is... by secdeal on Sunday September 17, 2023 @02:46AM (#37542190)
in Scala the idiomatic way to sum is the method sum on collections List(1,2,3,4).sum

Although this is indeed implemented with reduce. But is it really too much code? List(1,2,3).reduce(_ + _)

Re:Lodash just declared issue bankruptcy and closed every is... by BigJono on Sunday September 17, 2023 @04:40AM (#37542858)
Summing a list of numbers is the exact kind of use case you should use reduce for. If it feels wrong to you it's just because you have more experience with for loops than reducers.

In languages like JS that have both styles, the place you probably want to use for loops over reducers is for more complex operations where mutation can simplify the code. For example if you have 10,000 elements in an array that you want to aggregate into 1,000 properties on an object (with a non trivial relationship between array elements and object properties), it's probably going to look nicer in a for loop than it is in a reducer with a bunch of spread and ternary operators.

IMO .reduce calls should probably be one line. If not then it's time to either write a for loop or compose more smaller functions.

Avoiding them entirely is just FUD though. To compare summing an array in JS:

  let sum = 0;
  for (const n of numbers) {
    sum += n;
  }

  const sum = numbers.reduce((acc, n) => acc + n, 0);
The latter is much nicer to read if you're used to both styles. What I particularly like about it is it clearly signals that 'sum' is a variable that we will be using further down. The for loop style leaves ambiguity as to whether 'sum' is going to be used later or if it's just some context for something that's happening inside the loop.

Actually, to throw a hot take in the mix here, I think people should be more accepting of multiple statements across single lines in C-style languages.

  let sum = 0; for (const n of numbers) sum += n;
That would be a perfectly fine way to signal to the reader that "this is a specific line of code to produce a sum value" (much the same as the reduce example), but people seem to have a dogmatic aversion to leaving braces off if/for statements or putting multiple statements on a single line.
Re:Lodash just declared issue bankruptcy and closed every is... by da39a3ee on Sunday September 17, 2023 @06:12PM (#37549822)
I just expect it to be my list.sum() or sum(mylist) and to trust that the implementation under the hood is reasonable.
Re:Lodash just declared issue bankruptcy and closed every is... by ThinkBeat on Monday September 18, 2023 @02:33AM (#37552947)
I disagree.

The first version is something most programmers could read and understand right away.

I also dont understand why the second version signals use of the variable any better than the classic version, esp if you declare the variable right ahead of it, but that is the classic "C" style.

How ever in a real system I would hope people use better names than sum. which would give it some comprehension of what the variable does / exists for.

What is the obsession with one liners? Perhaps if paper was quite expensive and it was printed out paper on a regular basis you could save a few sheets, I dont think one long line is easier to read than several short lines.

I suppose if everyone involved with the project prefers or is used to the second version it is fine.

Re:Lodash just declared issue bankruptcy and closed every is... by BigJono on Monday September 18, 2023 @05:46AM (#37554120)
> I also dont understand why the second version signals use of the variable any better than the classic version, esp if you declare the variable right ahead of it, but that is the classic "C" style.

Because you have no idea if the variable is used further down in the scope. Compare with something like parsing a csv file with support for quotes:

  let rows = [];
  let quoteMode = false;
  for (char c of csvFile) {
    ...
  }
rows is the end result, quoteMode is state only relevant to the process happening within the for loop. There's nothing past variable names to distinguish their intended use. Whereas:

  const rows = parseCsv(csvFile);
makes it totally clear.

The reason something like reduce can make for nicer code is because it lets you do simple operations (probably not parsing a csv lol) inline in a way that makes the code just as clear as a function call would be, without adding a bunch of extra layers of abstraction (meaning more scrolling and flicking between tabs).

Really it's not about the reduce function at all, it's about the "const foo =". Once you see that, you can completely disregard the rest of the line if you've already read it and/or are confident you know what it's doing. It acts as a refresher in a way that a for loop doesn't. After you get past the inital shock of seeing a scary one liner (which get less and less scary as you see them more), it makes the next 20 times you read it much more pleasant.