Scala package delcaration - one way causes package objects visible, other makes it not? - scala

In foo/bar/my_package/package.scala:
package foo.bar
package object my_package {
type SomeType = java.lang.String
}
Then, in foo/bar/my_package/my_sub/MyClass.scala
package foo.bar.my_package.my_sub
class MyClass {
var x: SomeType = _
}
This fails to compile; SomeType isn't found. If I change MyClass.scala to
package foo.bar.my_package
package my_sub
class MyClass {
var x: SomeType = _
}
Everything works fine. What is the difference!?!??!
(This is Scala 2.8.1)

Package declarations, like imports, give you access to everything inside them. So when you
package foo.bar.my_package
then you have everything available that you would if you did
import foo.bar.my_package._
Furthermore, declaring a package on a single line means that everything below belongs to that package:
package foo.bar.my_package {
package my_sub {
class MyClass { var x: SomeType = _ }
}
}
(which is equivalent to:
package foo.bar.my_package
package my_sub
class MyClass { var x: SomeType = _ }
)
so you can see how the contents of foo.bar.my_package ought to be in scope in this case. In the other case, you only have the contents of foo.bar.my_package.my_sub available, which does not include SomeType.

It's a visibility question.
package foo.bar.my_package.my_sub
class MyClass {
var x: SomeType = _
}
When you declare x, the following things are visible:
Every member of MyClass
Everything inside foo.bar.my_package.my_sub
Every member of scala.Predef
Everything inside scala
Everything inside java.lang
The type SomeType is not inside any of those.
On the other hand, when you do:
package foo.bar.my_package
package my_sub
class MyClass {
var x: SomeType = _
}
Then the visibility is:
Every member of MyClass
Everything inside foo.bar.my_package.my_sub
Everything inside foo.bar.my_package
Every member of scala.Predef
Everything inside scala
Everything inside java.lang
And SomeType is inside foo.bar.my_package, which is the second line.
A related question is why it works this way. You can get a start here, though there's a question precisely about that. I don't much like the answer to that question, though, as it really doesn't touch the reasons for it. It does link to a page on scala-lang about new features of Scala 2.8, in which Odersky explains the reasons.

Related

Scala: package object v.s. singleton object within a package

I want to group a set of similar functions in a library in scala.
Here are two approaches I have seen elsewhere. I want to understand the
differences between the two.
Singleton object defined in a package
// src/main/scala/com/example/toplevel/functions.scala
package com.example.toplevel
object functions {
def foo: Unit = { ... }
def bar: Unit = { ... }
}
Package object
// src/main/scala/com/example/toplevel/package.scala
package com.example.toplevel
package object functions {
def foo: Unit = { ... }
def bar: Unit = { ... }
}
Comparison
As far as I can tell, the first approach will require explicitly importing
the functions object whenever you want to use its functions. While the package object approach allows anything in the package functions to access those methods without importing them.
Ie, com.example.toplevel.functions.MyClass would have access to com.example.toplevel.functions.foo implicitly.
Is my understanding correct?
If there are no classes defined within com.example.toplevel.functions,
it seems the approaches would be equivalent, is this correct?
Ansered by terminally-chill in a comment:
yes, your understanding is correct. Anything defined in your package
object will be available without having to import. If you use an
object, you will have to import it even within the same package.

Unable to declare functor type that takes zero parameters?

I'm trying to make a type definition for the function type () => Unit, I use this signature quite a bit for cleanup callback functions, and I'd like to give them more meaningful names.
I've tried the following, which I think should be correct syntax, but it doesn't compile:
package myPackage
import stuff
type CleanupCallback = () => Unit
trait myTrait ...
class mObject ...
Why doesn't it compile? And what is the correct syntax?
The compilation error is: expected class or object definition
You can't declare type alias out of class/trait/object scope. But you can declare it in package object as follows:
package object myPackage {
type CleanupCallback = () => Unit
}
It will be visible for all classes in myPackage.
Also you can import it in other classes which belong to other packages:
import myPackage.CleanupCallback
trait MyTrait {
def foo: CleanupCallBack
}
IDEA plugin supports creation of package objects, another version is (suppose you don't have IDEA plugin):
Create file package.scala in your package. The file must contain:
package object packageName { // name must match with package name
// ...
}

What's the scope of a private top-level class with access qualifier set to the same package where the class is defined in Scala?

I have read this article to better understand Scala scoping rules.
Everything seemed clear until I ran into some code on GitHub that was like this:
package x.y.z
private[z] class ExampleClass {
// class body
}
As you can see, we have a private top-level class, and there's an access qualifier to modify the scope of that class, but it's set to the very same package where the class is defined. If the access qualifier was set to an enclosing scope (e.g. package y) I would perfectly get it, but like this I can't understand the difference with simply declaring the class as private:
package x.y.z
private class ExampleClass {
// class body
}
So what is the difference between the two snippets posted above?
NOTE: I don't know if it's of any relevance, but in the same file a companion object for the class was defined and simply declared as private (with no access qualifiers).
In the example you provided both modifiers have the same effect. Difference would be more apparent if you had an enclosing class/object.
Compiles:
package x.y.z
object OuterExampleClass {
private[z] class ExampleClass()
}
object AnotherObject {
val ec = new OuterExampleClass.ExampleClass()
}
Fails to compile:
package x.y.z
object OuterExampleClass {
private class ExampleClass() // no [z] !!!
}
object AnotherObject {
val ec = new OuterExampleClass.ExampleClass() // error
}
with message:
class ExampleClass in object OuterExampleClass cannot be accessed in
object x.y.z.OuterExampleClass

Why is it illegal to put package-level defs/types/implicits at the root-level of a file?

This question has been bugging me ever since I started using Scala. So here's my trail of thought:
Scala doesn't have the requirement, which Java has, that everything has to be in a class—this is a good thing!
Scala has functions, i.e. methods without a class/object
packages are objects, so if you define a class in a package, it'll go into the package object
some things have to be put into package objects explicitly, whereas some things don't—WHY?
I think it's just ugly to have to write:
package foo.bar
object `package` {
type Foo = Bar
def fact(n: Int): Int = ???
}
instead of just
package foo.bar
type Foo = Bar
def fact(n: Int): Int = ???
So: does anybody know when/why was it decided that it's better to require explicit wrapping with (the otherwise implicit) package objects? I'm constantly finding myself annoyed with the extra level of indent and boilerplate introduced by the obscure object package declaration, which is annoying just for the same reason this is annoying in Java:
class MyMath {
public static int fact(int n) { ... }
}

Scala package object constructor

When and how is the Scala Package object constructor called?
I have two classes:
Package.scala
package my;
package object entities {
//Some initialization code in constructor
}
Classy.scala
package my.entities;
case class Classy {
}
I am trying to have the entities constructor to have already been executed by the time an object of Classy is created.
The package object is translated into a normal java class file called package.class IIRC. From then on I assume it behaves like any normal Java class, thus it is loaded and instantiated when it is first referenced. In Scala, that means you need to define some method or val in the package object, then access it from outside. In your case, you may try calling it from the constructor of Classy, or from the code which instantiates Classy.
Update
OK, here is some code I ran to test what I described above:
// package.scala
package some
package object pkg {
println("package created!")
def func() { println("func called") }
}
// C.scala
package some.pkg
class C {
println("created C")
}
// G.scala
package some.pkg
object G {
println("creating G")
func()
println("created G")
}
// PackageTester.scala
package some.pkg
object PackageTester extends App {
val c = new C
val g = G
}
And the output is:
created C
creating G
package created!
func called
created G
Which proves that Scala package objects are created lazily, only when they are actually referenced. And in fact the same is true for "normal" Scala objects, as demonstrated by G above.