In scala I can add access modifiers to a class/trait/object, like
private class Foo
protected[this] trait Foo
I have not found any good explanation on these class/trait/object-level modifiers. Do all such combinations make sense and what do they actually mean?
They mean the same as access modifiers for class/trait members, as classes and traits can also be members of other classes. For example:
class A {
private class Foo
}
Class Foo is only visible to class A. If I change the modifier to private[this], then it is called object private, and so any Foo is only visible to it's parent instance of A.
Declaring private, private[this], protected or protected[this] only really makes sense within another class or trait, because it has to be private to something. In this case, Foo being private to A. The same applies to traits.
We could also not have a containing object, and make them package private.
package com.example.foo
private[foo] class Foo
Now class Foo is only visible to other members of the package com.example.foo.
Do they make sense? In some cases I'm sure it is useful to have private classes and traits within some other object.
Related
In Scala, what's the difference between:
abstract class Foo
// And
abstract class Bar()
There doesn't seem to be a difference between them when inheriting:
// All of these seem to work
case class FooA() extends Foo()
case class FooB() extends Foo
case class BarA() extends Bar()
case class BarB() extends Bar
Are these really all equivalent, or is there a difference? And if they are all equivalent, which abstract class definition should I use, Foo or Bar?
I know methods make this distinction because of currying. Can you curry when constructing a class? Is that why this weird duplication exists?
There is no difference. An abstract class is just a class with the abstract modifier, which imposes the rule that you cannot instantiate it unless the abstract members are implemented in some way (whether through mixins, etc). And there is no difference been a parameterless class and a class with an empty parameter list. If a class has no parameter list, the compiler assumes an empty one.
This is stated clearly in the SLS Section 5.3:
If no formal parameter sections are given, an empty parameter section () is assumed.
Since they are equivalent, it's really just a matter of taste which you should use. I prefer to omit the parentheses for brevity, but the compiler will add them back in anyway.
The only time this can make things confusing is when you have a class with only implicit parameters. For example, this:
abstract class Foo(implicit bar: Bar)
is actually
abstract class Foo()(implicit bar: Bar)
which causes confusion when one tries to supply the implicit manually, and the parentheses must be supplied. e.g.
new Foo()(new Bar)
I'm reading over someone elses code on Scala in order to learn the language a little better, but I'm stumped at what the following means "privateutil" If I just saw the [util] I would suspect that it was some sort of specific generic? but its got it's own private modifier?
class RPGPluginProperties private[util]() extends Properties {
From http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#private:
A private modifier can be qualified with an identifier C (e.g.
private[C]) that must denote a class or package enclosing the
definition. Members labeled with such a modifier are accessible
respectively only from code inside the package C or only from code
inside the class C and its companion module.
So in this case the private modifier is making the no-args constructor private to the util class/package.
To declare the class private to the scope util, it would be private[util] class RPGPluginProperties...
I have an abstract class in package foo (in this particular case, a trait) that can be implemented by various subclasses, and I'd like to create an orthogonal subclass for use in a more specific package bar that adds package-specific info. It seems the best way is by composition (wrapping) rather than inheritance because otherwise I'd have to declare package-specific versions of every single one of the foo-package subclasses. But this leads to a problem with protected members which need to be forwarded:
package foo {
trait Foo {
protected def bar: Int
}
}
package bar {
import foo.Foo
class Baz
class WrapFoo(wrapped: Foo) extends Baz with Foo {
protected def bar = wrapped.bar
}
}
This leads to an error:
~/test/scala 14:54 152272% scalac testprotected.scala
testprotected.scala:11: error: method bar in trait Foo cannot be accessed in foo.Foo
Access to protected method bar not permitted because
prefix type foo.Foo does not conform to
class WrapFoo in package bar where the access take place
protected def bar = wrapped.bar
^
one error found
Even though WrapFoo is a subclass of Foo, scala doesn't like the call wrapped.bar. I'm guessing this is because the object of type WrapFoo isn't a sub-object of wrapped.
The question is: What's the idiomatic way to declare the protections on bar other than simply making it public? The function bar is meant to be called by other functions in Foo, not publicly. Scala has an expressive protection system but I don't quite understand it. Is this possible at all?
Put both types in a common package, it can be anywhere in the package hierarchy and doesn't have to be an immediate parent.
Then you can use protected[packagename] or private[packagename] to selectively control access.
I am confused regarding backward compatibility when adding a method with default implementation to a trait. Like:
Previous Version
trait Foo
New Version
trait Foo {
def verifyConsistency: Option[String] = ??? // provide default implementation
}
The Migration Manager reports this addition as a binary incompatibility. Is that correct?
Well yes it is correct.
When you define trait Foo, it will under the hood create both a (JVM) interface Foo and a (JVM) class Foo$class with all the method implementations defined as static methods. The corresponding java code would look like something like this (for your new defintion of Foo):
interface Foo {
Option<String> verifyConsistency();
}
class Foo$class {
static Option<String> verifyConsistency(Foo self) {
Predef.???();
}
}
When you mix Foo into a concrete class Bar, what happens at the JVM level is that Bar extends the interface Foo, and it implements method verifyConsistency by simply forwarding the call to Foo$class:
class Bar implements Foo {
Option<String> verifyConsistency() {
return Foo$class.verifyConsistency(this); // simple forwarding
}
}
The reason why it is done this way is that the JVM object model does not support multiple inheritance. The traits implementations cannot be simply put in classes that you would extend from, because you can only ever extend a single class on the JVM.
The take away of this situation is that everytime a concrete class mixes a trait, the class defines "stub" methods for each member of the trait (those methods simply forward to the actual implementation, which is a static method).
One consequence is that if you add a new method to a trait, even if you define an implementation it is not enough: concrete classes that mix the trait need to be recompiled (so that a stub for the new method is added to the class). If you don't recompile those classes, your program will fail to run, as you would now have a class that is supposedly concrete (non abstract) AND extend the corresponding interface but actually miss the implementation for the new method.
In your case this means having concrete classes that extend interface Foo but do not have any implementation for verifyConsistency.
Hence the binary incompatibility.
Are there cases where it's preferable to mixin traits to access the functionality of "static" methods, rather than importing objects with those methods?
Say we want to access the functionality of a method a(). Would we ever extend a trait that contains a() rather than import an object that contains a()?
If we look at the following example:
1)
trait A {
def a() {}
}
...
class B extends A {
val b = a()
}
vs.
2)
object A {
def a() {}
}
...
import A._
class B {
val b = a()
}
Is there any reason to prefer the first approach, even if there is no "is-a" relationship between the two classes B and A?
Maybe things that extend B don't want to keep re-importing A?
Maybe the method relies upon other "static" methods but you actually want to override the implementation?
If B is final (or an object) and the methods really are static (and don't refer to implementations that you might want to change in B), then there's not much point in mixing in a trait. The only exception is if there are implicit conversions defined, where if you mix in the implicit it will have lower priority than if you declare it yourself.
(Check out scala.LowPriorityImplicits which is mixed into scala.Predef for examples.)
All that Rex said...
And keep in mind as well that an import brings artifacts (methods, fields) into the current scope, but doesn't expose them on the new class' interface.
Mixing in a trait may expose artifacts (either public, protected, or ...) by making them "part of" the new class/trait interface.