There is an error I don't understand:
class MyClass1 {
private class MyClass1Internal(a: Int, b: Int, c: String, d: String)
def method1 = {
// doing something
new MyClass1Internal(1, 2, "3", "4")
}
}
an error
private class MyClass1Internal escapes its defining scope as part of type MyClass1.this.MyClass1Internal
[error] def method1 = {
[error] ^
What is it about and how do I get rid of it?
MyClass1Internal is private and thus should never be able to be accessed outside of MyClass1, but method will return an instance of it outside this class (as it's public), thus breaking its defining scope.
I bet if you defined method as private it would fix this error. You could also make the nested class not be private.
One more thing, if you wanted other code be able to work with that class but not be able to instantiate it, then just make the constructor private and the class public like so:
class MyClass1 {
class MyClass1Internal private[MyClass1](a: Int, b: Int, c: String, d: String)
def method1 = {
// doing something
new MyClass1Internal(1, 2, "3", "4")
}
}
The public API of MyClass1 uses a part of its private API (MyClass1Internal). This is bad, as another class does not know MyClass1Internal and hence cannot make sense of the return type of method1.
If you do not want to expose MyClass1Internal but still return an instance to it, you'll have to upcast method1's return type to something public. For example:
trait MyClass1Interface {
def a: Int
}
class MyClass1 {
private class MyClass1Internal(val a: Int, b: Int, c: String, d: String)
extends MyClass1Interface
def method1: MyClass1Interface = {
// doing something
new MyClass1Internal(1, 2, "3", "4")
}
}
This allows you to hide the exact implementation of the interface in your class, but keep the method public. (Your interface can of course still be part of the class if you prefer that).
Related
I'm new to Scala and can't find a way to achieve what I want.
I want to have abstract method in parent class like this
def copy():M
and then in each child class this method should have different number of arguments like
def copy(id: Int, title: String):M
Now when I try
override def copy(id: Int, title: String):M
I've got compilation error
method copy overrides nothing
If your parameters would be of the same type, you could write method signature like this
def copy(args: SomeType*):M
If not, you can use abstract type
trait T {
type CopyParam
def copy(c: CopyParam): T
}
case class SomeCopyParam(i: Int, s: String)
class A extends T {
type CopyParam = SomeCopyParam
def copy(c: SomeCopyParam): A = {
println(c.i + c.s)
this // some changed copy should be here
}
}
And use it like this:
val original = new A()
val copy = original.copy(SomeCopyParam(1, "a"))
I'd like to have some type 'ValidatedVals' that can be instantiated exclusively by a single class (i.e. it is the single factory for ValidatedVals).
I'd then like to reference this ValidatedVals type in many other classes.
Private constructors seems like one answer... but ...
The code below fails because (apparently) an inner class with a private constructor, declared within
object X{ ... }
makes that constructor not visible within object X
So, in the code below, how can I make it so that:
ONLY ValidatedValsFactory can construct a ValidatedVals object
AND I can reference a ValidatedVals type in other classes?
_
class ValidatedValsFactory {}
object ValidatedValsFactory {
class ValidatedVals private (val a: Int, val b: Int) {}
def validate(a: Int, b: Int): Unit = { /* .... */ }
def makeValidated(a: Int, b: Int): ValidatedVals = {
validate(a, b);
// **** Nope. Fail. Not visible. *****
return new ValidatedVals(a, b)
}
}
class ValidatedValsConsumer {
def f(param: ValidatedValsFactory.ValidatedVals): Unit = { /* ... */ }
}
I don't want f's parameter's type to be an interface (because its easy to circumvent the validate by implementing the interface).
I can't move class ValidatedVals into the class definition of ValidatedValsFactory because ValidatedValsConsumer needs to be able to reference the inner class typename (and therefore ValidatedVals must be a static declaration).
garrghh!
Looks like the compilation error goes away if you make it private to the object:
class ValidatedVals private[ValidatedValsFactory] (val a: Int, val b: Int) {}
Consider declaring your ValidatedVals type as a sealed class or trait. More details here: What is a sealed trait?
I know that we can overload class constructor in Scala as follows-
class Foo(x: Int, z: String) {
def this(z: String) = this(0, z);
}
But how can I overload a class which have two completely different types of parameters as below (imagine that I can identify an user either by name or numeric id)
class User(userId: Int) {
...
}
class User(userName: String) {
...
}
(imagine that I can identify an user either by name or numeric id)
You almost certainly don't want to do this by having optional fields in your class. Rather, you should encode the fact that the user is identified in various ways into the types and structure of your program.
One way to do this is to encode the user identifier using Scala's built-in Either type:
class User private(identifier : Either[String, Int]) {
def this(id : Int) = this(Right(id))
def this(name : String) = this(Left(name))
}
However, you might also want to make the nature of the user identifier a little more explicit, and encode it as your own Algebraic data type:
trait UserIdentifier
object UserIdentifier {
case class ById(id : Int) extends UserIdentifier
case class ByName(name : String) extends UserIdentifier
}
class User(id : UserIdentifier) {
def this(id : Int) = this(UserIdentifier.ById(id))
def this(name : String) = this(UserIdentifier.ByName(name))
}
By doing it this way, you prevent problems such as somebody trying to look up a name on a User which is identified by an id instead. The second approach also allows you to extend the idea of a UserIdentifier in the future, in case a user can be identified by some other construct.
Alternativelly, you can do this
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int)
class UserS(userName: String)
}
And use it this way:
val u1 = User(1)
val u2 = User("a")
If you have a lot of common logic you can put it into a common abstract class
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int) extends AUser
class UserS(userName: String) extends AUser
abstract class AUser{
// common logic for both classes
}
}
You can do this:
class User private() {
def this( userName: String ) = { this(); ??? }
def this( userId: Int ) = { this(); ??? }
}
the private keyword makes the no-arg constructor private. This means your other secondary constructors don't need to pass anything to the primary constructor
(effectively making the two secondary constructors independant), but the callers still cannot instantiate the class withouth passing any parameter.
Note that this pattern can be tricky to use when your class has vals to initialize from the construtors parameters.
In Scala I need to do something like following code in Java does:
public class A {
private String text;
public A(String text) {
this.text = text;
}
}
How can achieve that in Scala?
I know that I can use class A(text: String) { ... }, but this is only a very simplified example and not real case.
I have tried the following and it prints always null:
class A {
var text: String = null
def this(text: String) = {
this()
this.text = text
}
println(text)
}
Thanks for help.
In Scala classes have only one main constructor, and it's exactly what you define like this: class A(text: String) { ... }. All other constructors should call it at first and then do their own stuff.
All expressions in the body of the class are treated as body of the main constructor. So println(text) in you case is in the body of the main constructor. You call this() in your def this(text: String) constructor at first, so println is executed and only then you initialize text field.
From my point of view, main constructor can satisfy most of the real-life use-cases (especially with default and named arguments). So can you please elaborate on this and explain why you need the second one? Maybe we can find beter solution for the problem you are facing there.
Update regarding the comment
If you want to provide a set of optional arguments during construction time, then I recommend you to use Option instead of null values. So you can implement your A class like this:
class A(val a: Option[String] = None, val b: Option[Int] = None, c: Option[Double] = Some(2.0))
new A(b = Some(10))
All fields are now constant and have some default, but you can customize some of them. It's also possible that some combination of arguments are mutually exclusive, according to some business logic, for example. In this case it's reasonable to use several constructors. But even better solution can be to create several factory methods in companion object of the class and make constructor private. For example, if users of the class are allowed to provide either a and b or c, then you can write something like this:
class A private (val a: Option[String] = None, val b: Option[Int] = None, c: Option[Double] = Some(2.0))
object A {
def apply(a: String, b: Int) = new A(Some(a), Some(b))
def apply(c: Double) = new A(c = Some(c))
}
A("test", 1)
A(11.1)
class A {
var text: String = null
def this(text: String) = {
this()
this.text = text
println(text)
}
}
or
class A(text:String=""){
println(text)
}
or
class A(text:String=null){
println(text)
}
The correct way to do that is :
class A( text : String) {
def this() = this("") // or null
}
As Tenshi said, the default constructor is the A(text : String) and all other constructors, for instance this() must call it first.
I have two case classes that inherit from an abstract base class. I want to define some methods on the abstract base class that use the copy methods on the inheriting case classes (and so return an instance of the child class.) Is there a way to do this using self types?
Example code:
abstract class BaseClass(a: String, b: Int) {
this: case class => //not legal, but I'm looking for something similar
def doubleB(newB: Int) = this.copy(b = b * 2) //doesn't work because BaseClass has no copy
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass(a, b) {
def doesStuffWithC(newC: Boolean) = {
...
}
}
case class HasD(a: String, b: Int, D: Double) extends BaseClass(a, b) {
def doesStuffWithD(newD: Double) = {
...
}
}
I've figured out how to get the result I want thanks to this question:
How to use Scala's this typing, abstract types, etc. to implement a Self type?
but it involves adding a makeCopy method to BaseClass and overriding it with a call to copy in each of the child case classes, and the syntax (especially for the Self type) is fairly confusing. Is there a way to do this with Scala's built in self typing?
You can't do what you want because copy needs to know about all the possible parameters. So even if case classes inherited from Copyable, it wouldn't be the copy you needed. Also, if you're going to keep the types straight, you'll be thwarted by Scala's lack of a "MyType". So you can't just extend a base class. However, you could add an abstract method and type annotation:
abstract class BaseClass[C <: BaseClass[_]](a: String, b: Int) {
def setB(b0: Int): C
def doubleB(b0: Int) = setB(b0*2)
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass[HasC](a,b) {
def setB(b0: Int) = this.copy(b = b0)
def doesStuffWithC(c0: Boolean) = doubleB(if (c0) b else -b).copy(c = c0)
}
And then you can:
scala> HasC("fish",1,false).doesStuffWithC(true)
res47: HasC = HasC(fish,2,true)
This extra work will be worth it if you have a lot of shared functionality that depends on the ability to copy just b (either many methods, or a small number of complicated methods)--that is, this solves the DRY issue. If instead you want to abstract over HasC and other derived classes, you can either use BaseClass[_] or add yet another level that defines setB(b0: Int): BaseBase or simply forget the type parameterization and use BaseClass as the return type (but recognize that HasC cannot use BaseClass methods and still retain its type identity).
I think you're out of luck. The copy methods on HasC and HasD have different signatures. It's a bit hidden because of the default arguments, but basically the definition in BaseClass wouldn't know which copy method to call.
You could define a makeCopy in the abstract class that takes a copier function that takes Unit and returns a BaseClass, then, in your methods that use it (like doubleB) override them in the case class bodies and make use of makeCopy by passing it an anonymous function that does the work of creating a new copy with the props changed, like so:
package delegatedcopy
abstract class BaseClass(a: String, b:Int){
def aField = a
def bField = b
def doubleB:BaseClass
def makeCopy(copier: () => BaseClass):BaseClass = copier()
}
case class HasC(override val aField: String, override val bField: Int, cField: Boolean) extends BaseClass(aField, bField){
override def doubleB:BaseClass = makeCopy( ()=> HasC(aField, bField * 2, cField) )
}
case class HasD(override val aField: String, override val bField: Int, dField:Double) extends BaseClass(aField, bField){
override def doubleB:BaseClass = makeCopy( ()=> HasD(aField, bField * 2, dField) )
}
A test app that demonstrates it:
import delegatedcopy._
object TestApp extends Application{
val hasC = HasC( "A C object", 5, true)
val hasD = HasD( "A D object", 2, 3.55)
val hasCDoubleB = hasC.doubleB
val hasDDoubleB = hasD.doubleB
println(hasC) // prints HasC(A C object,5,true)
println(hasCDoubleB) //prints HasC(A C object,10,true)
println( hasD ) // prints HasD(A D object,2,3.55)
println( hasDDoubleB ) // prints HasD(A D object,4,3.55)
}
In this way, you are able to keep the makeCopy method the same for all children classes as in the base class, and can probably implement or mix in quite a bit of functionality in the base and case classes while keeping common code in a safe place and being able to pass clients a BaseClass and pattern match on the specific case classes.