scalaの2.9で入るらしい新機能試してみた

前に紹介した方法で、scala-2.9.0.r24265-b20110211020037を落として試してみた(`・ω・´)/

なお、ただnightly試しただけなので、2.9のRCとか正式版がでるころには、情報古くなって変わっていることがあるかもしれないので注意(´・ω・`)


まず、repl起動

C:\scala\scala-2.9.0.r24265-b20110211020037\bin>scala
Welcome to Scala version 2.9.0.r24265-b20110211020037 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

とりあえずhelp

scala> :help
All commands can be abbreviated - for example :he instead of :help.

:cp            add an entry (jar or directory) to the classpath
:help          print this help message
:history [arg] show the history (optional arg: lines to show)
:h?            search the history
:implicits     show the implicits in scope (-v to include Predef)
:javap         disassemble a file or class name
:keybindings   show how ctrl-[A-Z] and other keys are bound
:load          load and interpret a Scala file
:power         enable power user mode
:quit          exit the interpreter
:replay        reset execution and replay all previous commands
:sh            fork a shell and run a command
:silent        disable/enable automatic printing of results
  • implicits
  • javap
  • keybindings

っていうのが増えてる(・ω・)
keybindings打ってみる

scala> :keybindings
Reading jline properties for default key bindings.
Accuracy not guaranteed: treat this as a guideline only.

  1 CTRL-A: move to the beginning of the line
  2 CTRL-B: move to the previous character
  3 CTRL-C: toggle overtype mode (frankly, I wasn't sure where to bind this)
  4 CTRL-D: close out the input stream
  5 CTRL-E: move the cursor to the end of the line
  6 CTRL-F: move to the next character
  7 CTRL-G: move to the previous word
  8 CTRL-H: delete the previous character
  9 TAB, CTRL-I: signal that console completion should be attempted
 10 CTRL-J, CTRL-M: newline
 11 CTRL-K: erase the current line
 12 CTRL-L: clear screen
 13 ENTER: newline
 14 CTRL-N: scroll to the next element in the history buffer
 15 CTRL-O: move to the previous word
 16 CTRL-P: scroll to the previous element in the history buffer
 18 CTRL-R: search backwards in history
 19 CTRL-S: Move to the end of the history
 21 CTRL-U: delete all the characters before the cursor position
 22 CTRL-V: paste the contents of the clipboard (useful for Windows terminal)
 23 CTRL-W: delete the word directly before the cursor
 27 CTRL-[: escape - clear the current line.
127 CTRL-?: delete the previous character

ほほぅ
implicitsは?

scala> :implicits
No implicits have been imported other than those in Predef.

まだPredefで定義された物以外なにもないって言われた(´・ω・`)

そういえば、こないだのscala東北で、try catchの部分の仕様変わった(というか拡張された)って言ってたので試してみる

scala> val pf:PartialFunction[Exception,Unit] = {case e:Exception => println( "例外catchしたお(`・ω・´)" ) }
pf: PartialFunction[Exception,Unit] = <function1>

scala> try{
     |   throw new Exception
     | }catch{
     |   pf
     | }
<console>:12: error: type mismatch;
 found   : java.lang.Throwable
 required: Exception
         pf
         ^

なんか、微妙なエラー・・・(´・ω・`)
今度はThrowableでやってみる

scala> val pf:PartialFunction[Throwable,Unit] = {case e:Exception => println( "例外catchしたお(`・ω・´)" ) }
pf: PartialFunction[Throwable,Unit] = <function1>

scala> try{
     |   throw new Exception
     | }catch{
     |   pf
     | }
例外catchしたお(`・ω・´)

おぉぉぉ、成功したっぽい。

こんな感じで、2.9からは、catchの部分にThrowableを引数にとるPartialFunctionを書けるようになるらしいですよ

こんなことも・・・

scala> try 2 catch pf finally println("hoge")
hoge
res6: AnyVal = 2
  • tryとcatchの間
  • catchとfinallyの間
  • finallyの後

の中括弧が全部省略できる。っていうか調べたら、

  • tryとcatchの間
  • finallyの後

の中括弧を省略できるのは、もとからですね(・ω・`)
これで、catchとfinallyの間の中括弧も省略できることによって、ますます難読化でき・・・(違っ


ではなく、括弧が省略出来るっていうのは、
式がひとつの場合に、括弧省略できる
っていう原則を採用してるからですかね?メソッドなんかもそうですが。


caseの部分がPartialFunctionに出来ることについての利点ですが、まぁ例外部分の処理を、直接そこに書くのではなく、PartialFunctionにすることによって色々と柔軟性が増すんじゃないでしょうか?*1


そういえばまえに、自分の中でcaseの使い方を整理してたときに、
例外の部分てPartialFunctionの記述のしかたと、全く同じじゃないか?
と密かに気づいたことがあったのですが、もともと、こんな風PartialFunctionを受け取れるようにする予定があったんですかね?


わざわざ前のエントリで
例外のcaseはたぶんべつだから5種類じゃね?
ってあとから気づいて追記したんですが、この新文法のおかげで、ある意味、例外のcatchの部分には、
PartialFunctionリテラル*2を書いている
のと区別がつかなくなるわけですよね?*3


で、内部実装調べるために、以下のようなソースをコンパイルjadで逆コンパイルしてみた

object Test{

  val pf:PartialFunction[Throwable,String] = {case e:Exception => "例外catchしたお(`・ω・´)" }

  val a = try "scalaちゃん" catch pf 

}
//関係ないところは省略

    private final String liftedTree1$1()
    {
        String exceptionResult1 = null;
        exceptionResult1 = "scala\u3061\u3083\u3093";
        break MISSING_BLOCK_LABEL_41;
        Exception exception;
        exception;
        PartialFunction catchExpr1 = pf();
        if(!catchExpr1.isDefinedAt((Object)exception))
            break MISSING_BLOCK_LABEL_43;
        exceptionResult1 = (String)catchExpr1.apply((Object)exception);
        return exceptionResult1;
        throw exception;
    }

    private final String a = liftedTree1$1();

いや・・・わかんねぇ・・・jadェ・・・
じゃあJava Decompilerで(`・ω・´)つ

  // ERROR //
  private final String liftedTree1$1()
  {
    // Byte code:
    //   0: aconst_null
    //   1: astore_1
    //   2: ldc 29
    //   4: astore_1
    //   5: goto +36 -> 41
    //   8: astore_2
    //   9: aload_0
    //   10: invokevirtual 31	Test$:pf	()Lscala/PartialFunction;
    //   13: astore_3
    //   14: aload_3
    //   15: aload_2
    //   16: checkcast 33	java/lang/Object
    //   19: invokeinterface 39 2 0
    //   24: ifeq +19 -> 43
    //   27: aload_3
    //   28: aload_2
    //   29: checkcast 33	java/lang/Object
    //   32: invokeinterface 45 2 0
    //   37: checkcast 47	java/lang/String
    //   40: astore_1
    //   41: aload_1
    //   42: areturn
    //   43: aload_2
    //   44: athrow
    //
    // Exception table:
    //   from	to	target	type
    //   2	8	8	finally
  }

よけいわかんねぇ・・・

あと、DelayedInitていうの継承すると、コンパイラが特殊処理するようになるとか、他にも色々新機能あるらしいですが、後で気が向いたら試してみます

*1:適当ww誰かいい例をだしてくれ

*2:この言い方が正しいのかどうかは、知らない。というか自分で勝手にこういう言い方してる

*3:Throwableを引数にとるっていう制限はあるが