Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Final, Anonymous, or singleton (objects) classes should not have protected non-overridden members #11434

Open
diesalbla opened this Issue Mar 14, 2019 · 5 comments

Comments

Projects
None yet
4 participants
@diesalbla
Copy link

diesalbla commented Mar 14, 2019

Note: This is not a bug, it's a feature (request)

Consider the following code snippet, which compiles under Scala 2.12:

trait A 
trait B { protected x: Int }
final class C extends A with B {
  protected x: Int = ""     // OK
  protected y: String = ""  // KO
}
object D extends A with B {
  protected x: Int = 42      // OK 
  protected y: String = ""   // KO 
}
val e = new A with B {
  protected x: Int = 42     // OK
  protected y: String = ""  // KO 
}

The protected access modifier lies between public and private: it grants access to the member for the subclasses, but denies it to any other class. However, since final classes, cannot be extended, and have no sub-classes, it makes no sense for them to declare a protected member. Unless, of course, the said protected member was declared in a superclass, and so its access cannot be restricted to private.

Nevertheless, one can still desire for the compiler enforce the condition that a final class does not declare non-inherited protected members, either by:

  • Requiring that all protected methods also be marked as overridden, in which case the compiler would detect if they are not declared in a super-type; or
  • By adding to the compiler a check for this condition on final-like classes.

Note that here, super-class also includes traits or classes, and final classes includes anonymous classes and singleton classes.

@sjrd

This comment has been minimized.

Copy link
Member

sjrd commented Mar 14, 2019

There are reasonable use cases in Scala.js for protected members in final classes, because they are visible to JavaScript (or can be exported) but not to other Scala code.

Please don't make this idiom invalid.

@diesalbla

This comment has been minimized.

Copy link
Author

diesalbla commented Mar 14, 2019

There are reasonable use cases in Scala.js for protected members in final classes, because they are visible to JavaScript (or can be exported) but not to other Scala code.

Then why not make them public in that case? Subclasses can extend access grants on inherited protected members to make them public.

trait A { protected def x: Int = 0 }
trait B extends A { override def x: Int = 0} // x is now public  

Perhaps It could help to better understand the use cases you are referring to, if there was a small example of those, and why they would need protected members in final classes.

@joroKr21

This comment has been minimized.

Copy link

joroKr21 commented Mar 14, 2019

Sometimes I use protected in object as a workaround for linter limitations:

case class Foo(data: Map[String, Long])
object Foo {
  protected implicit val encodeData: Encoder[Map[String, Long]] = ...
  implicit val encoder: Encoder[Foo] = deriveEncoder // -> a macro
}

If we make encodeData private linters would complain that it's not used.
But it is after macro expansion!

@sjrd

This comment has been minimized.

Copy link
Member

sjrd commented Mar 14, 2019

@diesalbla Here is a typical usecase:

final class C {
  // For Scala users, give a List[Int]
  def xs: List[Int] = ???

  // For JS callers, give a js.Array[Int]
  @JSExport("xs")
  protected def jsXs: js.Array[Int] = xs.toJSArray
}
@hrhino

This comment has been minimized.

Copy link
Member

hrhino commented Mar 15, 2019

Scala is full of silly things you can do which one might think they want to be a compiler error. However, we also have scalafix, which can be made to emit that exact error. Moreover, while I would never have guessed that there would be a reason to use protected over private here, Sébastien reminds me that just because I can't think of it doesn't mean it shouldn't exist.

So I firmly think this should not be implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.