CLOVER🍀

That was when it all began.

Scala 2.10.0 Modularizing Language Features

Scala 2.10.0で、以下のようなスクリプトを実行するとなんか警告されます。
Features.scala

println(List(1, 2, 3) tail)
println(4 twice)

trait Foo {
  type MyMap[A, B] <: Map[A, B]
}

class IntWrapper(val underlying: Int) {
  def twice: Int = underlying * 2
}

implicit def intToWrapper(i: Int): IntWrapper = new IntWrapper(i)
$ scala Features.scala
warning: there were 4 feature warnings; re-run with -feature for details
one warning found
List(2, 3)
8

「-feature」を付けると詳細が出るよと言っているので、付けてみると

scala -feature Features.scala
Features.scala:12: warning: postfix operator tail should be enabled
by making the implicit value language.postfixOps visible.
This can be achieved by adding the import clause 'import scala.language.postfixOps'
or by setting the compiler option -language:postfixOps.
See the Scala docs for value scala.language.postfixOps for a discussion
why the feature should be explicitly enabled.
println(List(1, 2, 3) tail)
                      ^
Features.scala:13: warning: postfix operator twice should be enabled
by making the implicit value language.postfixOps visible.
println(4 twice)
          ^
Features.scala:16: warning: higher-kinded type should be enabled
by making the implicit value language.higherKinds visible.
This can be achieved by adding the import clause 'import scala.language.higherKinds'
or by setting the compiler option -language:higherKinds.
See the Scala docs for value scala.language.higherKinds for a discussion
why the feature should be explicitly enabled.
  type MyMap[A, B] <: Map[A, B]
       ^
Features.scala:23: warning: implicit conversion method intToWrapper should be enabled
by making the implicit value language.implicitConversions visible.
This can be achieved by adding the import clause 'import scala.language.implicitConversions'
or by setting the compiler option -language:implicitConversions.
See the Scala docs for value scala.language.implicitConversions for a discussion
why the feature should be explicitly enabled.
implicit def intToWrapper(i: Int): IntWrapper = new IntWrapper(i)
             ^
four warnings found
List(2, 3)
8

なんか、盛大に怒られております。

これ、SIP-18 Modularizing Language Featuresというので導入された機能らしいです。
http://docs.scala-lang.org/sips/pending/modularizing-language-features.html

新機能だったり、実験的機能だったり、あんまり使って欲しくない機能を使う時は、明示的に宣言する感じなようで。言語の機能を、モジュール分割してますよってことみたい。

この結果、Scala 2.10以前に書いていたImplicit Conversionとかは盛大に警告されるようになっていると思われます。

とりあえず、先の例で警告が出ないようにするためにはscalaコマンド(コンパイルするなら、scalacコマンド)に以下のようなオプションを指定します。

$ scala -language:postfixOps -language:higherKinds -language:implicitConversions Features.scala

もしくは、ソース中に以下のimport文を加えます。

import scala.language.{postfixOps, higherKinds, implicitConversions}

もちろん、ひとつひとつ指定してもかまいません。

まあ、基本的な書式としては、コンパイルオプションに

-language:[有効にする機能の名前]

と書くか、ソース中に

import scala.language.[有効にする機能の名前]

といったところですね。

少し前に、Type Dynamicのことを書いた時には

import scala.language.dynamics

をインポートしていました。この機能の場合は、これを明示しなければコンパイルが通りません。

全部importするなら、これでもいいんだとか。

import scala.language._

コンパイルオプションの場合は、

-language:_ 

ところで、コンパイル時の警告には

This can be achieved by adding the import clause 'import scala.language.postfixOps'
or by setting the compiler option -language:postfixOps.

と出るので、

import scala.language.postixOps

と書いて欲しそうなのですが、ドキュメントを見ると

import language.experimental.macros
import language.{reflectiveCalls, existentials}

と書いてあります。いったいどっちで指定して欲しいんでしょうか…。自分は、「scala.」から書く方が好みですが。

何が指定できるかは、こちらに書いてある通り
http://www.scala-lang.org/api/current/index.html#scala.languageFeature$

  • dynamics
  • existentials
  • experimental.macros
  • higherKinds
  • implicitConversions
  • postfixOps
  • reflectiveCalls

となります。

また、ソースでimportを書く場合は適用する範囲を絞ることができて、

def printTail(): Unit = {
  import scala.language.postfixOps
  println(List(1, 2, 3) tail)
}

のように普通にimport文を書いたり

def printTail(): Unit = {
  implicit val postfixOps = scala.language.postfixOps
  println(List(1, 2, 3) tail)
}

暗黙のパラメータとして書くこともできるんだとか。

スコープの外でこれらの機能を使用すると、やっぱり警告されたりすることになります。