Have you ever had this duplication of code in java?

public void doQuery(String q) throws SQLException {
       PreparedStatement preparedStatement = null;
       ResultSet resultSet = null;     
       Connection conn = null;
       try {
           conn = getConnection();
           preparedStatement = conn.prepareStatement(q);        
           resultSet = preparedStatement.executeQuery();
           
 
       } finally {
           close(resultSet);
           close(preparedStatement);
           close(conn);           
       }
   }
 
      private static void close(Connection connection) {
       try {
           if (connection != null) {
               connection.close();
           }
       } catch (Exception e) {
          error( e);
       }
   }
 
   private static void close(PreparedStatement ps) {
       try {
           if (ps != null) {
               ps.close();
           }
       } catch (Exception e) {
          error( e);
       }
   }
 
   private static void close(ResultSet rs) {
       try {
           if (rs != null) {
               rs.close();
           }
       } catch (Exception e) {
          error( e);
       }
   }

we have duplicated the close method (using cascading try or not ) because Connection, PreparedStatement and ResultSet does not share the same interface (may be the future AutoCloseable interface).

Next java version will introduce try-with ressource wich. We try to give the same behavior using scala futures.

I- BASIC ENHANCEMENT : ONE CLOSE METHOD

@throws(classOf[SQLException])
def doQuery( q:String)   {
  var  preparedStatement:PreparedStatement = null;
  var resultSet:ResultSet = null;
  var conn:Connection = null;
  try {
    conn = getConnection()
    preparedStatement = conn.prepareStatement(q)
    resultSet = preparedStatement.executeQuery()
  } finally {
    close(resultSet)
    close(preparedStatement)
    close(conn)
    
  }
}
def getConnection():Connection=null
 
def close(x : {def close()}){
  try {
          if (x != null) {
              x.close();
          }
      } catch  {
         case  e:Exception => error(e);
      }
}

Scala is a full object ( Java is not). x : {def close()} means any class that has this method as signature. The best point here is that scala rather than other dynamic language do compilation check, the worst is the performance.

II- GENERIC CLOSE

We can use var args close version :

def close(x : {def close()}*){
  x.foreach (close)    
}

and

close(resultSet)
close(preparedStatement)
close(conn)

will be :

close(resultSet,preparedStatement,conn)

III- OPEN CLASS

What if we need to add close method to theses class even final ones? Let’s open class by creation rich one:

class RichConnection (c:Connection){
  def <>(){
    close(c)
  }
}
class RichPreparedStatement(p :PreparedStatement){
  def <>(){
    close(p)
  }
}
class RichResultSet(r:ResultSet){
  def  <>(){
    close(r)
  }
}

and introduce implicit conversions :

implicit def toRichConnection(c:Connection):RichConnection= new RichConnection(c)
implicit def toRichPreparedStatement(p:PreparedStatement):RichPreparedStatement= new RichPreparedStatement(p)
implicit def toRichResultSet(r:ResultSet):RichResultSet= new RichResultSet (r)

and as the result the call will be :

finally {
      resultSet.<>
      preparedStatement.<>
      conn.<>
    }

IV- USING TYPES

define type :

type AutoCloseable={def close()}

and close definition will be

def close(x : AutoCloseable){
     try {
           if (x != null) {
               x.close();
           }
       } catch  {
          case  e:Exception => error(e);
       }
  }
 def close(x : AutoCloseable*){
   x.foreach (close)    
 }

V-CHAINED TRY-WITH

we introduce a curring tryWith method as

def tryWith[A<%AutoCloseable](ac :A)(f: A=> Unit)
{
  try {
    f
  } finally {
   close(ac)
  }
}

tryWith enable us to use doQuery as :

def doQuery( q:String)   {
   tryWith (getConnection()) { conn =>
     tryWith ( conn.prepareStatement(q)) {ps =>
       tryWith (ps.executeQuery()){rs =>
         }
     }     
  } 
}