package object definitions are not in scope - scala

Inside of my package com.example.common I have a package.scala file:
package com.example.common
import scala.concurrent.Future
package object common extends MyPackage {
}
trait MyPackage extends MyFutures {
}
trait MyFutures {
type Funit = Future[Unit]
}
Now inside of this file I thought I can have the above in scope:
com.example.common.email
class EmailService() {
def send(name: String): Funit = {
}
}
But my alias type Funit isn't in scope and I get the error:
no found: type Funit

Your EmailService is not in the package containing your package object.
Your package object is inside com.package.common.common
Also you should name name your package object according to the package:
A package object package object p extends t adds the members of template to the package p. There can be only one package object per package. The standard naming convention is to place the definition above in a file named package.scala that's located in the directory corresponding to package p.
So you should have the following
a file named com/example/common/package.scala
containing package object common
declared inside package com.example
import scala.concurrent.Future
package object common extends MyPackage {
}
trait MyPackage extends MyFutures {
}
trait MyFutures {
type Funit = Future[Unit]
}
// in the same file (you mentioned "Now inside of this file I thought I can have the above in scope:")
package common {
package email {
class EmailService() {
def send(name: String): Funit = ???
}
}
}

This way, since you're already in the common package:
package com.example.common
import scala.concurrent.Future
object `package` extends MyPackage {
}
trait MyPackage extends MyFutures {
}
trait MyFutures {
type Funit = Future[Unit]
}
and to make common._ visible:
package com.example.common
package email
class EmailService() {
def send(name: String): Funit = ???
}

Related

can't get abstract class out of package object in scala

I have a package object with an abstract class in it like this:
package mainPackage
package object subPackage {
abstract class MyBase(val i: Int)
case class DerivedClass(override val i: Int) extends MyBase(i)
}
In another file, I import the package:
import mainPackage.subPackage._
This gives me access to DerivedClass, but for some reason, I can't see the abstract base class. Any idea why? I want to create a List[BaseClass], but it's not letting me.
The following worked for me:
package mainPackage
class Baba {
import mainPackage.subPackage._
new MyBase(1) {
}
val l: List[MyBase] = ???
}

How to check if some T is a case class at compile time in Scala?

I have the following macro:
package macros
import scala.reflect.macros.blackbox.Context
object CompileTimeAssertions {
def mustBeCaseClass[T]: Unit =
macro CompileTimeAssertionsImpl.mustBeCaseClass[T]
}
object CompileTimeAssertionsImpl {
def mustBeCaseClass[T: c.WeakTypeTag](c: Context): c.Expr[Unit] = {
import c.universe._
val symbol = c.weakTypeTag[T].tpe.typeSymbol
if (!symbol.isClass || !symbol.asClass.isCaseClass) {
c.error(c.enclosingPosition, s"${symbol.fullName} must be a case class")
}
reify(Unit)
}
}
It works when generics aren't involved, but fails when they are:
import macros.CompileTimeAssertions._
import org.scalatest.{Matchers, WordSpec}
case class ACaseClass(foo: String, bar: String)
class NotACaseClass(baz: String)
class MacroSpec extends WordSpec with Matchers {
"the mustBeCaseClass macro" should {
"compile when passed a case class" in {
mustBeCaseClass[ACaseClass]
}
"not compile when passed a vanilla class" in {
// mustBeCaseClass[NotACaseClass] // fails to compile as expected.
}
"compile when working with generics" in {
// class CaseClassContainer[T] { mustBeCaseClass[T] } // fails to compile.
// new CaseClassContainer[ACaseClass]
}
}
}
The compiler error is mine:
MacroSpec.CaseClassContainer.T must be a case class
I'd like to find out what T is when the CaseClassContainer is instantiated. Is that even possible? If it is can you provide an example?
Thanks in advance.
Thanks to Eugene and Travis' advice I was able to solve this problem with type classes. Here's the solution:
package macros
import scala.reflect.macros.blackbox.Context
trait IsCaseClass[T]
object IsCaseClass {
implicit def isCaseClass[T]: IsCaseClass[T] =
macro IsCaseClassImpl.isCaseClass[T]
}
object IsCaseClassImpl {
def isCaseClass[T]
(c: Context)
(implicit T: c.WeakTypeTag[T]): c.Expr[IsCaseClass[T]] = {
import c.universe._
val symbol = c.weakTypeTag[T].tpe.typeSymbol
if (!symbol.isClass || !symbol.asClass.isCaseClass) {
c.abort(c.enclosingPosition, s"${symbol.fullName} must be a case class")
} else {
c.Expr[IsCaseClass[T]](q"_root_.macros.IsCaseClassImpl[$T]()")
}
}
}
case class IsCaseClassImpl[T]() extends IsCaseClass[T]
And here is the usage:
import macros.IsCaseClass
import org.scalatest.{Matchers, WordSpec}
case class ACaseClass(foo: String, bar: String)
class NotACaseClass(baz: String)
class CaseClassContainer[T: IsCaseClass]
class MacroSpec extends WordSpec with Matchers {
"the code" should {
"compile" in {
new CaseClassContainer[ACaseClass]
}
"not compile" in {
// new CaseClassContainer[NotACaseClass]
}
}
}
Worth noting the use of abort instead of error. Abort returns Nothing whereas error returns Unit. The latter was fine when the macro wasn't returning anything.
In scala 2.11 and above, it's much simplier now. I've created a small project that does it : https://github.com/samupra/CaseClassChecker

How to create package object which will be available to all the inner packages in scala?

I have package structure like this.
In file A/B/package.scala
package A
package object B {
def foo = "Hello world"
}
In file A/B/xyz.scala
package A.B
object bar {
def baz() {
println(foo())
}
}
This won't throw error. It will work as expected. But if I try to use like:
In file A/B/C/biz.scala
package A.B.C
object biz {
def baz() {
println(foo())
}
}
It will throw error as foo is not in the scope of inner package. I need to have global access to foo(). How can I achieve it?
One way is to import A.B like import A.B._.
But it will import all the classes in A.B package which I don't want to do.
Is there any other way to achieve the same?
The best fit is import A.B.foo (and other specific methods you need). You can also make foo available in a non-package object and import all of its methods. Of course, you can also have them in the package object:
package A.B
abstract class ABMethods { def foo = ... }
package A
package object B extends ABMethods { ... }
package A.B
object Foo extends ABMethods { ... }
But there is no way to have all of package object methods available without all classes of A.B.

Why is this specs2 test using Mockito passing?

Suppose I had this interface and class:
abstract class SomeInterface{
def doSomething : Unit
}
class ClassBeingTested(interface : SomeInterface){
def doSomethingWithInterface : Unit = {
Unit
}
}
Note that the doSomethingWithInterface method does not actually do anything with the interface.
I create a test for it like this:
import org.specs2.mutable._
import org.specs2.mock._
import org.mockito.Matchers
import org.specs2.specification.Scope
trait TestEnvironment extends Scope with Mockito{
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
class ClassBeingTestedSpec extends Specification{
"The ClassBeingTested" should {
"#doSomethingWithInterface" in {
"calls the doSomething method of the given interface" in new TestEnvironment {
test.doSomethingWithInterface
there was one(interface).doSomething
}
}
}
}
This test passes. Why? Am I setting it up wrong?
When I get rid of the scope:
class ClassBeingTestedSpec extends Specification with Mockito{
"The ClassBeingTested" should {
"#doSomethingWithInterface" in {
"calls the doSomething method of the given interface" in {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
test.doSomethingWithInterface
there was one(interface).doSomething
}
}
}
}
The test fails as expected:
[info] x calls the doSomething method of the given interface
[error] The mock was not called as expected:
[error] Wanted but not invoked:
[error] someInterface.doSomething();
What is the difference between these two tests? Why does the first one pass when it should fail? Is this not an intended use of Scopes?
When you mix-in the Mockito trait to another trait you can create expectations like there was one(interface).doSomething. If such an expression fails it only returns a Result, it doesn't throw an Exception. It then gets lost in a Scope because it is just a "pure" value inside the body of a trait.
However if you mix-in the Mockito trait to a mutable.Specification then an exception will be thrown on a failure. This is because the mutable.Specification class specifies that there should be ThrownExpectations by mixing in that trait.
So if you want to create a trait extending both Scope you can either:
create the trait from inside the specification and not have it extend Mockito:
class MySpec extends mutable.Specification with Mockito {
trait TestEnvironment extends Scope {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
...
}
create trait and specification as you do, but mix-in org.specs2.execute.ThrownExpectations
trait TestEnvironment extends Scope with Mockito with ThrownExpectations {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
class MySpec extends mutable.Specification with Mockito {
...
}

Scala importing a file in all files of a package

I need to use an implicit ordering that has been defined in an object in a file
abc
in the following way:
object abc{
implicit def localTimeOrdering: Ordering[LocalDate] = Ordering.fromLessThan(_.isBefore(_))
}
So, I make a package object
xyz
inside a file 'package.scala' that in turn is in the package 'xyz' that has files in which I need the implicit ordering to be applicable. I write something like this:
package object xyz{
import abc._
}
It does not seem to work. If I manually write the implicit definition statement inside the package object, it works perfectly. What is the correct way to import the object (abc) such that all of its objects/classes/definitions can be used in my entire package 'xyz' ?
You cannot import the implicit conversions in that way, you will have to:
Manually write them inside the object:
package obj {
implicit def etc//
}
Or obtain them via inheritance/mixins:
package obj extends SomeClassOrTraitWithImplicits with AnotherTraitWithImplicits {
}
For this reason, you usually define your implicit conversions in traits or class definitions, that way you can do bulk import with a single package object.
The usual pattern is to define a helper trait for each case.
trait SomeClass {
// all the implicits here
}
object SomeClass extends SomeClass {}
Doing this would allow you to:
package object abc extends SomeClass with SomeOtherClass with AThirdClass {
// all implicits are now available in scope.
}