3

This question is definitely not a duplicate because I do not refer to general post/precrement evaluation but specifically to the use of increment in lambda expressions, which is provably different. Everyone is free to confirm that the code will return zeros only where you would normally expect the variable's value to increase. No answer has been posted to that.

I am well aware of the varying evaluation and incrementation moments of both post- and prefix incrementation. Still, I fail to understand why this returns zeros only:

Stream.iterate(0, e -> e++)
            .limit(10)
            .forEach(System.out::println);

When checking this, I see e being initialized as 0 during the first iteration and then incremented. So the second iteration should yield e = 1, but apparently it doesn't. What am I missing?

Also, if I reverse the increment, it works as supposed, listing all numbers from 0 to 9:

Stream.iterate(0, e -> ++e)
            .limit(10)
            .forEach(System.out::println);
AdHominem
  • 1,204
  • 3
  • 13
  • 32
  • Looks like you missed that `e++` returns the _previous_ value of `e` when `++e` returns the updated value. So `e -> e++` is effectively equivalent to `e -> e`. – Tunaki Apr 22 '16 at 18:24
  • I do not think this is a duplicate of "How do postincrement and preincrement operators work?". AdHominem's problem isn't that s/he doesn't understand that `e++` evaluates to the old value of `e`; it's that s/he doesn't understand why it's what it evaluates to, rather than what value `e` has afterwards, that's important. – Gareth McCaughan Apr 22 '16 at 18:24
  • @GarethMcCaughan The linked question explains that. For example this answer http://stackoverflow.com/a/2371162/1743880 – Tunaki Apr 22 '16 at 18:25
  • 1
    Though in reality you'd use `IntStream.range(0,10)`. – Brian Goetz Apr 22 '16 at 18:26
  • @Tunaki No, it really doesn't. I think the problem is in AdHominem's mental model either of how `iterate` works or of how lambdas work, and neither of those is either asked by the linked question or addressed by any of its answers. – Gareth McCaughan Apr 22 '16 at 18:32
  • Well, if you run the above code, anyone can confirm that it's returning zeros and what you would expect of a postcrement operator does not happen - the variable stays the same. – AdHominem Apr 22 '16 at 21:30
  • @AdHominem See my first comment where I explained why it is always returning 0. `e -> e++` is really the same as `e -> e` because `e++` returns the previous value of `e` as per the rules of the postfix operator explained in the linked question. And `Stream.iterate(0, e -> e)` can only be a Stream of zeros. – Tunaki Apr 22 '16 at 21:53
  • I know, but this does not explain why the value is never increased. According to the Docs: `result++; and ++result; will both end in result being incremented by one.` So why is there no incrementation? – AdHominem Apr 23 '16 at 06:23

1 Answers1

5

The main problem is that you are using expressions intended for a side-effect which have no effect. Good IDEs, compilers or audit tools should issue a warning about it.

A lambda expression of the form e -> expression has a parameter called e. This must not be confused with a heap variable. The expressions e++ and ++e will modify the parameter which has no effect that will last longer than the single function evaluation. It’s not different to, e.g. a method like

static int myFunction(int e) {
    return e++; // or ++e
}

The modification of e has no persisting effect, the only thing that matters is what value will eventually be returned, so e -> ++e is equivalent to e -> e+1 and e -> e++ is equivalent to e -> e and therefore, you should use either e -> e+1 or e -> e to emphasize what will be returned without performing a distracting side-effect on a parameter variable.

But as mentioned in the comments, in this specific case you should use IntStream.range(0, 10) instead of Stream.iterate(0, e -> e+1).limit(10). Not only will IntStream.range clearly document the intention, in the current implementation, it has a performance benefit for a lot of stream operations.

Holger
  • 285,553
  • 42
  • 434
  • 765