Darth_Tato
Darth_Tato

Reputation: 1043

how to inherit a protected/private of an abstract class in Scala

I've got an abstract class with an object and a concrete subclass representing a binary tree for sorting a group of strings lexicographically.

abstract class StringSet {
  def incl(x:String):StringSet
  def contains(x:String):Boolean
  def union(that:StringSet):StringSet

  def biggest:String // this is my new method
  def bigIter(acc:String):String //this is my new helper method
}
object Empty extends StringSet {
  override def toString: String = "."
  def incl(x: String): StringSet = new NonEmpty(x, Empty, Empty)
  def contains(x: String): Boolean = false
  def union(that:StringSet):StringSet = that

  def biggest:String = throw new java.util.NoSuchElementException("...")
  def bigIter(acc:String):String = acc
}
class NonEmpty(elem:String, left:StringSet, right:StringSet) extends StringSet {
  def incl(x: String): StringSet = {
    if (x < elem) new NonEmpty(elem, left incl x, right)
    else if (x > elem) new NonEmpty(elem, left, right incl x)
    else this
  }
  def contains(x: String): Boolean = {
    if (x < elem) left contains x
    else if (x > elem) right contains x
    else true
  }
  def union(that:StringSet):StringSet = ((left union right) union that) incl elem

  def biggest:String =  bigIter(elem)
  def bigIter(acc:String):String = 
    if (elem < acc) left union right bigIter acc
    else left union right bigIter elem
}

I want to implement a method for obtaining the biggest string, using only the already created methods for that class in a "functional way". I used the method "biggest" with no parameters that return a string, that calls another method "bigIter" who recursively call itself until it traverses all the tree.

My idea worked, but I want to hide the bigIter implementation, in order for a user could only see the method "Biggest". I used protected and private for bigIter on the abstract and concrete classes, but it didn't work. I tried using private with bigIter method in the abstract class, but private methods of a superclass cannot be inherited. I tried with protected too, using it with both the superclass and the subclasses, getting the following error

Error:(50, 39) method bigiter in class StringSet cannot be accessed in A$A3.this.StringSet Access to protected method bigiter not permitted because prefix type A$A3.this.StringSet does not conform to class NonEmpty in class A$A3 where the access take place if (elem < acc) left union right bigiter acc ^

Any ideas of how could this be accomplished?

note: 1. calling biggest on Empty should return an error, so that's why I call "bigIter" from the concrete classes.
2. This is for a course I'm doing, so the idea is not to use higher order list functions.

Upvotes: 2

Views: 1282

Answers (1)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

SI-9890 explains why the compiler isn't happy when you try to access a method on a super type in a derived type instance. The specification restricts this:

A protected identifier x may be used as a member name in a selection r.x only if one of the following applies:

  • The access is within the template defining the member, or, if a qualification C is given, inside the package C, or the class C, or its companion module, or
  • r is one of the reserved words this and super, or
  • r's type conforms to a type-instance of the class which contains the access.

The last bullet basically means r, which in your case is StringSet, must be of type NonEmpty.

To get around this, you can place all your implementations of StringSet under the same package and have a protected[package] set on bigIter. For example, assume your package name is foo, you can do:

protected[foo] def bigIter(acc: String): String 

And now it will compile.

Upvotes: 3

Related Questions