Home

Back

Contents

Next

Scripted Methods

You can define define methods in BeanShell, just as they would appear in Java:

int addTwoNumbers( int a, int b ) {
    return a + b;
}

And you can use them in your scripts just as you would any Java method or built-in BeanShell command:

sum = addTwoNumbers( 5, 7 );

Just as BeanShell variables may be dynamically typed, methods may have dynamic argument and return types. We could, for example, have declared our add() method above like so:

add( a, b ) {
    return a + b;
}

In this case, BeanShell would dynamically determine the types when the method is called and attempt to "do the right thing":

foo = add(1, 2);
print( foo ); // 3

foo = add("Oh", " baby");
print( foo ); // Oh baby

In the first case Java performed arithmetic addition on the integers 1 and 2. (By the way, if we had passed in numbers of other types BeanShell would have performed the appropriate numeric promotion and returned the correct Java primitive type.) In the second case BeanShell performed the usual string concatenation for String types and returned a String object. This example is a bit extreme, as there are no other overloaded operators like string concatenation in Java. But it serves to emphasize that BeanShell methods can work with loose types.

Methods with unspecified return types may return any type of object (as in the previous example). Alternatively they may also simply issue a "return;" without a value, in which case the effective type of the method is "void" (no type). In either case, the return statement is optional. If the method does not perform an explicit "return" statement and the return type is not explicitly set to void, the value of the last statement or expression in the method body becomes the return value (and must adhere to any declared return typing).

Visibility of Variables and Methods

As you might expect, within a method you can refer to the values of variables and method names from the parent context. For example:

a = 42;
someMethod() { ... }

foo() {
    print( a );
    someMethod(); // invoke someMethod()
}

// invoke foo()
foo(); // prints 42

We could say that variable values and method names are "inherited" from the parent scope in the usual way. In BeanShell variable assignment, however, always defaults to the local scope. When you assign a value to a variable within your method, it by default creating a new variable in the current scope. For example, a variable assignment in the foo() method above would by default create a local variable in the scope of the foo() method. In the next section we'll talk more about this, why it is so, and what it implies.

Scope Modifiers: 'super'

Within a method, it is possible to explicitly qualify a variable or method reference with the identifier 'super' in order to refer to the parent method's scope (the scope in which the method is defined).

a = 42;

foo() {
    a = 97;
    print( a );
    print( super.a );
}

foo();  // prints 97, 42
print( a ); // prints 42

In the case above, the variable 'a' by default refers to the local method scope. By qualifying 'a' with 'super' we can refer to the scope "above". Note that the local use of 'a' did not change the value in the parent scope.

This behavior might not be what you'd expect. It may appear in this example that we should be changing the value of the parent's 'a', rather than creating a new local variable called 'a'. This case is one of the only places where BeanShell could be percieved to have an ambiguity with respect to standard Java syntax. We will explain why this exists and what it means more later. But for now, if it makes you feel any better, the explanation is that a BeanShell script is really like a Java method. So technically what we have here is a situation that can't exist in Java - a method within a method - and it is therefore not unreasonable to expect some new semantics.

Tip:
For those for whom strict Java compatability is the most important issue (e.g. Java students and teachers) BeanShell offers a "Strict Java" mode. Specifying setStrictJava( true ) eliminates any potential ambiguity, by turning off loosely typed variables and arguments entirely.

So, we've seen that 'super' can be used to refer to the method's parent context. You may never have a need to do this if you simply do all your work in your methods and return their results as a return value. But we'll see a bit later how this fits in with scripting Objects in BeanShell. As we hinted in the intervening note, we'll also see that BeanShell allows methods to be declared at various levels. Later we'll discuss another qualifier 'global', which always refers to the "top-most' scope. In our previous example 'super' and 'global' both referred to the same place, the context that defines foo().

Finally, Not to get too far ahead of ourselves, but we should note that 'super' always refers to the parent context - the scope in which the method was declared. Later when we talk about scripted objects it might be tempting to think of 'super' as the "caller's" context. But that is not necessarily the case. BeanShell has a different qualifier, which goes beyond standard Java, to allow referring to the caller's scope. It can be helpful in writing methods like BeanShell commands that often must have side effects in the caller's scope (as opposed to wherever the method is defined).

Home

Back

Contents

Next