1. 20
    1. 17

      This article has a good coverage of the pitfalls you can encounter when you misapply laziness, but the final analysis is very, very wrong. If you look thru the list of problems, you’ll notice that almost every one has one factor in common: they don’t apply to pure functions.

      Once you look at it thru this lens, the problems more or less disappear. Use laziness for pure functions. Never use it when a function isn’t pure. Boom; done. Some of the docstrings mention this: filter at least states “pred must be free of side-effects” but it’s a shame it’s not clearer because the actual correct answer is quite simple once you understand it.

      1. 3

        I don’t think the performance problems disappear with purity.

        I do agree some of the things like catching errors within map is a bit of a “totally fine problem to have”. But there are legitimate questions of performance, especially if the laziness isn’t easily tunable.

        The biggest difficulty with this kind of stuff that works well enough is that it gets pervasive in a code base, but the moment you start needing to do “serious” performance tuning you end up with a good amount of work to do. Granted, Clojure might offer good refactoring tools to make that easier.

        1. 1

          I don’t think the performance problems disappear with purity.

          Right, the performance problems are the one thing on the list which remain valid once you approach laziness from the right direction.

          The biggest difficulty with this kind of stuff that works well enough is that it gets pervasive in a code base

          I think of it as being extra incentive to get the “functional core vs imperative shell” distinction sorted out from the beginning. If you don’t do this from the start, laziness will be the least of your problems!

        2. 3

          I must say I wholeheartedly agree with the author and I’m happy to finally see some like-minded views in the community! It comes as no surprise that it is the people who focus on measuring Clojure’s performance who advise against lazy seqs.

          Your reply, IMO, is not actionable advice in a language where the purity requirements of a function are only communicated through docstrings. When there is no language enforced way to do something, I’d rather have it not be a rule at all.

          Some may say this is unfortunate, but IMO I’m very happy Clojure doesn’t have a way to enforce no side effects. I think this pragmatism is very important, and a defining characteristic of the language. There’s little to be gained from embracing the burrito monster. However, this also means we don’t get to play Haskell and pretend we have lazy evaluation in Clojure.

          I see no point in lazy seqs, given that it’s shown to be worse in terms of execution speed and memory consumption. In my opinion, processing of infinite lists is a nice party trick, rarely useful in practice.

          1. 1

            Use laziness for pure functions. Never use it when a function isn’t pure. Boom; done.

            The problem is Clojure isn’t designed to make ensuring this easy, unlike languages where purity is more heavily constrained, so I think the criticisms still stand.

            Over the years, I’ve come to think laziness is very overrated, at least in Clojure. Maybe in a purer lang like Haskell, I wouldn’t think twice, but most of the “advantages” listed are underwhelming to me:

            • Avoiding unnecessary work - Lazy sequences only cover some of the work you may wish to avoid, so if it’s truly important to avoid, you end up writing code anyway. TANSTAAFL.
            • Infinite sequences - Cases where I want to use a sequence forever are pretty rare. Many uses of infinite sequences are effectively bounded anyway (by take, etc). A “great party trick” is unfortunately an apt description.
            • Acting like you have infinite memory - It’s better to know how much memory you consume, than create an unreliable illusion IMO. (Ironically, Hickey uses this logic in core.async, which forbid the illusion of infinite channel buffers, unlike lazy seqs.)
            1. 1

              The problem is Clojure isn’t designed to make ensuring this easy, unlike languages where purity is more heavily constrained, so I think the criticisms still stand.

              OK sure, but that’s a completely different criticism.

              I agree Clojure doesn’t make this easy, but it doesn’t matter; you have to do it anyway if you want a reliable codebase. Messing up your pure/impure functions and then blaming laziness when you have a problem is addressing the symptoms instead of the cause.

              1. 1

                To me, any feature that requires programmer discipline to use safely will always be error-prone; humans just aren’t built for 100% reliability. So, the question is, is laziness worth the trade-off in Clojure?

                As you say, there are still some good reasons to consider which fns are pure/impure, but if I had to put a number to it, I’d say… 90% of pure/impure problems I’ve seen are associated with using laziness. IME, problems with impurity in other areas, like STM updating fns, delays, etc. are a small minority.

                1. 1

                  if I had to put a number to it, I’d say… 90% of pure/impure problems I’ve seen are associated with using laziness

                  If you’re talking about outright bugs, I’d say that number isn’t too far off from my experience. But I’m talking more about general good design principles.

                  Code written without thought towards separating logic vs action can be operationally correct but still a tremendous pain in the ass to work with because it’s just chaotic and haphazard. You can’t write well-designed Clojure code that’s pleasant to work with unless you carefully separate out side-effects from values.

          2. 4

            It’s worth noting that Java’s Streams suffer from the same problems around error handling: you need to catch things at the iteration site, not the site that generates the stream.

            It’s bit a few folks I know, including myself, far more than we’d like to admit.

            1. 4

              The clickbait title is a pun. Until I realised that I was grumpy with it.