views:

379

answers:

7

Delay execution is almost always a boon. But then there are cases when it’s a problem and you resort to “fetch” (in Nhibernate) to eager fetch it.

Do you know practical situations when lazy evaluation can bite you back…?

A: 

Lazy loading resources involves a trip back and forth between the requester and the source for each load. In the case of NHibernate, this means a from the application to the database (which is often on a different server).

There is often overhead associated with each trip (there certainly is for NHibernate or any other DB query).

If you know that you will need all or a substantial portion of the data, you are better off pulling it in one go and only incurring the overhead once.

A classic example is when you need to pull back a list of objects to populate a combo box (often these will be configuration objects). Lazy loading would go back to the database each time you added a list member to the combo box. Since you're putting the entire list into the combo box, you would incur lots of extra overhead to lazy fetch each object.

Eric J.
+1  A: 

It can also be a problem with the user experience of your program. People will happily wait for 5 seconds when a banner is displayed on the screen during app loading, but they despise to have to wait 0.25 seconds when they're typing in something in a textbox. If the amount of time it takes to load all your data eagerly is not that long, you may consider doing it at some point in the workflow where people accept a delay (such as app loading, window pop up, button presses).

David Rutten
+4  A: 

Lazy evaluation is not useful in situations where performance is critical and a value must always be evaluated. In these cases you are better off just evaluating the value and being done with it, because the overhead of lazy evaluation will be wasted.

vy32
Lazy evaluation is a way to gain performance.
Lajla
Incorrect. If you must evaluate the answer, then the extra overhead for lazy evaluation creates a cost with no benefit.
vy32
vy32 is correct. For example if you have a list of objects that are shown in a list on a mobile device the view will be created at the moment the list items comes on the screen. If some values that are shown in the list have to be lazy loaded the list will stutter and lag because the new listitems can not be filled fast enough.
Janusz
It's not incorrect. It's just not universally useful. For example, unrolling loops is a way to gain performance, but that doesn't mean unrolling loops always results in increased performance.
Ken
@Ken, you are correct --- I was a bit harsh. Lajla's comment is not incorrect, but it is off topic. That is, Lazy evaluation is a way to gain performance, but not in all cases---in fact, there are many cases where lazy evaluation does not help.
vy32
@Ken, unrolling loops is not an example of lazy evaluation.
vy32
A: 

Lazy evaluation is not useful when you don't want to store value, just use it. But this depends on the implementation of the lazy evaluator. Some systems (like Haskell) can tell if a value will be used again. Some others cannot and can cause leaks.

Eric Normand
+1  A: 

Lazy evaluation is not useful when evaluation can have side-effects. That's the only reason and that's why only purely functional languages have it. If expressions can have side-effects which must occur in a certain order you can't have it.

Apart from that, lazy evaluation only gains performance, that's it's primary goal. And that's why some languages forbid side-effects, to gain lazy evaluation for that compromise, another nice effect of it is that control structures can be regular functions.

Lajla
+2  A: 

One example for lazyness causing weird problems (happened to me today, in Haskell):

import System.IO

main = do
    content <- readFile "foo.txt"
    writeFile "foo.txt" content 

This throws the following error when compiled & executed:

foo.txt: openFile: resource busy (file is locked)

What I thought it would do: Open file foo.txt, read content, close it again. Then open it for writing, write the content, and close it again.

What it actually did: "Ah, some content. I'll probably read it later when we actually need it." Then open "foo.txt" for writing. Start writing content... ok, now we need the content. Open foo.txt for reading - bam!

I know it's trivial to fix, but it's hard to find if you don't know where to look.

jkramer
This is a problem caused specifically by lazy I/O, rather than by lazy evaluation in general. Lazy I/O is actually quite dangerous and against the spirit of functional programming, as it gives side-effects to functions which should be pure (namely, evaluating a string causes data to be read from disk - a side effect!), leading to problems just like this one, and this one too: http://stackoverflow.com/questions/2981582/haskell-lazy-i-o-and-closing-files But you can certainly have lazy evaluation without lazy I/O, in fact, such seems to be the current direction of Haskell.
Jesse
This is a neat example!
vy32
+1  A: 

You cannot do a reduction (eg. a fold) on input data in constant space with lazy evaluation, as the delayed evaluation of each reduction step results in linear space complexity. You must instead force-evaluate the result of each reduction step to keep the space usage constant.

For example, hashing a file in Haskell. You might be well meaning and read the input file lazily chunk-by-chunk, adding each chunk to the digest, but behind your back Haskell is actually making a thunk for every chunk you add to the digest, leaving the entire file in memory in these thunks until the resulting digest is actually evaluated. Ouch!

See last comment here: http://stackoverflow.com/questions/2981582/haskell-lazy-i-o-and-closing-files/2983328#2983328

Jesse