5 Sep 2012

Nested classes

As I've already told in previous post, I need to use nested classes. The main problem is that nested classes in CoffeeScript behave not like nested classes in Java. In Java any nested class can access fields and methods of the outer class instance in that the nested class instance was created. It is widely used, e.g. for iterators. In CoffeeScript you can define a nested class and create its' instance from the outer one but this nested class can't access outer's fields and methods.
So, you need somehow tell the nested class instance who created it. I've found two ways of solution.
The first one is C# way. You pass outer class instance reference to nested class constructor. This works fine. I do not like this way because you need to modify every constructor in every nested class (CoffeeScript allows you to determine only one constructor for each class, but you can use static methods as constructor; I will tell about this later).

The second one seems to me to be more elegant. You declare variable in outer class that holds the instance. Look:
class ArrayWrapper
  self = undefined
  array: undefined

  constructor: (number) ->
    self = this
    @array = new Array number

  set: (index, value) ->
    @array[index] = value

  top: () ->
    return new Iterator 0

  class Iterator
    index: undefined

    constructor: (@index) ->

    next: () ->
      res = self.array[@index]
      if @index == self.array.length then @index = 0
      return res

    prev: () ->
      res = self.array[@index]
      if @index == -1 then @index = self.array.length - 1
      return res
In this simple example we make a class that allows moving along array elements in both directions and in circle. The nested class is iterator. It gets an access to outer class instance array through self variable. Take a look at line 2. Do you see = instead of :? self is not a field of ArrayWrapper, it is a variable in the same scope as outer class methods and nested class itself. Java and C# do not allow declaring such variables. This variable is then initiated in outer class constructor (line 6) and used in nested class methods (lines 21, 23, 27, 29).
Lets test this class:
test = new ArrayWrapper 10
for i in [0..9]
  test.set i, i*i
fromLeftToRight = "Ring of size 10 from left to right 15 times: "
it = test.top()
for i in [0..14]
  fromLeftToRight += it.next() + " "
console.log fromLeftToRight
fromRightToLeft = "Ring of size 10 from right to left 15 times: "
it = test.top()
for i in [0..14]
  fromRightToLeft += it.prev() + " "
console.log fromRightToLeft
The output is:
Ring of size 10 from left to right 15 times: 0 1 4 9 16 25 36 49 64 81 0 1 4 9 16   
Ring of size 10 from right to left 15 times: 0 81 64 49 36 25 16 9 4 1 0 81 64 49 36   
For now these are two ways of nested classes problem solution. Maybe, you know any others?

To be continued...

No comments:

Post a Comment