What are nested/unnested packages in Scala 2.8?
Asked Answered
G

3

23

In Scala 2.7, I could write:

package com.acme.bar

class Bar

.

package com.acme.foo

class Foo {
  new bar.Bar
}

This doesn't compile in Scala 2.8 -- however this does:

package com.acme 
package bar

class Bar

.

package com.acme
package foo

class Foo {
  new bar.Bar
}
  1. What was the motivation for this?
  2. What is the precise meaning, with regards to scope and visibility?
  3. When should I use one form over the other?
Godden answered 13/5, 2010 at 20:55 Comment(0)
I
20

There were several long discussions on the mailing lists about this. See this thread for the problem and this thread for the solution.

As to meaning, only the

package A
package B

form will open a scope for A, which makes members of A visible without prefix. You'd typically use this form if your project consists of several subpackages which refer to each other. On the other hand, you'd use the form

package A.B.C

If you want to integrate C into the package hierarchy and do not intend to access other members of A or B directly. A typical case is

package net.myorg.myproject

Here, you do not want to be vulnerable to the possibility than somebody else has defined a net.java package that would shadow the root level java. In Scala 2.7 you'd prevent that by using _root_ imports. But that's ugly, and to be safe you'd have to do this almost everywhere. So the present solution is much better, IMO.

Inchoative answered 14/5, 2010 at 8:29 Comment(1)
Martin just published a more detailed description, part of the 'What's new in Scala 2.8' series: scala-lang.org/docu/files/package-clauses/packageclauses.html#Godden
G
13

Thanks for the answers so far! Let me add two small points, and we're done!

Visibility

The difference between nested and unnested packages only applies to scoping. Visibility is always based on nested packages.

package A

private[A] trait Secret

This works:

package A
package B

trait AB extends Secret

So does this:

package A.B

trait AB extends A.Secret

In both cases, the structure is interpreted as:

package A {
  trait Secret
  package B {
     //...
  }
}

Scoping

Compare this with scoping, in which you could imagine this interpretation for unnested packages:

package A {
  private [A] trait Secret
}

package `A.B` {
   trait AB extends A.Secret

}

Mix and Match

You can arbitrarily mix and match nested and unnested package:

package com.acme.project
package util.shazam
package blerg
Godden answered 14/5, 2010 at 13:35 Comment(0)
O
9

Doesn't it give you more control over what is being imported? For example, if there were packages:

package com.acme.foo.client
package com.acme.client

And then from within Foo, wasn't there an annoying ambiguity about which client was being referred to? For example, if you want to do a wildcard import from within Foo:

class Foo {
  import client._ //what is being imported?
}

This might be much more problematic if, instead of client, we had a package com.acme.java:

class Foo {
    val jul = new java.util.LinkedList //compile error; cannot find util
}
Oar answered 13/5, 2010 at 21:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.