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 counter= [:]
try{
  def count= 0
  counter.incr= { count++; counter.show() }
  counter.decr= { count--; counter.show() }
  counter.show= { count }
}

counter.incr()
assert counter.show() == 1

Expando

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

...

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
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 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:

...