I think we're in danger here of losing the distinction between _branched execution_ and _lazy evaluation_.

With branched execution, you have (test condition) {
case 0 => this thing runs case 1 => this thing runs
... }(two cases are enough in general if you nest them; in practice, multi-target jumping is what all modern computer architectures implement).

In contrast, with lazy evaluation, you have label = computation that produces a valueand you avoid actually running the computation until you need the value that the label says.

These are dramatically different ways to think about the problem; in particular, lazy evaluation requires branched execution but not vice versa (not without adding a function that is essentially the "branched execution function").

Branched execution is _absolutely necessary_ to get anything useful done. Lazy evaluation is only rarely _required_, though in many cases one can recast branched execution problems more cleanly and efficiently as lazy evaluation problems. The confusing part is that many strictly-evaluating languages have abnormal syntax for branched execution. For instance:

Interpreting these as lazy evaluation is both highly useful--as it lets you abstract over implementation details--and highly dangerous, as it sometimes matters what those implementation details are, and in most languages there is not in fact any ability to curry or otherwise manipulate the expressions that go into a short-circuiting boolean operator, and there is no guarantee that you won't get multiple evaluation of expressions that nominally appear to be the same thing. For example, in

lazy val x = f(y) if ( (x && a) || (!x && b) ) return g(z);

one has mixed lazy evaluation with short-circuiting in a way that may not immediately answer the question of whether f(y) is evaluated zero, one, or two times, and if the compiler doesn't help you out and write what you really mean:

val x = f(y) if ( (x && a) || (!x && b) ) return g(z);

then you are spending the overhead of lazy evaluation for no reason whatsoever.

Since the point of the discussion is not whether lazy evaluation produces _correct results_ (it does), but rather whether it _performs well_ (it may or may not), this distinction is important. As is the knowledge of how much your compiler is going to help you out when it comes to promoting to strictness those things whose structure makes laziness a waste of time.

I don't think the point really means a whole lot if you want to view Scala's code as expressions.Again, there's a continuum of lazy evaluated expressions vs. strictly evaluated expressions. Scala has both. if-expressions lazily evaluate some sub expressions.
I don't really think this debate is bringing to light a lot of useful material at this point, besides, In Haskell, lazily evaluated expressions are pretty rockin and have first class support in the runtime, and in Scala we support them as best as we can on the JVM.
Perhaps some of these Haskellers could work on a JSR for first-class thunk support and associated optimisatoins on the JVM? That would drastically alter my opinion on when to use laziness and eager evaluation.

- JoshNote: I use a lot more lazily evaluated expresisons in Scala than I ever did in Java, but no where near the line where Haskell is.

I think we're in danger here of losing the distinction between _branched execution_ and _lazy evaluation_.

With branched execution, you have (test condition) {
case 0 => this thing runs case 1 => this thing runs
... }(two cases are enough in general if you nest them; in practice, multi-target jumping is what all modern computer architectures implement).

In contrast, with lazy evaluation, you have label = computation that produces a valueand you avoid actually running the computation until you need the value that the label says.

These are dramatically different ways to think about the problem; in particular, lazy evaluation requires branched execution but not vice versa (not without adding a function that is essentially the "branched execution function").

Branched execution is _absolutely necessary_ to get anything useful done. Lazy evaluation is only rarely _required_, though in many cases one can recast branched execution problems more cleanly and efficiently as lazy evaluation problems. The confusing part is that many strictly-evaluating languages have abnormal syntax for branched execution. For instance:

Interpreting these as lazy evaluation is both highly useful--as it lets you abstract over implementation details--and highly dangerous, as it sometimes matters what those implementation details are, and in most languages there is not in fact any ability to curry or otherwise manipulate the expressions that go into a short-circuiting boolean operator, and there is no guarantee that you won't get multiple evaluation of expressions that nominally appear to be the same thing. For example, in

lazy val x = f(y) if ( (x && a) || (!x && b) ) return g(z);

one has mixed lazy evaluation with short-circuiting in a way that may not immediately answer the question of whether f(y) is evaluated zero, one, or two times, and if the compiler doesn't help you out and write what you really mean:

val x = f(y) if ( (x && a) || (!x && b) ) return g(z);

then you are spending the overhead of lazy evaluation for no reason whatsoever.

Since the point of the discussion is not whether lazy evaluation produces _correct results_ (it does), but rather whether it _performs well_ (it may or may not), this distinction is important. As is the knowledge of how much your compiler is going to help you out when it comes to promoting to strictness those things whose structure makes laziness a waste of time.

2011/12/15 Cédric Beust ♔ :
>
> It still gets you very close to the kind of laziness we want. Actually, Tony
> made the same mistake in this post where he says that you can't add laziness
> to Java but you can in Scala, and to illustrate it, he shows a simple
> example of a boolean short circuit. However, during his demonstration, he
> silently modifies this signature:
>
> def lazyAnd(a: Boolean, b: Boolean)
>
> to
>
> def lazyAnd(a: Boolean, b: => Boolean)
>
> Well, if you allow this kind of rewriting of the original problem, then you
> can do the same kind of thing in Java (although it will be more verbose and
> with slightly different semantics, but the idea remains) and in pretty much
> any strict language that offers even the most minimalistic support for
> lambdas.

Not without changing the call-site. In Scala, there's no change in the
call-site, just in the declaration-site.