The point is missed

Museum of public mistakes and unfinished projects

Phasing over from java to scala pt 1

with 6 comments

What do you do when you have all of these cool ideas for new projects and no time? How do you find the time to also keep yourself updated on the latest and greatest languages out there? Well, you would have to ask someone else because I don’t know. But I thought to give the nike way a try and just do it. I have a pet project called Agical publisher. I won’t bore you with the details of that project, maybe in some other post but what is relevant for this post is that I spend some time on it and it is written i Java.

I’ve done my share of toying with Ruby and that is a lot of fun, fun enough for me so that I start thinking that java is a bulky beast. I’m fortunate enough to work at a company with a lot of interesting discussions related to programming and Johan in particular has opened my eyes to new areas and ways to look at programming. I used to think that I liked to learn new things so it is a tough blow to realize that I have spent most of my time lately learning more about things I already know (at least in the field of programming). I feel that I can’t really give up my pet-project coding, I still feel that I have things I want to do in that area but what are pet-projects for if not learning new things?

So for no other reason than learning a new language and be better prepared in the upcoming discussions on our Friday- meetings at Agical… why not convert my pet-project to Scala?

Why Scala? I still want my project to integrate with eclipse sometime in the future so that scala generates java bytecode is a big plus. I also like that Scala seems like a very pragmatic language that adds functional oriented aspects to the object-oriented ones I already know from Java (and other OO languages). So in theory I can explore functional programming without letting go of my safe well known object oriented world, perfect! I can pretend to learn new things while not giving up on what I already know :)

Said and done, I thought that I could refactor my code-base into a java part with a scala-core so after an hour or two separating the existing code-base into implementation and API I am now in the position that I can move over implementations to scala one piece at the time. Perfect!

Lets dive right into the middle and convert my first java-class to scala in the project. Ctrl+A, Ctrl+C, new file PublishSiteGraph.scala, ctrl + V, and here we are:

package com.agical.publisher.content.site

import java.util.HashMap;

public class PublishSiteGraph implements SiteGraph {
    private final Map<String, SiteGraphNode> nodes = new HashMap<String, SiteGraphNode>();
    private final JobQueue queue;
    private final ResourceRepository resourceRepository;
    private final NodeFactory nodeFactory;

    public PublishSiteGraph(ResourceRepository resourceRepository,
            JobQueue queue, NodeFactory nodeFactory) {
         this.resourceRepository = resourceRepository;
        this.queue = queue;
        this.nodeFactory = nodeFactory;
    }

    @Override
    public SiteGraphNode findNode(String destination) {
        SiteGraphNode siteGraphNode = nodes.get(destination);
        if(siteGraphNode == null) {
            siteGraphNode = nodeFactory.create(destination, this);
            queue.enqueue(siteGraphNode);
            nodes.put(destination, siteGraphNode);
        }
        return siteGraphNode;
    }

    @Override
    public boolean exists(String resource) {
        return resourceRepository.exists(resource);
    }
}

Brilliant! But since java is not Scala it doesn’t compile! This can’t possibly end well… Ok, let’s do it, armed with my new best Scala friend on the net: Scala for java refugees (sounds like it is written for me!) and the Scala plugin for eclipse I can start step one. Making it compile!

The first steps:

  1. Remove public in front of class – In Scala classes are public by default, which kind of makes sense considering the ratio of public vs non public classes in the average java-project.
  2. change implements to extends, Scala does not have interfaces but supports multiple inheritance or traits from what I understand. I assume Scala will treat a java-interface as a trait with only abstract methods.

Now, what to do about the map? I bet Scala has some replacement for that. After some digging around in the Api docs I find: scala.collection.Map that is marked as trait and object. The object is empty, I bet the trait is what I need. From what I understand traits are like mixins in ruby, a concept I’m exceited to learn more about. Well, to me it is like an interface with some implementation attached to it so I need to find something that implements the trait.

After digging some more the choice is between scala.collection.mutable.HashMap and scala.collection.immutable.HashMap. Something tells me that I should strive to use immutable rather than mutable but mutable seems to be more of a 1.1 fit right now. So I go for that one.

Here is the upper part of the class after these initial changes:

package com.agical.publisher.content.site

import scala.collection.Map;
import scala.collection.mutable.HashMap;
import com.agical.publisher.content.SiteGraphNode;
import com.agical.publisher.content.SiteGraph;

class PublishSiteGraph extends SiteGraph {
    val nodes:Map[String, SiteGraphNode] = new HashMap[String, SiteGraphNode]();

Ok, that was easy. Now on to more of the minimum changes I need to make in order to make this beast compile. I commented out the rest of the java code and now scala tells me:

class PublishSiteGraph needs to be abstract, since method exists in trait SiteGraph of type (java.lang.String)Boolean is not defined

Ok, fair enough, I uncomment the exists method and scala continues to whine:

expected start of definition

The line of the error is on my uncommented method and scala does not like the public keyword there. Again, methods are public if you don’t say differently. Methods are declared, like in Ruby with the def keyword and the type comes after the parameter name in the formatname:type. Ok, lets make a first attempt:

def exists (resource:String):Boolean = {
    resourceRepository.exists(resource)
}

While I’m probably not the best person to explain the above there are some things that looks odd if you’re a java-guy like me. Boolean, scala does not have primitives, period. = { the best way I can explain this odd little sequence is that the codeblock {} is an anonymous function that is assigned to the exists function. There may be a more correct way to explain this but for now that explanation works for me. I happen to know that you can pass blocks like the one after the ‘=’ as parameters to other functions, if you have worked with Ruby and know about closures this should be familiar.

Also, like in ruby, the last statement in a method/function (whatever they are called in scala) is returned without having to exlpicitly say so.

Anyway, moving on with the first obstacle is out of the way. Now Scala wants a resourceRepository instance. Time to make use of scalas amazingly cool constructor properties:

class PublishSiteGraph (resourceRepository:ResourceRepository) extends SiteGraph {

What do you know, the exists method can now access the resourceRepository parameter as if it was a field of the class, whic is what it becomes from what I understand. The constructor-parameters live as properties on instance-scope, how useful! I might get back to that but it’s really all very well explained in Scala for java refugees if you want to know more.

Next problem:

class PublishSiteGraph needs to be abstract, since method findNode in trait SiteGraph of type (java.lang.String)com.agical.publisher.content.SiteGraphNode is not defined

Well, we know what to do about that now:

def findNode(destination:String):SiteGraphNode = {
   SiteGraphNode siteGraphNode = nodes.get(destination);
   if(siteGraphNode == null) {
     siteGraphNode = nodeFactory.create(destination, this);
     queue.enqueue(siteGraphNode);
    nodes.put(destination, siteGraphNode);
   }
   siteGraphNode;
}

A whole bunch of new errors show up. Addressing them one at the time yields the follwing:

def findNode(destination:String):SiteGraphNode = {
    var siteGraphNode = nodes.get(destination);
    if(siteGraphNode == null) {
      siteGraphNode = nodeFactory.create(destination, this);
      queue.enqueue(siteGraphNode);
      nodes.put(destination, siteGraphNode);
    }
    siteGraphNode;
}

Cool, now the nodeFactory and queue are missing. Let’s add them as constructor properties:

class PublishSiteGraph (resourceRepository:ResourceRepository,
                        nodeFactory:NodeFactory,
                        queue:JobQueue) extends SiteGraph {

Cool, this is easy! But what is this?!

type mismatch;
 found   : com.agical.publisher.content.SiteGraphNode
 required: Option[com.agical.publisher.content.SiteGraphNode]

Where does this Option[ come from? I'll ask my good friend google. Google suggests a couple of links and for some reason I pick this one. Ah, Option is a way to deal with null, At first I thought that Scala expect nulls from java API:s, rather insulting, after all this is my code :) But when I examined a bit further it is the line:

var siteGraphNode = nodes.get(destination);

that causes the problem. Scalas map returns options and scala infers the type Option[SiteGraphNode] to our siteGraphNode variable. Since siteGraphNode now has that type and we try to assign the option of a variable of the type SiteGraphNode, the typesystem kicks in and prevents this. Cool!

If we look at the code again it is a really good illustration of why an option is a better choice than what is currently in the method. Java maps may or may not return null. In case of a null value we queue the node and put it in the map in case it is asked for again:

def findNode(destination:String):SiteGraphNode = {
       var siteGraphNode = nodes.get(destination);
  if(siteGraphNode == null) {
    siteGraphNode = nodeFactory.create(destination, this);
    queue.enqueue(siteGraphNode);
    nodes.put(destination, siteGraphNode);
  }
  siteGraphNode;
}

Ok, let’s change this code to exploit Scalas option. Everything compiles and the final result looks like this:

package com.agical.publisher.content.site
import scala.collection.Map
import scala.collection.mutable.HashMap;
import com.agical.publisher.content.SiteGraphNode;
import com.agical.publisher.content.SiteGraph;
import com.agical.publisher.content.NodeFactory;
import com.agical.publisher.schedule.JobQueue;
import com.agical.publisher.resource.ResourceRepository;
class PublishSiteGraph (resourceRepository:ResourceRepository, nodeFactory:NodeFactory, queue:JobQueue) extends SiteGraph {
    val nodes = new HashMap[String, SiteGraphNode]();
    def findNode(destination:String):SiteGraphNode = {
       nodes.get(destination).getOrElse {
          var newNode = nodeFactory.create(destination, this);
          queue.enqueue(newNode);
          nodes += destination ->  newNode;
         newNode
       }
    }
    def exists (resource:String):Boolean = {
      resourceRepository.exists(resource);
    }
}

Much more compact, this was pretty much a random pick so I might have been lucky. There are probably tons of things that can be done better but for now I’m happy, all I wanted to do was port my code to java. Cool refactorings to scala features will come later. As of now I’m happy just to have touched on Scalas options. I’m excited to continue with part 2, making buildr compile my scala-code.

Until later!

The next part is here.


About these ads

Written by johlrogge

September 1, 2008 at 8:25 pm

Posted in java, learning, scala

Tagged with , ,

6 Responses

Subscribe to comments with RSS.

  1. Thanks for posting this! Very encouraging!

    Mats (also a Scala enthusiast)

    Mats Henricson

    September 16, 2008 at 9:00 pm

  2. Thanks for the encouraging feedback. it makes my efforts a little bit more worth while (this my posts are not interesting only to me). I hope you like the rest of the posts though I’m not too happy about part 4 :/

    johlrogge

    September 16, 2008 at 9:13 pm

  3. awesome read. thanks. this lowers the “bar of fear” significantly. i hope to have enough sparetime soon to dive into scala myself.

    uwe

    November 27, 2008 at 8:41 pm

  4. Comments like that makes the effort worth while. Thanks a lot for the positive feedback!

    johlrogge

    November 27, 2008 at 9:39 pm

  5. May I suggest you also drop all the semi collons?
    and change the import statement to:

    import scala.collection.{Map, mutable.HashMap}
    import com.agical.publisher.content.{SiteGraphNode, SiteGraph}
    import com.agical.publisher.content.NodeFactory
    import com.agical.publisher.schedule.JobQueue
    import com.agical.publisher.resource.ResourceRepository

    Antony Stubbs

    July 26, 2009 at 12:00 am

    • You certainly may :)

      Thats one of the things I was blind to when I wrote this and that I get annoyed when I find now.

      Thanks for pointing that out.

      johlrogge

      July 26, 2009 at 2:08 am


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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: