Monday, February 12, 2018

Groovy: Basic Concepts: Variables, Storage and Commands

Groovy supports variables for storing values and referencing other objects.

Simple Variables

Groovy supports simple variables.  These variables can contain either a primitive value or a reference to an object.
int i = 0
short s = 4

Composite Variables

Groovy also supports composite variables that can store or reference arrays and maps.  When updating composites, Groovy supports both selective and total updates.
// Define a composite as an array
def comp = [1,2,3]
// Selective update
comp[2] = 4
// Total update
comp = [5,6,7]
As mentioned in the section Arrays, Groovy defaults to arrays being the Java collection object, typically java.util.ArrayList, instead of a static array.  This means that arrays in Groovy are dynamic.  It does support flexible arrays in that a variable may be defined as an array, but through total update, the reference can point to an array of a different size.

Copy and Reference

Groovy supports the reference semantic.  When assigning one variable’s value to another, it will either copy the primitive value or the reference.  Groovy objects to support a clone method that has a similar effect to the copy semantic, however, the implementer will need to determine exactly how the copy occurs.

Lifetime

Variables created in Groovy are created on the heap and are generally defined as local variables.  Each variable is limited to the class that it was defined in, further defined by the block structure.  As each block is closed, the variables defined within that block fall out of scope and are marked for removal.  See the section Scope and Visibility for more information on scope in Groovy.
Because Groovy is a garbage collected language, the lifetime of a variable is impossible to precisely define as the garbage collector runs at arbitrary times and will clean up variables that have been marked for collection.
Groovy does support a form of global variable, but only in the script mode.  In this mode, a global exists for the lifetime of the script execution.  In a traditional class-based mode, variables are restricted to the class they are defined in.  Modifiers to class variables do allow for marking a variable as static, which has the effect of making that variable global to all instances of the class, and if marked as public, available to all instances as well.  This can have an effect of making a static variable as globally available though they are still a member of a class and not a true global.

Pointers

Groovy does not support pointers.  It only supports references as partial replacement for pointers.
Groovy supports several types of commands including skips, assignment, sequential, conditional and iterative commands.

Skips

Groovy supports a form of skip or command.  Groovy supports the Java ‘;’ line terminator as an optional element.  A single ‘;’ is interpreted as a skip.

Assignments

Groovy supports both single and multiple variable assignment.
int a = 1
def b = c = 2

Sequential Commands

Groovy supports sequential commands using the ‘;’ as a separator.

Conditional Commands

Groovy supports two key conditional commands: if-else and switch-case.  Both allow for conditional code execution based on provided values.

if-else

Groovy supports the Java standard if-else conditional structure.  This allows for executing two different blocks of code depending on whether the statement in the if statement evaluates to true or false.
boolean comparison = new Random().nextBoolean()
 
if(comparison)
{
 println "Value was true"
}
else
{
 println "Value was false"
}
Groovy also supports the nested if-else if-else structure.
boolean comparison = new Random().nextBoolean()
boolean comparison2 = new Random().nextBoolean()
 
if(comparison && comparison2)
 println "Both are true"
else if (comparison && !comparison2)
 println "Only comparison is true"
else if (!comparison && comparison2)
 println "Only comparison2 is true"
else
 println "Both were false"

switch-case

Groovy supports the switch-case structure.  The switch statement can accept a single variable and jump to a specific code block indexed with a specific value.  Unlike Java, Groovy can perform a broader set of matching in the case statement, including strings, types and lists of values.  The following example was taken directly from the Groovy language reference.
def x = 1.23
def result = ""
 
switch ( x ) {
 case "foo":
  result = "found foo"
  // let’s fall through
 
 case "bar":
  result += "bar"
 
 case [4, 5, 6, 'inList']:
  result = "list"
  break
 
 case 12..30:
  result = "range"
  break
 
 case Integer:
  result = "integer"
  break
 
 case Number:
  result = "number"
  break
 
 case ~/fo*/:
  result = "foo regex"
  break
 
 case { it < 0 }: // or { x < 0 }
  result = "negative"
  break
 
 default:
  result = "default"
}
 
assert result == "number"

Iterative Commands

Groovy offers the following types of loops: while, for, for in, each and do-while.  The following section covers each of the type of loops available in Groovy and the samples show how to print the numbers 0-9 within the loop.

While

A while starts with a test and as long as the test results in true it will continue the loop.  This behavior is shared with the underlying Java language.
// Definition
// while(<termination>)
// {
//  statement(s)
// }
 
// Example
def i = 0
while(i < 10)
{
println i++
}

For

A for loop works similar to a while loop, except that its definition contains the conditional, the definition of the variable(s) and the code that affects the variable. In operation, the for loop works the same as the while loop in that it will continue looping while the termination comparison evaluates to true.  The initialization and increment elements are optional.
// Prototype
// for(<initialization>;<termination>;<increment>)
// {
//  <statements>
// }
 
// Example
for(int i = 0; i < 10; i++)
{
 println i
}
 
def j = 0;
 
// Example
for(; j < 10;)
{
 println j++
}
One item to note is that as of 2.4, Groovy for loops only support a single initialization parameter in a for loop, while Java can support multiple.  Groovy version 2.6 will offer this functionality.

For In

Groovy offers an alternate form of a for loop that instead of checking for a conditional, the for in loop will loop through each item in a collection (typically a static array or a List).  Other languages implement this function with a separate foreach keyword.
// Definition
// for( <type> <variable> in/: <array/list>)
// {
//  statement(s)
// }
 
// Example using the word in
for(int j in [0,1,2,3,4,5,6,7,8,9])
{
 println j
}
 
// Example using the : instead of in
for(int j : [0,1,2,3,4,5,6,7,8,9])
{
 println j
}

Do-While

The current released version of Groovy (2.4) does not support the do-while loop construct.  This is scheduled to be released in version 2.6.

Each and EachWithIndex

Because Groovy offers closures, it offers an additional form of loop that can be applied to an array, list or map.  It offers similar functionality to the for-in loop, but in a more compact syntax.  Unlike the for-in loop, as Groovy iterates through each member of the collection, it calls the provided function/closure, providing the current item as a calling parameter.
// Definition
// <array/list/map>.each(Closure c)
 
// Print 0-9
[0,1,2,3,4,5,6,7,8,9].each {
 println it
}
 
// Get the index and letter from the list
["Alpha","Bravo","Charlie","Delta","Echo"].eachWithIndex { letter, index ->
 println "${index} -> ${letter}"
}
 
// Iterate through a map, using the variable letter for key
// and name for word
[
 "A":"Alpha",
 "B":"Bravo",
 "C":"Charlie",
 "D":"Delta",
 "E":"Echo"].each{ letter, name ->
 println "${letter} <-> ${name}"
}
Because closures can be bound to variables, this can allow for more compact coding through the reuse of closures on multiple each or eachWithIndex calls.
// Define the closure
def doSomething(letter,index)
{
 println "${index} -> ${letter}"
}
 
["Alpha","Bravo","Charlie","Delta","Echo"]
 .eachWithIndex this.&doSomething
 
["Foxtrot","Golf","Helo","India","Juliet"]
 .eachWithIndex this.&doSomething

Expressions with Side Effects

Groovy supports expressions with side effects, meaning that an expression, such as a function call or operation, can be used inline with another function call or operation.  The example below shows an example of embedding a function call in an if statement.
if(getCurrentState())
{
}

No comments: