Monday, February 12, 2018

Groovy: Basic Concepts: Binding and Scope

Binding and scope define how a language manages defining, storing and accessing variables and the data contained or referenced by that variable.  This section describes how Groovy manages variable/function binding and scope.

Type Binding

Groovy uses a hybrid of static and apparent dynamic typing.  Because Groovy is a superset of Java, it can utilize the compile time binding and type definition of the Java language.  However, to increase the flexibility of the language, Groovy added an additional layer of dynamic-like typing.  It accomplishes this through the def keyword which creates an un-typed variable.  This type allows the Groovy interpreter/cross-compiler to perform a runtime evaluation and value interpretation.  Under the covers, Groovy treats any variable defined by the def keyword as a subclass of Object.
Groovy, when executing in script mode, does not require that variables are explicitly defined offering the option to implicitly define them as in Perl or other languages.  However, if the value is implicitly defined, then it contains a separate scope than an explicitly defined variable.  See Scope below for a further definition of how Groovy works with scope.

Scope

Scoping defines where a variable can be accessed. This section describes how Groovy manages scope.

Scope and Visibility

Groovy is a nested block-based language, like Java.  This means that Groovy follows the block scope concept where a variable’s scope is limited to the inner-most block that it exists in.  For example, a variable defined inside a loop or other block structure only exists within that block.
Groovy also offers a class grouping through the use of packages.  This allows the developer to group a set of related classes together.  In the context of scope, this affects the class and instance level variables and methods, specifically in where they can be invoked.  Packages are defined as follows:
package name.with.dots
When defining a variable at a class or script level, the language offers three levels of visibility protection: public, protected and private.  Public variables and methods are available to any class within any package.  Protected variables and methods are limited to access within other classes in the same package.  Private variables are restricted to instances of that class only.  In Java, the default visibility for a method or variable is protected.
When a Groovy application is written with classes, it follows the standard Java-based scoping as defined above.  One difference with Java is that Groovy marks variables and methods as public by default instead of protected.  The following example shows example Groovy code written in the class style and executed in the runtime interpreter.
class ExampleClass
{
    // Statically defined variable
    private static def STATIC_STRING =
             "A static string"
 
    def createString()
    {
         return STATIC_STRING + "," +
           System.currentTimeMillis()
    }
 
    public static void main(String[] args)
    {
        ExampleClass ec = new ExampleClass();
   
        AnotherExample ae = new AnotherExample()
        // Accesses the automatic getters/setters
        ae.index = 1
        ae.name = ec.createString()
        println ae
    }
}
 
class AnotherExample
{
    private int index;
    private String name;
 
    // Remember, Groovy is public by default
    String toString()
    {
        return name + ":" + index;
    }
}
This code will generate the following output:
A static string,1510640317383:1
However, Groovy can also run in either an interactive or script based mode.  When a Groovy script is executed, scope is modified slightly.  Specifically, variables defined with a type (def, int, etc) are bound to the script itself.  This means any methods, called closures in Groovy, defined in the script will not have access to that variable.  If a variable’s type is not specified, it is given a global scope.  The mechanics of how Groovy deals with script mode will be described in the Object-Oriented Paradigm section.
The following example will demonstrate the scoping of variables in Groovy.
def useGlobal()
{
    // This will work as its a global
    println "In useGlobal: aGlobal = " + aGlobal
    aGlobal = 4
}
 
def useLocal(def variable)
{
    variable = 4
    println "In useLocal variable = " + variable
}
 
def failOnLocal()
{
    // This will throw an exception
    println aLocal
}
 
// Define the variable globally (available to all
// methods)
aGlobal = 1
// Define it local to the script
def aLocal = 1
 
println "In script aGlobal = " + aGlobal
useGlobal()
println "In script aGlobal = " + aGlobal
 
println "In script aLocal = " + aLocal
useLocal(aLocal)
println "In script aLocal = " + aLocal
 
failOnLocal()
Given the above script, the following output is generated:
In script aGlobal = 1
In useGlobal: aGlobal = 1
In script aGlobal = 4
In script aLocal = 1
In useLocal variable = 4
In script aLocal = 1
Exception thrown
In this example, aGlobal is treated as a global variable and is accessible both in the script itself and any of the defined functions.  The variables aLocal and variable are scoped more narrowly.  The variable aLocal is scoped to the script itself and is not directly available to any closures.  The variable v is scoped to the useLocal function only.

Storage Binding and Lifetime

Java, and by extension Groovy, allows for static binding of variables storage.  They accomplish this through the static keyword.  Any variables or functions defined with this modifier will be allocated storage during compile time and be readily accessible.  Other elements in a Groovy application are dynamically allocated storage at runtime.  These elements include non-static, class and method level variables as well as any object instances created during execution.  Groovy also offers a final keyword which marks a variable as readable but not updateable.

Declaration

Variable declaration defines the type, name and other elements.  This section describes these elements.

Type

Groovy does not support the declaration or re-declaration of types.

Constant

Groovy does support a form of constant through the use of the final and static keywords.  Variables marked as final are identified as non-modifiable and static indicates that a variable is available throughout the lifetime of the program execution.

Variable

Groovy allows for creating variables to store values, manage composite values and reference objects.  In defining a variable name, Groovy allows for names using a mixture of characters and numbers.  The following rules apply:
  • Variables must start with a character or a dollar sign ($)
  • Variables must not start with a number
  • They can include characters A-Z, a-z, \u00C0 to \u00D6, \u00D8 to \u00F6, \u00F8 to \u00FF and \u0100 to \uFFFE
  • It must not be a reserved keyword, such as as, for or while
  • Quoted identifiers are allowed after a dot (.) in a dotted expression.

Procedure

Groovy defines procedures in a similar manner to C, C++ and Java.  It takes the form of:
<return type> name(<parameter list>)
If a procedure is declared in a class it can optionally be prefixed with a visibility modifier.  In script mode there are no visibility modifiers.

Sequential and Recursive

Groovy supports sequential and recursive declaration in both class and script modes.

Blocks

Groovy is a block based language, with blocks defined by a pair of curly-braces ‘{}’.  Blocks control the scope of a variable, as discussed in the section Scope.  It also provides a collection of commands that can be assigned to a function.

No comments: