Scalaの「private object」「protected object」

コメント欄で、「クラスのアクセス修飾子はパッケージに対してのものだよ」と教えていただいたので、さらに突っ込んで色々と実験してみました。
発見したことを並べておきます。

複数のパッケージ宣言を1つのファイルで行える

コメント欄で教えてもらったまんまなのですが、ソースファイルをパッケージごとにフォルダ分けしておかなくてもコンパイルできます。
さらに、1ファイルの中に複数のパッケージ宣言を書けます。複数のパッケージを宣言するときは、パッケージ全体をニョロカッコで囲む必要があります。

package aomori {
  object apple
}
package akita {
  object namahage
}

println( aomori.apple )
println( akita.namahage )

ネストしたパッケージを1ファイルの中に書くときは、ネストして書かないといけない

下のように書くとコンパイルエラーが出ます。

package japan.tokyo {
  object hiyoko
}
package japan.akita {
  object hatahata
}


こう書かないといけない

package japan {
  package tokyo {
    object hiyoko
  }
  package akita {
    object hatahata
  }
}


複数ファイルに分けて書くなら大丈夫

// hiyoko.scala

package japan.tokyo
object hiyoko
// hatahata.scala

package japan.tokyo
object hatahata

「パッケージの一番上」を明示的に表す「_root_」というパッケージがある

下の二行は全く同じ意味。

println( japan.akita.hinaidori )
println( _root_.japan.akita.hinaidori )

private object は、他のパッケージから参照できないオブジェクト

private をつけて宣言したオブジェクトは、同一パッケージからは参照できるけど、他のパッケージからは参照できない。
ただし、パッケージの階層構造で、オブジェクトが宣言されたパッケージの下にぶらさがっているパッケージからは参照できる。

こんな感じ(見づらいなあ…)

// kamakura.scala

package japan.akita
private object kamakura   // japan.akita パッケージの kamakura オブジェクト
// japan_akita_yokote_main.scala

package japan.akita.yokote
object main {   // japan.akita.yokote パッケージの main オブジェクト
  def main(args: Array[String]) {
    println( japan.akita.kamakura ) // 参照できる
  }
}

protected object はよくわかんない

protected object を、宣言されたパッケージの下にぶらさがってるパッケージの中から参照したら、コンパイラがエラーになってしまった。

// kiritanpo.scala

package japan.akita
protected object kiritanpo   // japan.akita パッケージの kiritanpo オブジェクト
// japan_akita_oodate_main.scala

package japan.akita.oodate
object main {   // japan.akita.oodate パッケージの main オブジェクト
  def main(args: Array[String]) {
    println( japan.akita.kiritanpo )
  }
}

秋田県大館市パッケージの中から、秋田県パッケージのプロテクトきりたんぽを参照しようとしたら、コンパイラが大量のエラーを吐いて死んでしまいました。

$ scalac kiritanpo.scala
$ scalac japan_akita_oodate_main.scala
Exception in thread "main" java.util.NoSuchElementException: head of empty list
        at scala.Nil$.head(List.scala:1244)
        at scala.Nil$.head(List.scala:1241)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.accDefBuf(SuperAccessors.scala:44)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.makeAccessor(SuperAccessors.scala:283)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:189)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer$$anonfun$1.apply(SuperAccessors.scala:58)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer$$anonfun$1.apply(SuperAccessors.scala:55)
        at scala.List$.map2(List.scala:287)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transformArgs(SuperAccessors.scala:55)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:207)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$5.apply(Trees.scala:1290)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$5.apply(Trees.scala:1289)
        at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:1405)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:27)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.atOwner(SuperAccessors.scala:224)
        at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:1288)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:46)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:213)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:1381)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:1381)
        at scala.List$.loop$1(List.scala:254)
        at scala.List$.mapConserve(List.scala:271)
        at scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:1381)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer$$anonfun$3.apply(SuperAccessors.scala:112)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer$$anonfun$3.apply(SuperAccessors.scala:112)
        at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:1405)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:27)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.atOwner(SuperAccessors.scala:224)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:112)
        at scala.tools.nsc.ast.Trees$Transformer.transformTemplate(Trees.scala:1383)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$3.apply(Trees.scala:1281)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$3.apply(Trees.scala:1281)
        at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:1405)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:27)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.atOwner(SuperAccessors.scala:224)
        at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:1280)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:46)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:102)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:1399)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:1397)
        at scala.List$.loop$1(List.scala:254)
        at scala.List$.mapConserve(List.scala:271)
        at scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:1397)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1273)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1273)
        at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:1405)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:27)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.atOwner(SuperAccessors.scala:224)
        at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:1272)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:46)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:213)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:1399)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:1397)
        at scala.List$.loop$1(List.scala:254)
        at scala.List$.mapConserve(List.scala:271)
        at scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:1397)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1273)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1273)
        at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:1405)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:27)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.atOwner(SuperAccessors.scala:224)
        at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:1272)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:46)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:213)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:1399)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:1397)
        at scala.List$.loop$1(List.scala:254)
        at scala.List$.mapConserve(List.scala:271)
        at scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:1397)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1273)
        at scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1273)
        at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:1405)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:27)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.atOwner(SuperAccessors.scala:224)
        at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:1272)
        at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:46)
        at scala.tools.nsc.typechecker.SuperAccessors$SuperAccTransformer.transform(SuperAccessors.scala:213)
        at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:1400)
        at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
        at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:247)
        at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:233)
        at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:233)
        at scala.Iterator$class.foreach(Iterator.scala:387)
        at scala.collection.mutable.ListBuffer$$anon$1.foreach(ListBuffer.scala:255)
        at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:233)
        at scala.tools.nsc.Global$Run.compileSources(Global.scala:545)
        at scala.tools.nsc.Global$Run.compile(Global.scala:629)
        at scala.tools.nsc.Main$.process(Main.scala:86)
        at scala.tools.nsc.Main$.main(Main.scala:107)
        at scala.tools.nsc.Main.main(Main.scala)


これは報告した方がいいのかな…