In Java, classes are placed in a package with a declaration like package com.acme.foo
and by putting your source files in a subdirectory like com/acme/foo
.
I'm working on a JVM language intended to be more don't repeat yourself in style than Java, so I'm going to use one or other of these mechanisms but not both, and I'm wondering which to use.
How do other JVM languages like Scala and Clojure handle it? Do they require both mechanisms or just one, and if so which one?
As mentioned in the comments to the question Travis Brown is correct, scalac does not place any such constraints or restrictions on the paths or names of files of the source and you can even specify multiple packages in one file if you wish.
However, the bytecode generated by scalac puts the bytecode classes files in the necessary directory structure required by the appropriate classloader.
Here are some examples showing the flexibility (I do not necessarily advocate these styles, just showing the flexibility).
// in packages1.scala file in local directory
package my {
package states {
sealed trait State
case class CheckingOut(shoppingCartId: Long) extends State
case class ConfirmedOrder(orderId: Long) extends State
case class ItemShipped(orderId: Long, itemId: Long, quantity: Int) extends State
}
}
And this...
// in packages2.scala file
package com.foo.bar
sealed trait Scale
case object WebScale extends Scale
case object LolScale extends Scale
case object RoflScale extends Scale
case object WatScale extends Scale
And this style is possible too:
// in packages3.scala file
package foo {
package awesomeness {
class Main extends App {
println("Bananas are awesome")
}
}
}
package foo {
package lameness {
class Main extends App {
println("Congress is pretty lame, honestly")
}
}
}
As well as this...
package foo
package bar
// now we are in package foo.bar for remainder of file unless another package statement is made
Here is the resulting source and compiled bytecode tree:
$ tree
.
├── com
│ └── foo
│ └── bar
│ ├── LolScale$.class
│ ├── LolScale.class
│ ├── RoflScale$.class
│ ├── RoflScale.class
│ ├── Scale.class
│ ├── WatScale$.class
│ ├── WatScale.class
│ ├── WebScale$.class
│ └── WebScale.class
├── foo
│ ├── awesomeness
│ │ ├── Main$delayedInit$body.class
│ │ └── Main.class
│ └── lameness
│ ├── Main$delayedInit$body.class
│ └── Main.class
├── my
│ └── states
│ ├── CheckingOut$.class
│ ├── CheckingOut.class
│ └── State.class
├── packages1.scala
├── packages2.scala
└── packages3.scala
8 directories, 19 files
I am not sure if Clojure supports such flexibility but Clojure convention is to use the Java convention of structuring source code with it's commonly used build tool lein
(see leiningen tutorial here).
The one thing to note, however, is that in both Scala and Clojure there appears to be a departure from the $DOMAIN.$APPLICATION
format that is often used in the Java world (e.g. com.oracle.jdbc...
, org.hibernate.session...
, etc). In Scala you will see the $DOMAIN part of the package name being taken out completely (e.g. scalaz...
, akka.{actor,io, ...}
, etc.).
Also of note is the way you can import from packages in Scala:
foo.bar
package: import foo.bar._
import foo.bar.Baz
import foo.bar.{Baz => FooBarBaz}
import foo.bar.{Baz, Boo, Bla}
Also of note is package private scoping in Scala:
package foo.bar
class Baz{
private[bar] def boo[A](a: A)
private[foo] def bla[A](a: A)
}
Above boo
is private to the foo.bar
package (and subpackages) and bla
is private to foo
and all it's subpackages.
For further details read the Scala language specification and related links: