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?
Related
Consider the following segment of code -
abstract class Vehicle {
val name: String
}
case class Car(name: String) extends Vehicle
case class Truck(name: String) extends Vehicle
abstract class VehicleContainer[T <: Vehicle] {
def compare(that: VehicleContainer[T]): Int
}
class CarContainer(wheels: Int) extends VehicleContainer[Car] {
override def compare(that: CarContainer): Int = ???
}
The intention here is to have a compare method on the VehicleContainer that can be defined for each specific instance of VehicleContainer. The compare method comparison clause needs to be unique for each instance, because it could be comparing using attributes specific to that instance and hence not defined in the abstract base class VehicleContainer.
The trouble is that this does not work in it's current form, i.e. the override for compare is illegal. What I am not able to understand is how to accomplish this - define a base class that indicates that the sub classes need to implement a compare method, where the method argument to that compare method is that sub class itself. Would appreciate a pointer to the right concept here if it's some straightforward generics concept that I am missing here.
Thanks!
One way to solve your problem could be use of F-bounded polymophism. You would just need one additional type parameter:
abstract class Vehicle {
val name: String
}
case class Car(name: String) extends Vehicle
case class Truck(name: String) extends Vehicle
abstract class VehicleContainer[T <: Vehicle, V <: VehicleContainer[T, V]] {
def compare(that: V): Int
}
class CarContainer(wheels: Int) extends VehicleContainer[Car, CarContainer] {
override def compare(that: CarContainer): Int = ???
}
Given a superclass or trait, and assuming an open hierarchy, how can I enforce that all extending classes implement a particular type class?
For instance, assuming the type class Default
trait Default[T] { def default: T }
and some trait Super:
trait Super { }
I would like to enforce that the following (by itself) is not allowed:
class A(val i: Int) extends Super
...while the following is:
class B(val i: Int) extends Super
implicit val bHasDef = new Default[B] { def default = B(42) }
Assuming the above is possible, can I then access the type class evidence for the subtypes from a method within Super? I.e, something like:
trait Super {
def magic: Default[this.type] = ???
}
I hardly think you can enforce that, at least in a simple enough way, maybe it's possible with something more complex like shapeless.
What I would do is add some modifications to the super trait and make it take a self reference to Default
trait Default[T] { def default: T }
trait Super[T] {
self: Default[T] =>
}
class B(val i: Int) extends Super[Int] with Default[Int] {
override def default: Int = ???
}
class A(val i: Int) extends Super[Int] // doesn't compile, needs a Default
This should also solve the second part of your question, the disadvantage is that now one trait is bundled to the other.
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).
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.
If I understand correctly, traits are the closest thing to Java interfaces and class constructors automatically set the variables.
But what if I have a class that extends a trait and has a constructor which sets a variable from the trait, so something like:
trait Foo {
var foo: String
}
class Bar (foo: String) extends Foo { /* ... */ }
Where I want the foo string of the trait been set when I make a Bar object.
The compiler seems to give me errors about this. What is the correct way to achieve this?
trait Foo { var foo: String = _ }
class Bar(foo0: String) extends Foo { foo = foo0 }
The trait declares an uninitialized var; the class then sets it equal to the input parameter.
Alternatively,
trait Foo {
def foo: String
def foo_=(s: String): Unit
}
class Bar(var foo: String) extends Foo {}
declares the getter/setter pair corresponding to a foo, which are set by the class.
Bar must define the abstract var foo in Foo (would be the same for a val). This can be done in the constructor
class Bar(var foo: String) extends Foo{...}
(of course, it could be done in the body of Bar too). By default, constructor parameters will be turned to private val if need be, that is if they are used outside the initiailization code, in methods. But you can force the behavior by marking them val or var, and possibly control the visibility as in
class X(protected val s: String, private var i: Int)
Here you need a public var to implement Foo.