本当に Scala は Java の半分のコーディング量で済むのか?
「Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)」(通称コップ本)の帯の背表紙のところに「コード量はJavaの半分以下」と書いてあります。
マジで?
ということで、実験。
実験方法
みんな大好き Cubby の雛形プロジェクトを Maven の cubby-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%減 |
ところが、この結果には裏があって
- Java のほうは public フィールドを使うことによって getter / setter 分のコードを削減している
- Cubby は Java 用のフレームワークなので Java Beans の流儀に合わせるために Scala 側ではフィールドに scala.reflect.BeanProperty アノテーションをつけなければならない。
まぁ、@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!" }