Scala: More differences from Java

Method declarations use the def keyword and follow’s Scalas syntax rules of putting the type after the symbol for argument variables. In our send method below, the statements within look a lot like Java code with some minor differences:

  def send(socket: SocketChannel, data: Array[Byte]) {
    this.pendingChanges.synchronized {
      // Indicate we want the interest ops set changed
      this.pendingChanges.add(new ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE))

      // And queue the data we want written
      this.pendingData.synchronized {
        var queue: java.util.List[ByteBuffer] = this.pendingData.get(socket)
        if (queue == null) {
          queue = new java.util.ArrayList[ByteBuffer]()
          this.pendingData.put(socket, queue)
        }
        
        queue.add(ByteBuffer.wrap(data))
      }
    }

    // Finally, wake up our selecting thread so it can make the required changes
    this.selector.wakeup()
  }

On line 2, synchronized is a method, not a keyword as it was in Java. The block that follows is a closure. That means it is an anonymous function object that has access to variables in the scope it was declared. In this case it has access to the socket and data argument variables. This closure is passed into the synchronized method and the resulting behaviour is identical to the Java synchronized block.

The following run method shows more Scala language constructs:

  def run() {
    while (true) {
      try {
        // Process any pending changes
        this.pendingChanges.synchronized {
          val changes = this.pendingChanges.iterator()
          
          while (changes.hasNext()) {
            val change = changes.next()
            
            change.`type` match {
            case ChangeRequest.CHANGEOPS =>
              val key = change.socket.keyFor(this.selector)
              key.interestOps(change.ops)
            }
          }
          
          this.pendingChanges.clear()
        }

        // Wait for an event one of the registered channels
        this.selector.select()

        // Iterate over the set of keys for which events are available
        val selectedKeys = this.selector.selectedKeys().iterator()
        while (selectedKeys.hasNext()) {
          val key: SelectionKey = selectedKeys.next()
          selectedKeys.remove()

          if (key.isValid()) {
            // Check what event is available and deal with it
            if (key.isAcceptable()) {
              this.accept(key)
            } else if (key.isReadable()) {
              this.read(key)
            } else if (key.isWritable()) {
              this.write(key)
            }
          }
        }
      } catch { case e: Exception =>
        e.printStackTrace()
      }
    }
  }

The familiar while loop is used on line 2, although you will find that Scala doesn’t support Java’s continue or provide an equivalent. This is why the key.isValid() test is inverted to avoid needing to use a continue construct.

Line 11 has a statement that would be quite unfamiliar to Java programmers. It’s analog in Java is the switch statement, but is is way more powerful. The Java switch statement can only be used in non reference types and enumerations. The Scala match statement can be used on any object and can even be used to deconstruct complicated objects to get at their components. The code on line 11, however, behaves just like a switch statement does: The block inside the match block but under the case statement executes only if change.`type` and ChangeRequest.CHANGEOPS have the same value.

There is also a try block that at first glance looks very much like the Java equivalent apart from the syntax differences. The semantics are different however and much more powerful. As written it binds the caught exception object to e if the type of the exception object is Exception and then executes the code following =>.

Here is another method that demonstrates some more Scala features:

  private def write(key: SelectionKey) = {
    val socketChannel = key.channel().asInstanceOf[SocketChannel]

    this.pendingData.synchronized {
      val queue = this.pendingData.get(socketChannel)

      // Write until there's not more data ...
      val breaks = new Breaks
      breaks.breakable {
        while (!queue.isEmpty()) {
          val buf = queue.get(0)
          socketChannel.write(buf)
          if (buf.remaining() > 0) {
            // ... or the socket's buffer fills up
            breaks.break
          }
          queue.remove(0)
        }
      }

      if (queue.isEmpty()) {
        // We wrote away all data, so we're no longer interested
        // in writing on this socket. Switch back to waiting for
        // data.
        key.interestOps(SelectionKey.OP_READ)
      }
    }
  }

Line 2 shows how casts are performed in Scala. There is no special cast syntax as there is in Java or C. Instead, use the asInstanceOf method supplying the desired type as the type argument to this method.

While support for continue doesn’t exist, there is support for a break construct in the Scala library that can be used to break from loops. It is however a little more involved. You need to create an object of the type Breaks, and then use the breakable method of the object to delimit the area you would want to break from. When the break method is invoked, the program control will continue from the point after where the break method is called. By delimiting the code with the breakable method, it is possible to precisely control where the break puts the program control.

Finally as there is no support for static methods, the main method is declared just the way you would expect: a normal method in a singleton object:

object NioServer {
  def main(args: Array[String]) = {
    try {
      val worker = new EchoWorker()
      new Thread(worker).start()
      new Thread(new NioServer(null, 9876, worker)).start()
    } catch { case e: IOException =>
      e.printStackTrace()
    }
  }
}
Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s