Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Accessing Private Variables

Closures and functions can't remember any information defined within themselves between invocations. If we want a closure to remember a variable between invocations, one only it has access to, we can nest the definitions inside a block:

Code Block
def c
try{
   def a= new Random() //only closure c can see this variable; it is private to c
   c= { a.nextInt(100) }
}
100.times{ println c() }
try{ a; assert 0 }catch(e) //'a' inaccessable here
{ assert e instanceof MissingPropertyException }
//'a' inaccessable here

We can have more than one closure accessing this private variable:

Code Block
def counterInit, counterIncr, counterDecr, counterShow
      //common beginning of names to show common private variable/s
try{
   def count
   counterInit= { count= it }
   counterIncr= { count++ }
   counterDecr= { count-- }
   counterShow= { count }
}
counterInit(0)
counterIncr(); counterIncr(); counterDecr(); counterIncr()
assert counterShow() == 2

...

Code Block
def counter= [:]
try{
   def count= 0
   counter.incr= { count++; (counter.show)() }
//we must use map name and nonintuitive parens here
  counter.decr= { count--; (counter.show)() }
   counter.show= { count }
}

//intuitive format for closure call doesn't work...
try{ counter.incr();
assert 0 }catch(e){ assert e instanceof MissingMethodException }

//we must call closures in one of these formats...
counter['incr']()
(counter.incr)()
assert (counter.show)() == 21

Expando

We can access private variables with an Expando instead. An expando allows us to assign closures to Expando names:

Code Block
def counter= new Expando()
try{
   def count= 0
   counter.incr= { count++; show() }
           //no need to qualify closure call with expando name
   counter.decr= { count--; show() }
   counter.show= { timesShown++; count }
   counter.timesShown= 0
           //we can associate any value, not just closures, to expando keys
}
//we can use intuitive syntax for closure calls...
counter.incr(); counter.incr(); counter.decr(); counter.incr()
assert counter.show() == 2

...

Code Block
def language= new Expando()
language.name= "Groovy"
language.letterValue numLetters= {->   (name as List).injectsize(0){flo,it->     flo+= 1+ (it as int) - ( (it in 'a'..'z')?('a' as int):(it in 'A'..'Z')?('A' as int):(1+(it as int)) )
  }
}
assert language.letterValuenumLetters() == 1026
language.name= "PythonRuby"
assert language.letterValuenumLetters() == 984
language.name= "A...b,   cPHP"
assert language.letterValuenumLetters() == 63

Like individual closures, closures in expandos see all external variables all the way to the outermost block. This is not always helpful for large programs as it can limit our choice of names:

Code Block
def a= 7
try{
   //... ... ... lots of lines and blocks in between ... ... ...
   def exp= new Expando()
   exp.c= {
       //def a= 2 //does not compile becauseif uncommented: a is already defined
       //... ... ...
   }
}

For single-argument closures, both standalone and within expandos, we can use the implicit parameter as a map for all variables to ensure they're all valid, though the syntax is not very elegant:

Code Block
def a= 7
try{
   def c= {
       it= [it: it]
       it.a= 2
       it.it + it.a
  }
   assert c(3) == 5
}

There is a better way to ensure a chosen variable name will not "shadow" another from the same scope.

Static Classes

Just as we can use functions instead of closures to hide names from the surrounding context, so also we can use static classes instead of expandos to hide such external names. We use the static keyword to qualify the individual definitions in a class definition:

Code Block
def a= 7
def a= 7
class Counter{
   //variable within a class is called a field...
   static public count= 0
      //count has 'public' keyword, meaning it's visible from outside class

   //function within a class is called a method...
   static incr(){
       count++
      //variables defined within class visible from everywhere else inside class
   }
   static decr(){
       //println a //compile error if uncommented:
because                 //a is outside the class and not visible
       count--
   }
}
Counter.incr(); Counter.incr(); Counter.decr(); 5.times{ Counter.incr() }
assert Counter.count == 6

Methods act quite similar to standalone functions. They can take parameters:

Code Block
class Counter{
   static private count = 0
      //qualified with private, meaning not visible from outside class
   static incr( n ){ count += n }
   static decr( count ){ this.count -= count }
      //params can have same name as a field; 'this.' prefix accesses field
   static show(){ count }
}
Counter.incr(2); Counter.incr(7); Counter.decr(4); Counter.incr(6)
assert Counter.show() == 11

We can have more than one method of the same name if they each have different numbers of parameters. (But see forthcoming tutorial on "Groovy Typing" for exceptions to this rule.)

Code Block
class Counter{
   static private count = 0
   static incr(){ count++ }
   static incr( n ){ count += n }
   static decr(){ count-- }
   static decr( n ){ count -= n }
   static show(){ count }
}
Counter.incr(17); Counter.incr(); Counter.decr(4)
assert Counter.show() == 14

//Methods are also similar to other aspects of functions:

Code Block
class U{
   static a(x, Closure c){ c(x) }
   static b( a, b=2 ){ "$a, $b" } //last argument/s assigned default values
   static c( arg, Object[] extras ){ arg + extras.inject(0){ flo, it-> flo+it } }
   static gcd( m, n ){ if( m%n == 0 )return n; gcd(n,m%n) }
                                           //recursion by calling own name
}
assert U.a(7){ it*it } == 49 //shorthand passing of closures as parameters
assert U.b(7, 4) == '7, 4'
assert U.b(9) == '9, 2'
assert U.c(1,2,3,4,5) == 15 //varying number of arguments using Object[]
assert U.gcd( 28, 35 ) == 7

We can assign each method of a static class to a variable and access it directly similar to how we can with functions:

Code Block
class U{
   static private a= 11
   static f(n){ a*n }
}
assert U.f(4) == 44
def g= U.&f //special syntax to assign method to variable
assert g(4) == 44
def h = g //don't use special syntax here
assert h(4) == 44

When there's no accessibility keyword like 'public' or 'private' in front of a field within a static class, it becomes a property, meaning two extra methods are created:

Code Block
class Counter{
   static count = 0
       //property because no accessibility keyword (eg 'public','private')
   static incr( n ){ count += n }
   static decr( n ){ count -= n }
}
Counter.incr(7); Counter.decr(4)
assert Counter.count == 3
assert Counter.getCount() == 3 //extra method for property, called a 'getter'
Counter.setCount(34)                      //extra method for property, called a 'setter'
assert Counter.getCount() == 34

When we access the property value using normal syntax, the 'getter' or 'setter' is also called:

Code Block
class Counter{
   static count= 0 //'count' is a property

   //we can define our own logic for the getter and/or setter...
   static setCount(n){ count= n*2 } //set the value to twice what's supplied
   static getCount(){ 'count: '+ count }
                    //return the value as a String with 'count: ' prepended
}
Counter.setCount(23) //our own 'setCount' method is called here
assert Counter.getCount() == 'count: 46'
                     //our own 'getCount' method is called here
assert Counter.count == 'count: 46'
                     //our own 'getCount' method is also called here
Counter.count= 7
assert Counter.count == 'count: 14'
                 //our own 'setCount' method was also called in previous line

To run some code, called a static initializer, the first time the static class is accessed. We can have more than one static initializer in a class.

Code Block
class Counter{
   static count = 0
   static{ println 'Counter first accessed' } //static initializer
   static incr( n ){ count += n }
   static decr( n ){ count -= n }
}
println 'incrementing...'
Counter.incr(7) //'Counter first accessed' printed here
println 'decrementing...'
Counter.decr(4) //nothing printed

Instantiable Classes

We can write instantiable classes, templates from which we can construct many instances, called objects or class instances. We don't use the static keyword before the definitions within the class:

Code Block
class Counter{
   def count = 0 //must use def inside classes if no other keyword before name
   def incr( n ){ count += n }
   def decr( n ){ count -= n }
}
def c1= new Counter() //create a new object from class
c1.incr(2); c1.incr(7); c1.decr(4); c1.incr(6)
assert c1.count == 11

def c2= new Counter() //create another new object from class
c2.incr(5); c2.decr(2)
assert c2.count == 3

We can run some code the first time each object instance is constructed. First, the instance initializer/s are run. Next run is the constructor with the same number of arguments as in the calling code.

Code Block
class Counter{
   def count
   { println 'Counter created' }
      //instance initializer shown by using standalone curlies
   Counter(){ count= 0 }
      //instance constructor shown by using class name
   Counter(n){ count= n }
      //another constructor with a different number of arguments
   def incr( n ){ count += n }
   def decr( n ){ count -= n }
}
c = new Counter() //'Counter created' printed
c.incr(17); c.decr(2)
assert c.count == 15
d = new Counter(2) //'Counter created' printed again
d.incr(12); d.decr(10); d.incr(3)
assert d.count == 7

If we don't define any constructors, we can pass values directly to fields within a class by adding them to the constructor call:

Code Block
class Dog{
   def sit
   def number
   def train(){ ([sit()] * number).join(' ') }
}
def d= new Dog( number:3, sit:{'Down boy!'} )
assert d.train() == 'Down boy! Down boy! Down boy!'

Methods, properties, and fields on instantiable classes act similarly to those on static classes:

Code Block
class U{
   private timesCalled= 0 //qualified with visibility, therefore a field
   def count = 0 //a property
   def a(x){ x }
   def a(x, Closure c){ c(x) } //more than one method of the same name but
                              //each having different numbers of parameters
 
  def b( a, b=2 ){ "$a, $b" } //last argument/s assigned default values
   def c( arg, Object[] extras ){ arg + extras.inject(0){ flo, it-> flo+it } }
   def gcd( m, n ){ if( m%n == 0 )return n; gcd(n,m%n) }
                              //recursion by calling own name
}
def u=new U()
assert u.a(7){ it*it } == 49 //shorthand passing of closures as parameters
assert u.b(7, 4) == '7, 4'
assert u.b(9) == '9, 2'
assert u.c(1,2,3,4,5) == 15 //varying number of arguments using Object[]
assert u.gcd( 28, 35 ) == 7
u.setCount(91)
assert u.getCount() == 91

A class can have both static and instantiable parts by using the static keyword on the definitions that are static and not using it on those that are instantiable:

Code Block
class Dice{
   //here is the static portion of the class...
   static private count //doesn't need a value
   static{ println 'First use'; count = 0 }
   static showCount(){ return count }

   //and here is the instantiable portion...
   def lastThrow
   Dice(){ println 'Instance created'; count++ }

   //static portion can be used by instantiable portion, but not vice versa
   def throww(){
       lastThrow = 1+Math.round(6*Math.random()) //random integer from 1 to 6
       return lastThrow
   }
}
d1 = new Dice() //'First use' then 'Instance created' printed
d2 = new Dice() //'Instance created' printed
println "Dice 1: ${(1..20).collect{d1.throww()}}"
println "Dice 2: ${(1..20).collect{d2.throww()}}"
println "Dice 1 last throw: $d1.lastThrow, dice 2 last throw: $d2.lastThrow"
println "Number of dice in play: ${Dice.showCount()}"

A class can have more than one constructor:

Code Block

class A{
  def list= []
  A(){
    list<< "A constructed"
  }
  A(int i){
    this()
      //a constructor can call another constructor if it's the first statement
    list<< "A constructed with $i"
  }
  A(String s){
    this(5)
    list<< "A constructed with '$s'"
  }
}
def a1= new A()
assert a1.list == ["A constructed"]

def a2= new A(7)
assert a2.list.collect{it as String} == [
  "A constructed",
  "A constructed with 7",
]

def a3= new A('bird')
assert a3.list.collect{it as String} == [
  "A constructed",
  "A constructed with 5",
  "A constructed with 'bird'",
]

Categories

When a class has a category method, that is, a static method where the first parameter acts like an instance of the class, we can use an alternative 'category' syntax to call that method:

Code Block
class View{
   def zoom= 1
   def produce(str){ str*zoom }
   static swap(self, that){ //first parameter acts like instance of the class
       def a= self.zoom
       self.zoom= that.zoom
       that.zoom= a
   }
}
def v1= new View(zoom: 5), v2= new View(zoom: 4)
View.swap( v1, v2 ) //usual syntax
assert v1.zoom == 4 && v2.zoom == 5
use(View){ v1.swap( v2 ) } //alternative syntax
assert v1.zoom == 5 && v2.zoom == 4
assert v1.produce('a') == 'aaaaa'

We can also use category syntax when the category method/s are in a different class:

Code Block
class View{
   static timesCalled= 0 //unrelated static definition
   def zoom= 1
   def produce(str){ timesCalled++; str*zoom }
}
class Extra{
   static swap(self, that){ //first parameter acts like instance of View class
       def a= self.zoom
       self.zoom= that.zoom
       that.zoom= a
   }
}
def v1= new View(zoom: 5), v2= new View(zoom: 4)
use(Extra){ v1.swap( v2 ) }
      //alternative syntax with category method in different class
assert v1.zoom == 4 && v2.zoom == 5
assert v1.produce('a') == 'aaaa'

...

Code Block
assert String.format('Hello, %1$s.', 42) == 'Hello, 42.'
use(String){
   assert 'Hello, %1$s.'.format(42) == 'Hello, 42.'
}

...

Code Block
def list= ['a', 7, 'b', 9, 7, 7, 2.4, 7]
Collections.replaceAll( list, 7, 55 ) //normal syntax
assert list == ['a', 55, 'b', 9, 55, 55, 2.4, 55]

list= ['a', 7, 'b', 9, 7, 7, 2.4, 7]
use(Collections){
   list.replaceAll(7, 55) //category syntax
}
assert list == ['a', 55, 'b', 9, 55, 55, 2.4, 55]

We can call category methods inside other category methods:

Code Block
class Extras{
   static f(self, n){ "Hello, $n" }
}
class Extras2{
   static g(self, n){
       Extras.f(self, n)
   }
   static h(self, n){
       def ret
       use(Extras){ ret= self.f(n) } //call Extras.f() as a category method
       ret
   }
}
assert Extras.f(new Extras(), 4) == 'Hello, 4'
assert Extras2.g(new Extras2(), 5) == 'Hello, 5'
assert Extras2.h(new Extras2(), 6) == 'Hello, 6'

class A{ }
def a= new A()
use(Extras){
   assert a.f(14) == 'Hello, 14'
}
use(Extras2){
   assert a.g(15) == 'Hello, 15'
   assert a.h(16) == 'Hello, 16' //call category method within another
}

But we can't call category methods inside another category method from the same class:

Code Block
class Extras{
   static f(self, n){ "Hello, $n" }
   static g(self, n){ f(self, n) }
   static h1(self, n){ f(n) } //calling f without first parameter only valid
                             //when called within a category method
   static h2(self, n){
       def ret
       use(Extras){
      ret= self.f(n)
    } //class as category within itself only valid if method wasn't called
                                                       //using category syntax
       ret
   }
}
assert Extras.f(new Extras(), 4) == 'Hello, 4'
assert Extras.g(new Extras(), 5) == 'Hello, 5'
try{ Extras.h1(new Extras(), 6); assert 0 }
catch(e){ assert e instanceof MissingMethodException }
assert Extras.h2(new Extras(), 7) == 'Hello, 7'

class A{ }
def a= new A()
use(Extras){
   assert a.f(14) == 'Hello, 14'
   assert a.g(15) == 'Hello, 15'
   assert a.h1(16) == 'Hello, 16'
   try{ a.h2(17); assert 0 }
  catch(e){ assert e instanceof java.lang.reflect.InvocationTargetExceptionGroovyRuntimeException }
}

A lot of entities in Groovy are classes, not just the explicit ones we've just learnt about. Numbers, lists, sets, maps, strings, patterns, scripts, closures, functions, and expandos are all implemented under the hood as classes. Classes are the building block of Groovy.