user2697852
user2697852

Reputation:

Scala companion object with abstract class

I'm reading the book Programming in Scala (second edition) by Martin Odersky and I have a problem with the examples in Chapter 10.

This is my file almost at the end of the chapter:

class Element
object Element {

  private class ArrayElement(
    val contents: Array[String]
  ) extends Element

  private class LineElement(s: String) extends ArrayElement(Array(s)) {
    override def width = s.length
    override def height = 1
  }

  private class UniformElement(
    ch: Char,
    override val width: Int,
    override val height: Int
  ) extends Element {
    private val line = ch.toString * width
    def contents = Array.fill(height)(line)
  }

  def elem(contents: Array[String]): Element =
    new ArrayElement(contents)

  def elem(chr: Char, width: Int, height: Int): Element =
    new UniformElement(chr, width, height)

  def elem(line: String): Element = 
    new LineElement(line)

}

abstract class Element {
  def contents: Array[String]

  def width: Int = 
    if (height == 0) 0 else contents(0).length

  def height: Int = contents.length

  def above(that: Element): Element =
    elem(this.contents ++ that.contents)

  def beside(that: Element): Element =
    elem(
      for (
        (line1, line2) <- this.contents zip that.contents
      ) yield line1 + line2
    )
}

The compiler says this:

defined class Element
<console>:15: error: method width overrides nothing
           override def width = s.length
                        ^
<console>:16: error: method height overrides nothing
           override def height = 1
                        ^
<console>:21: error: value width overrides nothing
           override val width: Int,
                        ^
<console>:22: error: value height overrides nothing
           override val height: Int
                        ^
<console>:17: error: not found: value elem
           elem(this.contents ++ that.contents)
           ^
<console>:20: error: not found: value elem
           elem(
           ^

If I remove the class Element from the beginning then it complains that the Element type is not found when I try to subclass it.

I found a couple topics here that are already discussing this chapter from the book but I couldn't use any of the proposed solutions there.

What did I miss?

Regards, Norbert

Upvotes: 1

Views: 4959

Answers (2)

Anon
Anon

Reputation: 1

There is a companion object and a companion class for Element, and I thought they could access each other's members without import. However, it seems that the companion can only access members protected by private, and does not do name resolution. So you may have to add import beforehand in order to access the Element object's elem with only elem.

Upvotes: 0

Shadowlands
Shadowlands

Reputation: 15074

First, you declare class Element twice - remove the first line, it is only confusing things (this doesn't cause any errors for me - if it does for you, can you show us some more info on the error?). That should fix the override errors. Second, method elem from the companion object isn't automatically visible in the class. Either prefix it with Element wherever it is used or - better - add an import line at the start of the class:

object Element {
  ...
}

abstract class Element {
  import Element._
  ...
}

EDIT: Ah, I might have an idea why you get an error when you leave off the first line. If you are trying this in the REPL and entering it one line (or one declaration) at a time, then you might hit this issue because the REPL doesn't like the forward referencing required. Try pasting all the code in at once (using ":paste" in the REPL).

Upvotes: 6

Related Questions