简体   繁体   中英

What is the type of a nested object in scala

I am trying to figure out how to create a method that takes a nested object as an argument. For a nested class I can do the following:

scala> class Outer { 
 | class Inner
 | def method(i:Outer#Inner) = { "inner class" }
 | }
defined class Outer

However, if I try something like that with an object instead i get an error:

scala> class Outer { 
 | object Inner
 | def method(i:Outer#Inner) = { "inner object" }
 | }
<console>:11: error: type Inner is not a member of Outer
   def method(i:Outer#Inner) = { "inner object" }

What should the type of the argument to the method be to accomplish this? Also I want to refer to the type of Inner object not generalize the argument to say Any .

Inner is an object, thus it is not a type, and can't be use as a type. the type of Inner is Inner.type . It means, in your example. Unfortunately, each instance of Outer will have it's own Inner object and type Outer#Inner.type can not be used, since it is not stable. A workaround is to use: this.Inner.type .

 def method(i:this.Inner.type) = { "inner object" }

But it means that you can only pass as a parameter the Inner object of the instance on which you call method .

A simple example to illustrate what's going on here (in the REPL):

object A
def foo(a : A) = "Does not compile"
def bar(a : A.type) = "Does compile!"
bar(A) // returns "Does compile!"

As Nicholas says, Inner is not a type, so you can't use it as such.

Trying to understand your motivation, I came up with something like this:

class Outer(i : Int) {
  object Inner {
    def getI : Int = i
  }
  def foo(x : Inner.type) = x.getI
}

This is a bit pointless, since we would just directly reference Inner - after all, there's only one of it:

class Outer(i : Int) {
  object Inner {
    def getI : Int = i
  }
  def foo = Inner.getI
}

I'm guessing that what you want to do is accept an Inner from any instance of Outer. We can check the type of such a thing:

val o = new Outer(1)
:type o.Inner
o.Inner.type

So we might expect to be able to do something like this:

class Outer(i : Int) {
  object Inner {
    def getI : Int = i
  }
  def foo(x : Outer#Inner.type) = x.getI
}

This, however, fails to compile. I'm not sure why. Type aliases to the rescue!

class Outer(i : Int) {
  type Inner = Inner.type
  object Inner {
    def getI : Int = i
  }
  def foo(x : Outer#Inner) = x.getI
}

val a = new Outer(1)
val b = new Outer(2)
a.foo(b.Inner) //returns 2

I'm guessing it's just a restriction of the parser that it's unable to read something of the form A#B.type . You could potentially submit a bug request.

Each Scala object has its own type, and there is exactly one value of that type - the object itself. Therefore, the type of a Scala object is no more useful than the type Unit .

For example, say you have an object A and declare a method or function that takes an A.type parameter:

def foo(arg: A.type) = {}

Since there will always exist exactly one value of type A.type , we lose no generality by instead referencing it directly inside the method foo .

If you find yourself wanting to do this, it's more likely that what you really want to abstract over is a trait or base class of the object:

trait Useful { def usefulness: Int }
object A extends Useful { override val usefulness = 42 }
class Foo {
  def foo(arg: Useful) = arg.usefulness
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM