8

I contrived a fairly trivial example to illustrate my point as follows:

abstract class AbstractSuperClass {
  protected def someFunction(num: Int): Int
  def addition(another: AbstractSuperClass, num: Int): Int
}

class SubclassSquare extends AbstractSuperClass {
  override protected def someFunction(num: Int): Int = num * num
  override def addition(another: AbstractSuperClass, num: Int): Int =
    someFunction(num) + another.someFunction(num)
}

I received the following error message upon execution of the code. (of course, the main function is properly defined.)

Error:(12, 33) method someFunction in class AbstractSuperClass cannot be accessed in AbstractSuperClass Access to protected method someFunction not permitted because prefix type AbstractSuperClass does not conform to class Subclass where the access takes place someFunction(num) + another.someFunction(num)

The method addition is causing the problem. The code tries to access the protected field of an AbstractSuperClass instance, but from my perspective, it should cause no issue here since the SubclassSquare is a sub-class of AbstractSuperClass.

However, I know there must be something I do not understand here. I would like to know how to change my code to make it compile. Well-appreciated.

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
Jude Gao
  • 183
  • 4
  • It seems you can not access a `protected` field on another instance. However, that seems like a bug to me. – Luis Miguel Mejía Suárez Jan 05 '20 at 01:58
  • Yes, normally you would be able to access the protected field of another object so long as both are instances of the same class. Technically, the parameter `another` and `this` are both instances of AbstractSuperClass, so one would think that it works, but it apparently does not. – Jude Gao Jan 05 '20 at 02:26
  • 1
    Plus one for the opening volley, or if you prefer, sally. I hope they add a template for the bug tracker that begins: "I contrived a fairly trivial example to illustrate my point as follows." – som-snytt Jan 05 '20 at 03:55

2 Answers2

5

In scala, protected is more restrictive than in java.

I found this answer very helpful while understanding protected modifier for scala.

if protected member is not qualified(i.e. its just plain protected) then it is visible with another instances of declaring class into declaring class as well as with this into class and subclass.

So you could modify your addition function in SubclassSquare as follows:

override def addition(another: AbstractSuperClass, num: Int): Int =
      someFunction(num) + another.asInstanceOf[SubclassSquare].someFunction(num)

This code would compile, but it’d crash if the argument is not an instance of SubclassSquare, so it’s not a good solution.

The better way is to use access qualifiers. So you just need to specify your package name with protected modifier e.g. protected[yourPackageName]. Doing this will make your protected member accessible in classes in declared package or below. So your code will look like:

abstract class AbstractSuperClass {
    protected[yourPackageName] def someFunction(num: Int): Int
    def addition(another: AbstractSuperClass, num: Int): Int
  }

  class SubclassSquare extends AbstractSuperClass {
    override protected[yourPackageName] def someFunction(num: Int): Int = num * num
    override def addition(another: AbstractSuperClass, num: Int): Int =
      someFunction(num) + another.someFunction(num)
  }
Blaisorblade
  • 6,438
  • 1
  • 43
  • 76
asanand
  • 404
  • 3
  • 8
4

You can widen the access:

package prot

abstract class AbstractSuperClass {
  protected[prot] def someFunction(num: Int): Int
  def addition(another: AbstractSuperClass, num: Int): Int
}

class SubclassSquare extends AbstractSuperClass {
  override protected[prot] def someFunction(num: Int): Int = num * num
  override def addition(another: AbstractSuperClass, num: Int): Int = someFunction(num) + another.someFunction(num)
}

The spec words:

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.

So access depends on what you're selecting from.

You fell afoul of the third condition, and the first is the remedy.

som-snytt
  • 39,429
  • 2
  • 47
  • 129