Scala protected constructor and builder in companion object - scala

I have some classes with a protected constructor and the factory method is inside the companion object of an abstract super class. As of Scala 2.9.0.RC4 this doesn't compile anymore. I have "fixed" the issue by making the constructors package protected. But I don't want other classes even inside the same package to be able to call the constructors.
So what should I?
sealed abstract class A
object A {
//the factory method, returning either a B or C
def apply(): A
}
class B protected (...) extends A
class C protected (...) extends A

You could make them private inner classes of the object.
object A {
private class B extends A
private class C extends A
}

Since you need the classes accessible for pattern matching, I would suggest creating a new subpackage for them and making the constructor private to that package. Now only the import statements in your client code need to be changed.
sealed abstract class A {
}
package myPackage.subPackage {
object A {
def apply(): A = new B
}
class B private[subPackage] () extends A {
}
}
package other {
object Foo {
def foo {
myPackage.subPackage.A()
//does not compile: new myPackage.subPackage.B
}
}
}

Another option is to create companion objects for each implementation of A and delegate construction to a factory method in this object:
sealed abstract class A
object A {
//the factory method, returning either a B or C
def apply(): A = {
if (...) B()
else C()
}
}
object B {
def apply() : B = new B()
}
class B private (...) extends A
object C {
def apply() : C = new C()
}
class C private (...) extends A

Related

Why does this subclass have to implement a final method?

I thought putting final in Function would stop this issue from happening? I'm not too familiar with Scala. Can someone explain?
Class 'Country must either be declared abstract or implement abstract member 'execute():Object' in path.to.Invokable'
class Country extends MarketFunction("america") {}
abstract class MarketFunction(function: String) extends Function {
...
}
trait Function extends Invokable {
final def execute(): AnyRef = {
// not important
}
}
public interface Invokable {
Object execute();
}
Is it because AnyRef is not a direct comparison to java Object?
This worked for me
class Country extends MarketFunction("america") {}
abstract class MarketFunction(function: String) extends Function[AnyRef] {
...
}
trait Function[A <: AnyRef] extends Invokable {
override final def execute(): A = {
// not important
}
}
public interface Invokable {
Object execute();
}

How to "instantiate" an abstract class in the superclass?

I am implementing an extension of ml.Transformer in Spark; but this question is Scala specific. Here is an example object (part of a Class/Object pair):
abstract class UDFTransformer(func: UserDefinedFunction,
inputFieldNames: Seq[String],
outputFieldName: String) extends Transformer with MLWritable with Serializable {
... definitions here ...
}
object UDFTransformer extends MLReadable[UDFTransformer] {
// Since there are no parameters associted with the UDF, there is nothing to save!
class Writer(instance: UDFTransformer) extends MLWriter {
override protected def saveImpl(path: String): Unit = {}
}
abstract protected class Reader extends MLReader[UDFTransformer]
override def read: MLReader[UDFTransformer] = new Reader
override def load(path: String): UDFTransformer = super.load(path)
}
The new Reader does not compile because the class is abstract and cannot be instantiated. But; any child class will have to define it; along with its necessary members. I cannot just make read abstract as well, this gives me a warning Only classes can have declared but undefined methods.
The fundamental problem is that each child class of my UDFTransformer is going to wrap a specific UDF. Therefore, the reader needs to be able to generate a specific UDF object; this can't be declared in the superclass. But this 'factory' belongs in the companion object, not in the abstract class itself.
How can I go about building a companion object for an abstract class that can leave the definition of read undefined?
The normal way to do it is by creating an abstract class or trait for the companion objects. Something like
abstract class UDFTransformerCompanion[T <: UDFTransformer] extends MLReadable[T] {
abstract def read: MLReader[T]
override def load(path: String): T = super.load(path)
}
class SomeTransformer extends UDFTransformer { ... }
object SomeTransformer extends UDFTransformerCompanion[SomeTransformer] {
override def read: MLReader[SomeTransformer] = ...
}
Not sure why you have the load = super.load override, and it doesn't look like you can have a companion object for the UDFTransformer itself, at least not one extending this abstract class.
See GenericTraversableTemplate for a standard library example.

Scala: Return type of abstract method

I cannot figure out how to specify the return type of a method an abstract class A, if the same method of the concrete classes have different return (sub)types:
abstract class A {
def method: List[Common (?)] // I want to force all subclasses to define this method
}
class B1 extends A {
def method(a,b,c): List[Sub1] = {...}
}
class B2 extends A {
def method(a,b,c): List[Sub2] = {...}
}
I tried to define a common trait of Sub1 and Sub2:
abstract class Common // or abstract class
case class Sub1 extends Common
case class Sub2 extends Common
but I keep getting this:
Compilation error[class B1 needs to be abstract,
since method "method" in class A of type => List[Common] is not defined]
If I don't define the return type in class A, I get the same error with ... type => Unit ... instead.
How can I solve that?
def method: List[Common]
Is not the same as
// returns `List[Common]` to simplify things, but it would be the same if we returned a sub-type
def method(a: ?, b: ?, c: ?): List[Common] = {...}
The first is a parameterless method that returns a List[Common], and the second is a method with three parameters that returns a List[Common]. The compiler sees these as two completely different methods. The fact that they have the same name means nothing.
The compiler is complaining because def method: List[Common] is not defined in the subclasses of A.
This compiles:
abstract class Common // or abstract class
case class Sub1() extends Common
case class Sub2() extends Common
abstract class A {
def method(): List[Common]
}
class B1 extends A {
def method(): List[Sub1] = ???
}
class B2 extends A {
def method(): List[Sub2] = ???
}
All I have done is:
add the () to Sub1() and Sub2()
return List[Common] from A
EDIT
As #m-z mentioned, it works because every def method() has the same signature now.

How to restrict public method access to superclass?

In my Scala project, I have the following class hierarchy:
class A {
def methodA = ...
... other methods here ...
}
class B extends A {
... other methods here ...
}
In my class design, it makes perfect sense to make B a subclass of A. The only problem is that methodA is only applicable to class A but not to class B. Unfortunately, I cannot set methodA to private because it needs to be callable from any instance of class A.
Do I have to rethink my class design or is it possible to restrict the access to public method methodA to class A?
In my class design, it makes perfect sense to make B a subclass of A. The only problem is that methodA is only applicable to class A but not to class B.
These statements can't be true at the same time.
Unfortunately, I cannot set methodA to private because it needs to be callable from any instance of class A.
Every instance of B is an instance of A (that's just what "subclass" means). So if the method isn't callable from an instance of B, it isn't "callable from any instance of class A".
One of possible way below:
class A protected() {
//.... methods ....
}
trait AExt extends A {
def foo(s : String) = println(s)
}
object A {
def apply() : A with AExt = new A with AExt
}
class B extends A {
//.... methods ....
}
val a = A()
a.foo("hello")
val b = new B()
// b.foo("hello") // no 'foo' method

Privacy of inner classes and accessibility from subtypes of the outer type

I'm having difficulties with the private annotation of inner class methods and constructors. While this works as expected:
trait A {
protected def lala = ()
}
trait B extends A {
lala
}
The following doesn't:
trait A {
class Lala protected()
}
trait B extends A {
new Lala
}
Neither does this:
trait A {
class Lala private[A]()
}
trait B extends A {
new Lala
}
The only way around is something like this:
object Screwed {
trait A {
class Lala private[Screwed]()
}
trait B extends A {
new Lala
}
}
Does Scala really fail here to provide a clear mechanism, or am I missing something? My guess would have been that it should be private[this.type] but scalac doesn't want to swallow that at all...
Well,
trait A {
class Lala protected()
new Lala
}
doesn't compile either. The error message seems pretty reasonable:
error: constructor Lala in class Lala cannot be accessed in trait A
Access to protected constructor Lala not permitted because
enclosing class trait A in object $iw is not a subclass of
class Lala in trait A where target is defined
Protected access means you can only access that constructor from that class or sub-classes. You're trying to call it from the enclosing trait. One thing you can do is this:
trait B extends A {
class Gaga extends Lala
new Gaga
}
I wouldn't expect your third example to compile, for similar reasons.
Also note the difference between a protected constructor and a protected class. So for example:
trait A {
protected class P
class U // unprotected
}
class B extends A {
new P // OK
new U // OK
}
val b = new B
new b.P // error
new b.U // OK
This also works with the desired visibility (Lala can only be instantiated from A or subtypes of A).
trait A {
class Lala private[A]()
protected def newLala = new Lala
}
trait B extends A {
newLala
}
I wonder what is the purpose of something like protected[A] if it doesn't work in this case.
the protected one should work for sure, what error do you get? for the private ones, the scope you define controls their visibility (so in a trait A, if you give visibility of A, it is obviously not visible in B). In the last example, you have given the scope as Screwed so anything inside Screwed would be able to see the private class. btw, I prefer to write the access modifiers as the first thing in a code line to facilitate easier reading
what version of scala are you using and what do you mean by "does not work" ?
HTH!