Why would I want to re-implement lazy?
Asked Answered
I

1

14

I was reading the section on Lazyness [sic] over at Twitter's Effective Scala page, which includes this suggestion (emphasis is mine):

Use lazy fields for this purpose [computing and caching values on-demand], but avoid using lazyness when lazyness is required by semantics. In these cases it's better to be explicit since it makes the cost model explicit, and side effects can be controlled more precisely.

I don't understand why they would make this claim. Why would it be better to avoid using the lazy keyword for cases when laziness is required by the semantics (meaning that it's necessary for correctness in your program rather than just using it as an optimization). I don't see how writing your own lazy initialization code would make the fact that laziness is required more clear than using the lazy keyword built into the language! I know there's a bit of extra overhead involved with making lazy fields thread-safe, but I don't think that's what they're getting at here...

Is there some hidden merit to this guideline on the use of lazy that I'm totally missing, or am I better off just ignoring this suggestion?

Illdefined answered 18/10, 2012 at 16:52 Comment(0)
S
6

Edit: I am now no longer sure what the advice is, so take my points below with a grain of salt when it comes to critiquing Twitter's advice. (But I give my own advice below.)

I also disagree with the advice, but I (used to) think their point is that laziness is too easy. You pay a performance penalty for accessing a lazy value, but you don't notice at the use-point that you are doing anything aside from accessing a normal val. Of course, that's one thing that makes lazy vals so useful: you can switch between lazy behavior and not and not change your interface at all. But if people pepper their code randomly with lazy, performance in critical regions will likely suffer (assuming that it is not more than made up for by lazy evaluation), order of initialization will be harder to predict (especially important if you're performing a lot of side-effects), and so on.

Even so, I think it is worse to be explicit but you do have to be disciplined. If you cannot count on either documentation or discipline, maybe it's better to just avoid it entirely.

Sorn answered 18/10, 2012 at 17:51 Comment(8)
I personnaly thingk that the advice is pretty sound. It is about side effects. If you're adding a lazy keyword to postpone a side effect, you're probably doing it wrong. And sometimes, when some computation is really long, that should count as side effect too (the effect being a quantifiable pause).Upend
@RégisJean-Gilles - Shouldn't the advice be, "Don't use lazy vals when the creation process includes side-effects", then? If you're using a lazy val to postpone a result, you're doing it exactly right. If you're doing it to postpone a side-effect, you're asking for trouble unless the side-effect makes sense only in the context of the result being created.Sorn
I think the essence of the advice is right, but it could have been phrased more clearly. When they say "when lazyness is required by semantics", to me it necessarily implies "when you are using the lazy keyword to try to control side effects" (how else could laziness affec semantics, if it's not for side effects?). If that is not what they implied, then I will have to agree with you that the advice is strange.Upend
@RégisJean-Gilles - By side-effects, I mean something other than what is placed in the val: printing, setting variables somewhere, deleting an entry in a database, etc.. You very much want the direct effect of having the val when you need it and not wasting space/computation on it before.Sorn
Well, I think we very much agree on the definition of a side-effect ... ^^. I am just saying that this it is my belief that the advice is all about explicitly controlling side effects (with this very definition of side effect).Upend
@RégisJean-Gilles - I guess I'm not sure what they mean by "required by semantics", then. I was interpreting it as that certain things were guaranteed to be lazy, like Stream. That is actually part of Stream's contract (verbal, not type-enforced)--and lazy val is a perfectly sensible way to implement some if it.Sorn
I can only agree that they are pretty vague. The very fact that we can't seem to agree on their intent goes to show that the wording would need some rework.Upend
Interesting. I didn't even thing of the val vs lazy val case for side effects—I was thinking of def vs lazy val, where lazy val is basically the same as a def where the answer is cached after the first call.Illdefined

© 2022 - 2024 — McMap. All rights reserved.