Bob Balaban's Blog

     
    alt

    Bob Balaban

     

    "Lazy Evaluation": When Being Lazy Causes You More Work

    Bob Balaban  August 16 2009 06:39:18 AM
    Greetings, Geeks!

    I have always held that being "lazy" is not a bad thing. In fact, I often tell people that I'm lazy, and that this is why I became a software developer: I want the computer to do the work, so that I don't have to.

    Being "lazy" (if you define the word as meaning "don't do more work than you have to") is not a bad programming principle. It's really just another way of saying "KISS" (Keep It Simple, [Silly]).

    Recently, though, I got bit by a LotusScript program I was working on because I forgot that LotusScript isn't as "lazy" as other programming languages I regularly use (Java, C++...).

    But, to tell you that story, I have to tell you about a thing called "lazy evaluation". It's a principle that applies to the runtime evaluation of "if" statements in a program. In virtually all programming languages, an "if" statement is a critical control-flow influencer, and an important part of the logic a developer is implementing. Usually the word "if" is followed by a boolean expression. The expression can be of arbitrary complexity, nested parenthetical sub-expressions, whatever, but the expression, in the end, needs to evaluate to a value that can be interpreted as either "true" or "false" (thus, boolean). In some languages, the defintion of "true" is more, um, flexible than in others. The most relaxed definition says that "true" is anything that is non-zero, while (in most languages) "false" is zero.

    So, you can have an "if" that contains lots of logical "AND"s and "OR"s, and as long as the whole thing can be computed down to a numeric value that represents either T or F. Most compilers take advantage of some standard optimizing intelligence that says, "we don't have to completely evaluate the expression, we can stop once we know that  the expression will never be TRUE. Thus, "lazy evaluation", it won't do more work than it has to. Here's a pseudo-code example:

        if doc.IsValid() AND DocIsWhatIWant(doc) then
             ' something
        ELSE
             ' something else
        end if

    Because there are 2 sub-expressions here connected by an AND, the "then" part of the block should only be executed if BOTH  conditions are TRUE. With most compilers, the generated code will test the first sub-expression, and if it's FALSE, it won't bother to test the second, because it "knows" that the entire expression will certainly fail. Lazy evaluation, it works for me!

    So. What's the problem?? The problem is that LotusScript does NOT USE lazy evaluation. Here's an example similar to the one that bit me:

                                                   dim preserved as variant
                                                   dim respIdx as Integer
                                                 respIdx = 0
                                                  preserved = FillArrayWithStuff    ' might be an array, might be NULL
                                                  If Not Isnull(preserved)  AND  Isarray(preserved) AND If respIdx <= Ubound(preserved) Then
                                                         values = preserved(respIdx)
                                                        ' do more work
                                                End If

    Here's what's happening with this code: I have a "preserved" variable that gets computed by the FillArrayWithStuff() function. If there's nothing for it to do, it returns a NULL. So my next bit of work has to be controlled by a test for IsNull(), then I want to make sure that when "preserved" has something in it, the thing is an array. THEN I want to be sure that the index I'm about to apply to the array is within bounds.

    In Java, or C or many other languages, the sub-expressions here would be evaluated left-to-right. If preserved is null, they stop right there. If it's not NULL, but is not an array, don't even bother to check the array bounds.

    HOWEVER, LotusSCRIPT DOES NOT WORK THAT WAY!! LotusScript ALWAYS evaluates ALL the sub-expressions. Why? Because Visual Basic (from which LotusScript was cloned) does it that way (or at least, used to).

    So, the first time I ran this code where "preserved" was NULL (not an error condition, it was set up that way on purpose), LotusScript threw an exception on the Ubound() call. I had forgotten that LotusScript is not "lazy". I should have coded it this way:

                                                   dim preserved as variant
                                                   dim respIdx as Integer
                                                 respIdx = 0
                                                  preserved = FillArrayWithStuff    ' might be an array, might be NULL
                                                 If Not Isnull(preserved)  Then
                                                        If Isarray(preserved) Then
                                                                If respIdx <= Ubound(preserved) Then
                                                                        values = preserved(respIdx)
                                                                         ' do more work
                                                                End If        ' ubound
                                                       End If                 ' isarray
                                               End If                   ' isnull

    So, here's one case where the fact that LS is not "lazy" made more work for me. Sigh. I need a nap.

    Geek Ya Later!


    (Need expert application development architecture/coding help? Contact me at: bbalaban, gmail.com)
    Follow me on Twitter @LooseleafLLC
    This article ┬ęCopyright 2009 by Looseleaf Software LLC, all rights reserved. You may link to this page, but may not copy without prior approval.