Scalaでdottyを試してみた

次世代のScalaコンパイラ dottyを試してみました。
Scalaは素人なので、ツッコミどころや正しい情報ご存知の方いらっしゃいましたら教えて戴けると嬉しいです。

クイックスタート

インストール

Windowsを使っているためsbt経由でインストールしました。
githubからcloneしてビルドしたものはWindowsに対応していなそうな雰囲気だったので..

sbtは 公式サイト から 0.13.15.MSI をインストールしました。

プロジェクト作成

適当なディレクトリ作成してから sample-project をベースに作成します。

$ sbt new lampepfl/dotty.g8

ディレクトリ名は dotty-study にして、バージョンは 0.1.0-RC4 でした。

dotty-study
│  build.sbt
│  LICENSE
│  README.md
│
├─project
│      build.properties
│      plugins.sbt
│
└─src
    ├─main
    │  └─scala
    │          Main.scala
    │
    └─test
        └─scala
                Test1.scala

また dotty-study と同じ階層に以下のようなディレクトリも作成されていました。

target
└─streams
    └─$global
        ├─ivyConfiguration
        │  └─$global
        │      └─streams
        │              out
        │
        └─projectDescriptors
            └─$global
                └─streams
                        out

target ディレクトリの役割がよく分かりませんでした。
プロジェクトに依存するファイル群ならdotty-studyの下にできそうなので、グローバルのライブラリ依存関係が記録されていたりするのでしょうか…

コンパイル

sbtでコンパイルします。

$ cd dotty-study
$ sbt compile

完了すると以下のような構成になりました。

dotty-study
│  build.sbt
│  LICENSE
│  README.md
│
├─project
│  │  build.properties
│  │  plugins.sbt
│  │
│  ├─project
│  │  └─target
│  │      └─config-classes
│  │              $a189acdf69166717de30$.class
│  │              $a189acdf69166717de30.cache
│  │              $a189acdf69166717de30.class
│  │
│  └─target
│      ├─config-classes
│      │      $c28c73ec60ca10e9997f$$anonfun$root$1.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$10.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$2.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$3.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$4.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$5.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$6.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$7.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$8.class
│      │      $c28c73ec60ca10e9997f$$anonfun$root$9.class
│      │      $c28c73ec60ca10e9997f$.class
│      │      $c28c73ec60ca10e9997f.cache
│      │      $c28c73ec60ca10e9997f.class
│      │
│      ├─resolution-cache
│      │  ├─default
│      │  │  └─dotty-study-build
│      │  │      └─scala_2.10
│      │  │          └─sbt_0.13
│      │  │              └─0.1-SNAPSHOT
│      │  │                      resolved.xml.properties
│      │  │                      resolved.xml.xml
│      │  │
│      │  └─reports
│      │          default-dotty-study-build-compile-internal.xml
│      │          default-dotty-study-build-compile.xml
│      │          default-dotty-study-build-docs.xml
│      │          default-dotty-study-build-optional.xml
│      │          default-dotty-study-build-plugin.xml
│      │          default-dotty-study-build-pom.xml
│      │          default-dotty-study-build-provided.xml
│      │          default-dotty-study-build-runtime-internal.xml
│      │          default-dotty-study-build-runtime.xml
│      │          default-dotty-study-build-scala-tool.xml
│      │          default-dotty-study-build-sources.xml
│      │          default-dotty-study-build-test-internal.xml
│      │          default-dotty-study-build-test.xml
│      │          ivy-report.css
│      │          ivy-report.xsl
│      │
│      ├─scala-2.10
│      │  └─sbt-0.13
│      └─streams
│          ├─$global
│          │  ├─$global
│          │  │  └─$global
│          │  │      └─streams
│          │  │              out
│          │  │
│          │  ├─dependencyPositions
│          │  │  └─$global
│          │  │      └─streams
│          │  │          └─update_cache_2.10
│          │  │                  input_dsp
│          │  │                  output_dsp
│          │  │
│          │  ├─ivyConfiguration
│          │  │  └─$global
│          │  │      └─streams
│          │  │              out
│          │  │
│          │  ├─ivySbt
│          │  │  └─$global
│          │  │      └─streams
│          │  │              out
│          │  │
│          │  ├─projectDescriptors
│          │  │  └─$global
│          │  │      └─streams
│          │  │              out
│          │  │
│          │  ├─update
│          │  │  └─$global
│          │  │      └─streams
│          │  │          │  out
│          │  │          │
│          │  │          └─update_cache_2.10
│          │  │                  inputs
│          │  │                  output
│          │  │
│          │  └─updateSbtClassifiers
│          │      └─$global
│          │          └─streams
│          │                  out
│          │
│          ├─compile
│          │  ├─$global
│          │  │  └─$global
│          │  │      └─discoveredMainClasses
│          │  │              data
│          │  │
│          │  ├─compile
│          │  │  └─$global
│          │  │      └─streams
│          │  │              out
│          │  │
│          │  ├─compileIncremental
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │              out
│          │  │
│          │  ├─copyResources
│          │  │  └─$global
│          │  │      └─streams
│          │  │              copy-resources
│          │  │              out
│          │  │
│          │  ├─dependencyClasspath
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │
│          │  ├─exportedProducts
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │
│          │  ├─externalDependencyClasspath
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │
│          │  ├─incCompileSetup
│          │  │  └─$global
│          │  │      └─streams
│          │  ├─internalDependencyClasspath
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │
│          │  ├─managedClasspath
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │
│          │  ├─unmanagedClasspath
│          │  │  └─$global
│          │  │      └─streams
│          │  │              export
│          │  │
│          │  └─unmanagedJars
│          │      └─$global
│          │          └─streams
│          │                  export
│          │
│          └─runtime
│              ├─dependencyClasspath
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              ├─exportedProducts
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              ├─externalDependencyClasspath
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              ├─fullClasspath
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              ├─internalDependencyClasspath
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              ├─managedClasspath
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              ├─unmanagedClasspath
│              │  └─$global
│              │      └─streams
│              │              export
│              │
│              └─unmanagedJars
│                  └─$global
│                      └─streams
│                              export
│
├─src
│  ├─main
│  │  └─scala
│  │          Main.scala
│  │
│  └─test
│      └─scala
│              Test1.scala
│
└─target
    ├─resolution-cache
    │  ├─dotty-cross-template
    │  │  └─dotty-cross-template_0.1
    │  │      └─0.1
    │  │              resolved.xml.properties
    │  │              resolved.xml.xml
    │  │
    │  └─reports
    │          dotty-cross-template-dotty-cross-template_0.1-compile-internal.xml
    │          dotty-cross-template-dotty-cross-template_0.1-compile.xml
    │          dotty-cross-template-dotty-cross-template_0.1-docs.xml
    │          dotty-cross-template-dotty-cross-template_0.1-optional.xml
    │          dotty-cross-template-dotty-cross-template_0.1-plugin.xml
    │          dotty-cross-template-dotty-cross-template_0.1-pom.xml
    │          dotty-cross-template-dotty-cross-template_0.1-provided.xml
    │          dotty-cross-template-dotty-cross-template_0.1-runtime-internal.xml
    │          dotty-cross-template-dotty-cross-template_0.1-runtime.xml
    │          dotty-cross-template-dotty-cross-template_0.1-scala-tool.xml
    │          dotty-cross-template-dotty-cross-template_0.1-sources.xml
    │          dotty-cross-template-dotty-cross-template_0.1-test-internal.xml
    │          dotty-cross-template-dotty-cross-template_0.1-test.xml
    │          ivy-report.css
    │          ivy-report.xsl
    │
    ├─scala-0.1
    │  └─classes
    │          Main$.class
    │          Main.class
    │
    └─streams
        ├─$global
        │  ├─$global
        │  │  └─$global
        │  │      └─streams
        │  │              out
        │  │
        │  ├─dependencyPositions
        │  │  └─$global
        │  │      └─streams
        │  │          └─update_cache_0.1
        │  │                  input_dsp
        │  │                  output_dsp
        │  │
        │  ├─ivyConfiguration
        │  │  └─$global
        │  │      └─streams
        │  │              out
        │  │
        │  ├─ivySbt
        │  │  └─$global
        │  │      └─streams
        │  │              out
        │  │
        │  ├─projectDescriptors
        │  │  └─$global
        │  │      └─streams
        │  │              out
        │  │
        │  ├─update
        │  │  └─$global
        │  │      └─streams
        │  │          │  out
        │  │          │
        │  │          └─update_cache_0.1
        │  │                  inputs
        │  │                  output
        │  │
        │  └─updateSbtClassifiers
        │      └─$global
        │          └─streams
        │                  out
        │
        └─compile
            ├─$global
            │  └─$global
            │      └─discoveredMainClasses
            │              data
            │
            ├─compile
            │  └─$global
            │      └─streams
            │              out
            │
            ├─compileIncremental
            │  └─$global
            │      └─streams
            │              export
            │              out
            │
            ├─dependencyClasspath
            │  └─$global
            │      └─streams
            │              export
            │
            ├─externalDependencyClasspath
            │  └─$global
            │      └─streams
            │              export
            │
            ├─incCompileSetup
            │  └─$global
            │      └─streams
            │              inc_compile_0.1
            │
            ├─internalDependencyClasspath
            │  └─$global
            │      └─streams
            │              export
            │
            ├─managedClasspath
            │  └─$global
            │      └─streams
            │              export
            │
            ├─unmanagedClasspath
            │  └─$global
            │      └─streams
            │              export
            │
            └─unmanagedJars
                └─$global
                    └─streams
                            export

targetが三箇所に出現して、もう意味が分からなくなってきました…
なんでScalaのディレクトリ構成ってこんな複雑なんでしょうか…

実行

sbtで実行します。

$ sbt run

コンパイルに成功すると以下の様になります。

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[warn] Executing in batch mode.
[warn]   For better performance, hit [ENTER] to switch to interactive mode, or
[warn]   consider launching sbt without any commands, or explicitly passing 'shell'
[info] Loading project definition from C:\Users\syoum\tmp\dotty-study\project
[info] Set current project to dotty-cross-template (in build file:/C:/Users/syoum/tmp/dotty-study/)
[info] Running Main
Hello world!
I was compiled by dotty :)
[success] Total time: 1 s, completed 2017/05/20 18:33:49

sbt run ではcompileも実施されますので sbt compile を実行する必要はありません。

コードを変更してみる

src/main/scala/Mani.scala をいじります。
元々、以下の記事で説明されている Enrich my library を実践してみたかったのでそれを試します。

Scalaでimplicits呼ぶなキャンペーン – kmizuの日記

ファイルに変更があったらコンパイル

コードを変更したらすぐにリコンパイル & 実行できるよう、sbtコマンドの実行をし直します。
\~ がポイント。

$ sbt ~run

ソースコードを変更します。

object Main {
  implicit class RichInt(self: Int) {
    def times(func: => Unit): Unit = (1 to self).foreach(x => func)
  }

  def main(args: Array[String]): Unit = {
    3.times {
      println("Yes! you can!")
    }
  }
}

ファイルを保存すると以下が出力されます。

[success] Total time: 1 s, completed 2017/05/20 20:10:37
24. Waiting for source changes... (press enter to interrupt)
[info] Running Main
Yes! you can!
Yes! you can!
Yes! you can!

しかし、dottyのコンパイルエラーメッセージは親切すぎますね…
最初、foreachに直接 func を指定しようとした時のエラーです。

[info] Compiling 1 Scala source to C:\Users\syoum\tmp\dotty-study\target\scala-0.1\classes...
[error] -- [E007] Type Mismatch Error: C:\Users\syoum\tmp\dotty-study\src\main\scala\Main.scala:3:57
[error] 3 |    def times(func: => Unit): Unit = (0 to self).foreach(func)
[error]   |                                                         ^^^^
[error]   |                                                      found:    Unit
[error]   |                                                      required: Int => Any
[error]   |
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 0 s, completed 2017/05/20 20:03:33

関数型っぽいコードを書きつつdottyのエラーを眺める

せっかくなので、もう1つコードを書いてみました。

object Main {

  def main(args: Array[String]): Unit = {
    val numbers: Seq[Int] = Seq(1, 5, 10, 30, 50, 100)
    val result = numbers.map(_*2).filter(_ < 50).mkString(" ----> ")
    println(result)
  }

}

コーディング中に表示されたdottyのエラーです。
相変わらず親切です。

[info] Compiling 1 Scala source to C:\Users\syoum\tmp\dotty-study\target\scala-0.1\classes...
[error] -- [E017] Syntax Error: C:\Users\syoum\tmp\dotty-study\src\main\scala\Main.scala:4:28
[error] 4 |    def numbers: Seq[Int] = [1, 5, 10, 30, 50, 100]
[error]   |                            ^
[error]   |                            illegal start of simple expression
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 0 s, completed 2017/05/21 0:56:00

ついPythonやTypeScriptのクセが…

[info] Compiling 1 Scala source to C:\Users\syoum\tmp\dotty-study\target\scala-0.1\classes...
[error] -- Error: C:\Users\syoum\tmp\dotty-study\src\main\scala\Main.scala:5:63 --------
[error] 5 |    val result = numbers.map(_*2).filter(_ < 50).mkString('----')
[error]   |                                                               ^
[error]   |                                                unclosed character literal
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 0 s, completed 2017/05/21 0:57:19

これもPythonやTypeScriptのクセですね…

IntelliJ IDEAで動かす

以下は `Scala Plugin` がインストールされている前提の話になります。

やっぱりIDEを使いたいので、公式ドキュメントを参考にチャレンジしてみました。

Getting Started

Application から実行する

色々やってみたのですが、上手くいきませんでした..。
諦めて、先ほど作ったプロジェクトをOpenする作戦に切り替えました。

何も考えずに実施するとsacalacのエラーが出ます。

Error:scalac: Multiple 'scala-library*.jar' files (scala-library-0.1.1-bin-20170502-df22149-NIGHTLY.jar, scala-library-2.11.11.jar) in Scala compiler classpath in Scala SDK SBT: ch.epfl.lamp:dotty-library_0.1:0.1.1-bin-20170502-df22149-NIGHTLY:jar

今回のプロジェクトはsbt経由でコマンドを実行するため、以下にチェックを付ける必要があります。
デフォルトでは付いていませんので、Project Openの時にチェックしましょう。 (後でも可)

Runをすれば成功すると思います。

SBT Task から実行する

SBT Task で明示的にタスクを指定すれば、先ほどの設定変更は不要dす。

Tasksに ~run と設定すれば、先ほどのようにソースコード変更を監視できます。
実行の必要がなければ ~compile ですね。

総括

dottyを使ってScalaのプロジェクトを作成し、コマンドプロンプトとIntelliJ IDEAでコードを書いてみました。

IntelliJ IDEAでエディタ上にコンパイルエラーが表示されなかったのが心残りですが、sbt経由以外でdottyをインストールしなければいけないのかもしれません。
Windowsのせいか分かりませんが、今はできそうにないので正式版の対応を待ちたいと思います。

コメントを残す