本当に Scala は Java の半分のコーディング量で済むのか?

 「Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)」(通称コップ本)の帯の背表紙のところに「コードJava分以下」と書いてあります。


 マジで?


 ということで、実験。

実験方法

 みんな大好き Cubby の雛形プロジェクトを Mavencubby-s2-archetype で生成させたものを Scala で実装しなおします。↓これで生成させた奴です。

mvn archetype:generate -DarchetypeCatalog=http://cubby.seasar.org 

 看板コメント分を差し引いたコードのバイト数で比較します。インデントは Tab でやります。Scala 特有の構文に寄らない改行はできるだけもとの Java ソースと同じようになるようにします。

結果

 結論から言うと Scala で書いた方がコード量は少なくなりますが、半分にはなりません。↓実際のバイト数

Java Scala 削減率
HelloAction 1,345 1,120 17%減
IndexAction 329 198 40%減
HelloService 124 91 26%減

 ところが、この結果には裏があって

 まぁ、@BeanProperty に関しては受け入れなければならないでしょう。でも、getter / setter 省略はずるい! ということで、HelloAction.java には getter / setter をつける余地があったので、つけたもので比較してみました。これでクラスとしての機能はほぼ同じのはず!

Java Scala 削減率
HelloAction 1,987 1,120 44%減
IndexAction 329 198 40%減
HelloService 124 91 26%減

 やっぱり半分にまでは行かなかったですけど、かなり削減できましたね! Scala のことなんて考慮していない(と思われる)Javaフレームワークを使うにしてもこのパワーです! Scala いいよ、Scala

 ↓最後に今回の Scala 化したソースです。


HelloAction.scala

package org.seasar.cubby.hello.action

import scala.reflect.BeanProperty

import org.seasar.cubby.action.{ActionClass, ActionContext, ActionResult, Forward, Redirect, RequestParameter, Validation}
import org.seasar.cubby.validator.{DefaultValidationRules, ValidationRules}
import org.seasar.cubby.validator.validators.RequiredValidator

import org.seasar.cubby.hello.service.HelloService

@ActionClass
class HelloAction {

  @BeanProperty
  val validation = new DefaultValidationRules {
    override def initialize = {
      add("name", new RequiredValidator)
    }
  }

  @BeanProperty
  var actionContext: ActionContext = _

  @BeanProperty
  var helloService: HelloService = _

  @RequestParameter
  @BeanProperty
  var name: String = _

  @BeanProperty
  var mezzage: String = _

  def index = new Forward("index.jsp")

  @Validation { val rules = "validation", val errorPage = "index.jsp" }
  def message = {
    this.mezzage = this.name + " " + helloService.getMessage
    new Forward("hello.jsp")
  }

  def back = {
    actionContext.getFlashMap.put(
      "notice", "Redirect OK!(this message is flash message)")
    new Redirect("/hello/")
  }

}

IndexAction.scala

package org.seasar.cubby.hello.action

import org.seasar.cubby.action.{ActionClass, ActionResult, Forward, Path}

@ActionClass
@Path("/")
class IndexAction {

  def index = new Forward("index.jsp")
}

HelloService.scala

package org.seasar.cubby.hello.service

class HelloService {

  def getMessage = "Hello!"

}