Bob Balaban's Blog

     
    alt

    Bob Balaban

     

    Geek-o-Terica 2: Using parentheses in LotusScript

    Bob Balaban  April 21 2009 03:49:49 AM
    Greetings, Geeks!

    Parentheses in LotusScript can be confusing. For example, check out this seemingly innocuous statement:

     MyFunc(arg1, arg2)

    Easy, right? Well, it's fine if "MyFunc" is a Function, but it will cause a compiler error if "MyFunc" is a Sub. Want to know why?

    The difference between a Sub and  Function (you already know this) is that a Function returns a value, and can therefore be used on the right-hand side of an assignment statement ("="), while a Sub does not return a function.

    So think about this from the compiler's point of view. An invocation of a Sub does not need parentheses around the parameter list being passed to the Sub, syntactically. Because the statement that invokes the Sub stands alone (no value is returned, so you can't assign the result of the invocation to something else, or use it in a more complex expression), there's no ambiguity:

     MyFunc "arg1", "arg2"

    works fine, I (the compiler) know just what to do. Likewise, if MyFunc is an actual Function that returns something, but I (the programmer) don't care, I can still code the above statement and the compiler knows what to do. BUT, if I use MyFunc's return value in some way -- assign it to a variable, or use it to invoke another Sub or Function, I MUST enclose the paremeter list in parentheses:

     stvar = MyFunc("arg1", "arg2")
     MySub MyFunc("arg1", "arg2"), 7

    You can see that if the language allowed me to omit the parens, line 1 might be ok, but line 2 would be impossible to parse.

    So, why is it "wrong" (compiler error) to code my original example above if "MyFunc" is a Sub? BECAUSE enclosing a paremeter in parentheses during a Sub invocation has ANOTHER MEANING! It means "pass this parementer by value, not by reference".

    What's the difference, and why would anyone care? Consider this sample agent:

    option declare     ' ALWAYS use Option Declare!
    Sub Initialize
        Dim st As String
        st = "set in Initialize"
        subr st
        Msgbox "String is: " & st
        st = "reset in initialize"
        subr (st)
        Msgbox "Now string is: " & st
    End Sub
    Sub subr(arg As String)
        arg = "set in subr"
    End Sub

    The result of the first Msgbox will be: "set in subr". The result of the second one will be: "reset in initialize". Why?

    Because the first call to "subr" passes the "st" parameter as a reference -- a pointer to the variable's memory location. So when the Sub "subr" modifies the parameter, that memory location gets updated with the new string, and Initialize "sees" the change. In the second call, the parens around "st" tell the compiler to "pass by value", the calling code does not pass a reference to "st" to the Sub, it passes a COPY of the VALUE of "st" (the string "set in initialize"). The Sub modifies the copy's memory location, but Initialize does not "see" that after the call.

    You can accomplish the same thing as using pass-by-value parens by changing the declaration of "subr" to:

     Sub subr(ByVal arg As String)

    So, now you can see why

     MyFunc(arg1, arg2)

    is weird when MyFunc is a Sub: pass-by-value around TWO parameters like that makes no sense, syntactically, so the compiler throws an error.

    Get it? Yes, it's a little odd, but don't blame LotusScript -- this little feature was copied from BASIC, as was most of the LotusScript language (BASIC as it was back in 1990, that is).

    Geek ya later.
    (Topic inspired by Kathy Brown. Thanks Kathy!)

    (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.
    Comments

    1Simon Boulton  4/21/2009 4:40:25 AM  Geek-o-Terica 2: Using parentheses in LotusScript

    That's something I didn't know about the differences between subs and funcs! About the only time I use subs is for an object constructor. Otherwise I always use a func with the 'byval' keyword for the parameters. I *did* wonder why byval wasn't the default parameter passing method . . .

    2David Leedy  4/21/2009 7:01:07 AM  Geek-o-Terica 2: Using parentheses in LotusScript

    Bob,

    Great Post!! Thanks for the info!

    How does the "Call" statement fit in? is there a difference if you use Call when invoking a sub-routine (or function)?

    I thought there was, but sitting here I don't remember.

    More often then not I typically add Call in front of the subroutine name...

    Thanks

    3Bob Balaban  4/21/2009 9:06:15 AM  Geek-o-Terica 2: Using parentheses in LotusScript

    @2 - Thanks for reminding me! I meant to say something about "call", and forgot.

    Here's an extract from the Designer Help on "Call statement":

    Usage

    When you use the Call keyword, you must include parentheses around the argument list. If there are no arguments, the empty parentheses are optional.

    When you omit the Call keyword, the following parenthesis rules apply:

    For a sub or a function, do not use parentheses around the argument list (Syntax 2) unless you are passing a single argument by value to the sub or function.

    For a function within an expression, enclose the argument list (if there is one) in parentheses (Syntax 4).

    4Tim Tripcony  4/21/2009 9:17:51 AM  Geek-o-Terica 2: Using parentheses in LotusScript

    That's one of the primary reasons why I don't use Subs anymore: the other languages that I'm using more frequently now (specifically, Java and JavaScript) have no concept of a Sub - everything's a function - therefore, the syntax never varies. Similarly, those languages require parentheses when calling functions, so I've gotten in the habit of always including parentheses in LotusScript even when they're not required (for example, when calling methods of the standard product object classes). Any habitual convention that minimizes the mental reset required when switching between languages saves my time and the client's money. Everybody wins.

    5Bob Balaban  4/21/2009 10:17:42 AM  Geek-o-Terica 2: Using parentheses in LotusScript

    @4 - Valid points, Tim, but you also have to remember that BASIC is way older than C, C++, Java, etc. Those "new kid" languages have (luckily for us!) learned from some of the mistakes of BASIC.

    Of course, you could just use "call" all the time...

    There are a LOT of idiosyncracies in LotusScript I could do Geek-o-Terica topics on. Maybe I'll do DATE types next. Or LIST. Or LIKE! (how's that for obscure?)

    6Starrow Pan  5/18/2011 5:51:21 AM  Geek-o-Terica 2: Using parentheses in LotusScript

    Great post! But am I the only one confused by "pass-by-value around TWO parameters like that makes no sense, syntactically"?

    As I understand, the argument of preventing the parameters in the caller from being modified by the called routine stands no matter how many the parameters are. So if MySub(arg1) is sometimes valid, why MySub(arg1, arg2) isn't.