Monday, February 1, 2010

Temporary variables during object instantiation

In Java a common pattern with class constructors is to assign field values and often there are several intermediate values used for the calculation. If the code is ported to Scala the resulting class will have the intermediate values as fields, which take up space in the object. However the issue is easily worked around. Lets look at a couple examples.

Example 1: Assigning a single field
  1. //  Java
  2. import java.io.File
  3. /** 
  4. No real logic behind class.  But for some reason it needs the path of a tmp directory in the working directory
  5. */
  6. class OneAssignment {
  7.   final String field;
  8.   public OneAssignment() {
  9.     File file = new File("tmp");
  10.     if(!file.exists()) {
  11.       file.mkdirs();
  12.     }
  13.     field = file.getAbsolutePath();
  14.   }
  15. }

In Scala the naive way to port this would be:
  1. //  Scala
  2. import java.io.File
  3. class OneAssignment {
  4.   val file = new File("tmp")
  5.   if(!file.exists()) {
  6.     file.mkdirs()
  7.   }
  8.   val field = file.getAbsolutePath()
  9. }

Problem is that it has an extra field "file" now. The correct way to port this would be as follows:
  1. //  Scala
  2. import java.io.File
  3. class OneAssignment {
  4. /* 
  5. notice that assignment is in a block so file is only visible within the block
  6. */
  7.   val field = {
  8.     val file = new File("tmp")
  9.     if(!file.exists()) {
  10.       file.mkdirs()
  11.     }
  12.     file.getAbsolutePath()
  13.   }
  14. }


Example 2: Assigning multiple fields
  1. //  Java
  2. import java.io.File
  3. /** 
  4. Basically the same as last example but multiple fields are assigned
  5. Notice that 2 fields depend on the temporary file variable but count does not
  6. */
  7. class MultipleAssignments {
  8.   final String tmp,mvn_repo;
  9.   find int count;
  10.   public OneAssignment() {
  11.     File file = new File("tmp");
  12.     if(!file.exists()) {
  13.       file.mkdirs();
  14.     }
  15.     tmp = file.getAbsolutePath();
  16.     count = file.listFiles.length;
  17.     
  18.     File home = new File(System.getProperty("user.home"));
  19.     mvn_repo = new File(home, ".m2").getPath();
  20.   }
  21. }

The Scala port:
  1. //  Scala
  2. import java.io.File
  3. class MultipleAssignments {
  4. /*
  5. When multiple fields depend on the same temporary variables the fields can be assigned together from one block by returning a tuple and using Scala's matching to expand the tuple during assignment.  See previous topics on assignment for details 
  6. */
  7.   val (tmp,count) = {
  8.     val file = new File("tmp");
  9.     if(!file.exists()) {
  10.       file.mkdirs();
  11.     }
  12.     val tmp = file.getAbsolutePath();
  13.     val count = file.listFiles.length;
  14.     (tmp, count)
  15.   }
  16.   val mvn_repo = {
  17.     val home = new File(System.getProperty("user.home"));
  18.     new File(home, ".m2").getPath();
  19.   }
  20. }

In some ways the Scala port is cleaner in that it splits the constructor up and decouples the dependencies between fields.

6 comments:

  1. So, when will the Daily Scala book be out? :-)

    ReplyDelete
  2. now don't be giving anyone idea ;-)

    ReplyDelete
  3. In the first Scala example, is there some reason you used 'def file = new File("tmp")' instead of 'val file = ...'?

    ReplyDelete
  4. That is a mistake. It should be val

    ReplyDelete
  5. ok post updated to fix def file=

    ReplyDelete
  6. Book? I'd buy one :-)

    Cheers
    Stephan
    http://codemonkeyism.com

    ReplyDelete