How to partially abstract a method in Scala - scala

This question is related to this one.
I have a family of classes of type Config and all of them are built using a builder pattern. Therefore, I have also ConfigBuilder classes that form a hierarchy as well, since many implementation share the same behaviour.
What I want to achieve is that ConfigBuilder expose a method build which always perform these steps: validate the parameters (throwing an exception if not valid) and build the Config. Of course I would like to do this with the least possible duplication of code. In fact, the build method can be ideally split in two parts: a common build of the parameters shared by all implementation of Config and a implementation-specific build for each Config.
This is an example of the superclasses
abstract class Config {
def name: String
def query: String
def sourceTable: String
}
abstract class ConfigBuilder {
// common variables are set through setters by the user, which finally calls build
def build = {
validate
val sourceTable = extractFrom(query) // private local method
// it will contain more fields, extracted from the ones set by the user
buildInternal(sourceTable)
}
def validate = {
if(name == null) throw new Exception() // and all common checks
}
abstract def buildInternal(s:String): Config
}
And this is an implementation
case class Factlog private (
name:String, query:String, sourceTable:String, description: String)
class FactlogBuilder extends ConfigBuilder {
// description is set through setters by the user
def validate = {
super.validate()
if(description == null) throw new Exception()
}
def buildInternal(s:String) =
Factlog(name,query,s,description)
}
This snippet of code works but I would like to understand if this is the best way to do implement the build and buildInternal method.
With this approach, buildInternal signature will change with any new Factlog specific parameter, so the solution will be to place the computation of sourceTable in ConfigBuilder, outside the method build
If I do this, I am forced to generate sourceTable before the call to validate
As last approach, I could instantiate the variable outside as var sourceTable = _ and then, after validate method call, give it the value returned by the method extractQuery
I am tempted to use the approach 3, but I assume this is not really how Scala should be used. I am sure there are better approaches to compose these hierarchies.
P.S. the list of parameters will surely grow over time, so this is something that I have to consider. Moreover, the builder pattern usage is facilitated by a Spark feature that at the moment I cannot avoid to use.

Related

How to enforce encapsulation of immutable class in Scala?

I am trying to write immutable code in Dart. Dart wasn't really built with immutability in mind, that's why I need to write a lot of boilerplate in order to achieve immutability. Because of this, I got interested in how a language, like Scala, which was built around the concept of immutability, would solve this.
I am currently using the following class in Dart:
class Profile{
List<String> _inSyncBikeIds = []; // private field
String profileName; // public field
Profile(this.profileName); // You should not be able to pass a value to _inSyncBikeIds
void synchronize(String bikeId){
_inSyncBikeIds.add(bikeId);
}
bool isInSync(String bikeId){
return _inSyncBikeIds.contains(bikeId);
}
void reset(){
_inSyncBikeIds = [];
}
}
The same class in immutable:
class Profile{
final List<String> _inSyncBikeIds = []; // private final field
final String profileName; // public final field
factory Profile(String profileName) => Profile._(profileName); // You should not be able to pass a value to _inSyncBikeIds
Profile._(this._inSyncBikeIds, this.profileName); // private contructor
Profile synchronize(String bikeId){
return _copyWith(inSyncBikeIds: _inSyncBikeIds.add(bikeId);
}
bool isInSync(String bikeId) {
return _inSyncBikeIds.contains(bikeId);
}
Profile reset(){
return _copyWith(inSyncBikeIds: []);
}
Profile copyWith({
String profileName,
}) {
return _copyWith(profileName: profileName)
}
Profile _copyWith({
String profileName,
List<Id> inSyncBikeIds,
}) {
return Profile._(
profileName: profileName ?? this.profileName,
inSyncBikeIds: inSyncBikeIds ?? _inSyncBikeIds);
}
}
What I understand from Scala so far, is that for every class a copy method is automatically created. In order to be able to change a field using the copy method, it needs to be part of the constructor.
I want the field _inSyncBikeIds to be final (val in Scala). In order to change the value of the field _inSyncBikeIds I need to create a copy of the object. But in order to use the copy method, to change the field, it needs to be part of the constructor of the class, like class Profile(private val _inSyncBikeIds, val profileName). But this would then break encapsulation, because everyone can create an object and initialize _inSyncBikeIds. In my case, _inSyncBikeIds should always be an empty list after initialization.
Three questions:
How do I solve this in Scala?
When I use the copy method inside the class, can I change private fields using the copy method?
Does the copy method in Scala copy private fields as well (even when they are not part of the constructor, you can't mutate that private field then of course)?
Scala comes from a tradition that tends to view immutable data as a license for free sharing (thus public by default etc.). The interpretation of encapsulation is more that code outside an object not be able to directly mutate data: immutable data regardless of visibility satisfies this.
It's possible to suppress the auto-generated copy method for a case class by making it abstract (nearly always sealed abstract with a private constructor). This is commonly used to make the apply/copy methods return a different type (e.g. something which encodes a validation failure as a value without throwing an exception (as require would)), but it can be used for your purpose
sealed abstract case class Profile private(private val _inSyncBikeIds: List[String], profileName: String) {
def addBike(bikeId: String): Profile = Profile.unsafeApply(bikeId :: _inSyncBikeIds, profileName)
// Might consider using a Set...
def isInSync(bikeId: String): Boolean = _inSyncBikeIds.contains(bikeId)
def copy(profileName: String = profileName): Profile = Profile.unsafeApply(_inSyncBikeIds, profileName)
}
object Profile {
def apply(profileName: String): Profile = unsafeApply(Nil, profileName)
private[Profile] def apply(_inSyncBikeIds: List[String], profileName: String): Profile = new Profile(_inSyncBikeIds, profileName) {}
}
unsafeApply is more common for the validation as value use-case, but the main purpose it serves is to limit the concrete implementations of the abstract Profile to only that anonymous implementation; this monomorphism has beneficial implications for runtime performance.
Notes: case classes are Serializable, so there is a Java serialization hole: in application code this is solvable by never ever using Java serialization because it's broken, but it makes up for being broken by being completely evil (i.e. if you have a Scala application that uses Java serialization, you should probably re-evaluate the choices that led you there).
There's no way to encode sealedness in JVM bytecode AFAIK (Scala uses an annotation, IIRC, so Scala will limit extension of Profile to that compilation unit but, e.g, Kotlin won't), nor is the private[Profile] access control encoded in a way that JVM languages which aren't Scala will enforce (the unsafeApply method is actually public in the bytecode). Again, in application code, the obvious question is "why are you trying to use this from Java/Kotlin/Clojure/...?". In a library, you might have to do something hacky like throw an exception, catch it and inspect the top frames of the stack, throwing again if it's not hunky-dory.
I have no idea if it is possible in dart, but in scala this would be done with a private constructor:
class Profile private (val _foo: Seq[String], val bar: String) {
def this(bar: String) = this(Nil, bar)
}
This lets you define
private copy(foo: Seq[String], bar: String) = new Profile(foo, bar)
This is fine as long the class is final. If you subclass it, badness ensues: Child.copy() returns an instance of Parent, unless you override copy in every subclass, but there is no good way to enforce it (scala 3 admittedly has some improvement over this).
The generated copy method you mentioned only works for case classes. But subclassing a case class would lead to some even more interesting results.
This is really rarely useful though. Looking at your code for instance, if I read the ask correctly, you want the user to not be able to do
Profile(List("foo"), "bar") but Profile("bar").synchronize("foo") is still possible even though it produces exactly the same result. This hardly seems useful.

Setting an immutable field for later use

I'm in a situation where I need to set a certain field in a singleton object so it can be used later.
def register(importantField: String): Unit = {
Factory.setField(importantField)
}
where Factory is:
object Factory {
var field: Option[String] = None
def setField(importantField: String): Unit = {
field = Option(importantField)
}
def functionThatWillBeCalledLater: Unit = {
// do something with member "field"
}
}
but I really want to avoid using var. Is there some kind of idiomatic way to do this?
Don't do this. Global factories, besides being racy and breaking referential transparency, are also a nightmare for unit testing. You should really think about designing your code in a way, where you can keep all the "important fields" where you need them.
The trick is that instead of something like
class Foo {
def doFoo() = Factory.bar
}
Factory.register(param)
new Foo().doFoo()
You would have to write
class Foo {
def doFoo(factory: Factory) = factory.bar
}
new Foo().doFoo(new Factory(param)
Or maybe
class Foo(factory: Factory) {
def doFoo() = factory.bar
}
new Foo(new Factory(param)).doFoo
It may seem a bit tedious compared, to just throwing all the stuff into a global state object, and accessing it from everywhere ... but that's only as long as all of the uses of that function everywhere always use the same value of the parameter (in which case, it is better off just being a constant in the first place) or (perhaps, more importantly) until you start thinking about writing unit tests to test places that use your Factory. You cannot mock an object ... so, what will you do?
Singleton objects have to be thread safe - since the object is static, there's no guarantee that only one thread will access it, so your call not to use a var is totally reasonable. All vals are final and guaranteed to be thread safe, but we can't say the same about vars (and, well, if we're talking about idiomatic, mutable state is generally frowned upon).
You could implement your own getter and setter (using proper synchronization) for a private var, or use a scala.concurrent.Promise for this purpose - a Promise can only be completed once, and is guaranteed to be thread safe.
import scala.concurrent.Promise
object Factory {
private val _field: Promise[String] = Promise()
// the notation below allows you to set it via `Factory.field = "a"`
def field_=(value: String): Boolean = _field.trySuccess(value)
def field: Option[String] = _field.future.value.flatMap(_.toOption)
}
That said, the most idiomatic Scala way to approach factories with variable baseline conditions would be to create one with all the variables set to the values you need. An object is essentially just a val, so instead of an actual singleton object you could instantiate the Factory with all the parameters you need once they're available - and then just use that everywhere.

Scala Class that containing List

I have a very basic and simple Scala question. For example, I have a java class like that
class Dataset{
private List<Record> records;
Dataset(){
records = new ArrayList<Record>()
}
public void addItem(Record r){
records.add(r)
}
}
When I try to write same class in Scala, I encoutered with some error:
class RecordSet() {
private var dataset:List[Record]
def this(){
dataset = new List[Record]
}
def addRecord(rd: Record)={
dataset :+ rd
}
}
I cannot declare a List variable like ( private var dataset:List[Record])
and cannot write a default constructor.
Here is how you will replicate the Java code you mentioned in your question:
// defining Record so the code below compiles
case class Record()
// Here is the Scala implementation
class RecordSet(private var dataset:List[Record]) {
def addRecord(rd: Record)={
dataset :+ rd
}
}
Some explanation:
In Scala, when you define a class, you have the ability to pass parameter to the class definition. eg: class Foo(num:Int, descr:String) Scala would automatically use the given parameter to create a primary constructor for you. So you can now instantiate the Foo, like so new Foo(1, "One"). This is different in Java where you have to explicitly define parameter accepting constructors.
You have to be aware that the parameter passed do not automatically become instance member of the class. Although if you want, you can tell Scala to make them instance member. There are various ways to do this, one way is to prefix the parameter with either var or val. For example class Foo(val num:Int, val descr:String) or class Foo(var num:Int, var descr:String). The difference is that with val, the instance variable are immutable. With var they are mutable.
Also, by default the instance member Scala will generate would be public. That means they can be accessed directly from an instance of the object. For example:
val foo = new Foo(1, "One")
println(foo.num) // prints 1.
If you want them to be private, you add private keyword to the definition. So that would become:
class Foo(private var num:Int, private var desc:String)
The reason why your code fails to compile is you define a method called this() which is used to create multiple constructors. (and not to create a constructor that initiates a private field which is your intention judging from the Java code you shared). You can google for multiple constructors or auxiliary constructors to learn more about this.
As dade told the issue in your code is that with this keyword you are actually creating an auxilary constructor which has some limitations like the first line of your auxilary constructor must be another constructor (auxilary/primary). Hence you cannot use such a way to create a class.
Also you can not write such lines in a scala concrete class private var dataset:List[Record] as it is considered as abstract (no definition provided).
Now with the code. Usually in Scala we don't prefer mutability because it introduces side-effects in our functions (which is not the functional way but as scala is not purely functional you can use mutability too).
In Scala way, the code should be something like this:
class RecordSet(private val dataset:List[Record]) {
def addRecord(rd: Record): RecordSet ={
new RecordSet(dataset :+ rd)
}
}
Now with the above class there is no mutability. Whenever you are adding on an element to the dataset a new instance of RecordSet is being created. Hence no mutability.
However, if you have to use the same class reference in your application use your a mutable collection for your dataset like below:
class RecordSet(private val dataset:ListBuffer[Record]) {
def addRecord(rd: Record): ListBuffer[Record] ={
dataset += rd
}
}
Above code will append the new record in the existing dataset with the same class reference.

Scala cake pattern for objects with different lifetimes

I tried to use cake pattern in my project and liked it very much, but there is one problem which bothers me.
Cake pattern is easy to use when all your components have the same lifetime. You just define multiple traits-components, extend them by traits-implementation and then combine these implementations within one object, and via self-types all dependencies are automatically resolved.
But suppose you have a component (with its own dependencies) which can be created as a consequence of user action. This component cannot be created at the application startup because there is no data for it yet, but it should have automatic dependency resolution when it is created. An example of such components relationship is main GUI window and its complex subitems (e.g. a tab in notebook pane) which are created on user request. Main window is created on application startup, and some subpane in it is created when user performs some action.
This is easily done in DI frameworks like Guice: if I want multiple instances of some class I just inject a Provider<MyClass>; then I call get() method on that provider, and all dependencies of MyClass are automatically resolved. If MyClass requires some dynamically calculated data, I can use assisted inject extension, but the resulting code still boils down to a provider/factory. Related concept, scopes, also helps.
But I cannot think of a good way to do this using cake pattern. Currently I'm using something like this:
trait ModelContainerComponent { // Globally scoped dependency
def model: Model
}
trait SubpaneViewComponent { // A part of dynamically created cake
...
}
trait SubpaneControllerComponent { // Another part of dynamically created cake
...
}
trait DefaultSubpaneViewComponent { // Implementation
self: SubpaneControllerComponent with ModelContainerComponent =>
...
}
trait DefaultSubpaneControllerComponent { // Implementation
self: SubpaneViewComponent with ModelContainerComponent =>
...
}
trait SubpaneProvider { // A component which aids in dynamic subpane creation
def newSubpane(): Subpane
}
object SubpaneProvider {
type Subpane = SubpaneControllerComponent with SubpaneViewComponent
}
trait DefaultSubpaneProvider { // Provider component implementation
self: ModelContainerComponent =>
def newSubpane() = new DefaultSubpaneControllerComponent with DefaultSubpaneViewController with ModelContainerComponent {
val model = self.model // Pass global dependency to the dynamic cake
}.asInstanceOf[Subpane]
}
Then I mix DefaultSubpaneProvider in my top-level cake and inject SubpaneProvider in all components which need to create subpanes.
The problem in this approach is that I have to manually pass dependencies (model in ModelContainerComponent) down from the top-level cake to the dynamically created cake. This is only a trivial example, but there can be more dependencies, and also there can be more types of dynamically created cakes. They all require manual passing of dependencies; moreover, simple change in some component interface can lead to massive amount of fixes in multiple providers.
Is there a simpler/cleaner way to do this? How is this problem resolved within cake pattern?
Have you considered the following alternatives:
Use inner classes in Scala, as they automatically have access to their parent class member variables.
Restructuring your application in an actor based one, because you will immediately benefit of:
Hierarchy / supervision
Listening for creation / death of components
Proper synchronization when it comes to access mutable state
It will probably be helpful having some more code to provide a better solution, can you share a compiling subset of your code?
Let's say we have a program that has only two components: one contains the business logic of our program and the other one contains the dependency of this program, namely printing functionality.
we have:
trait FooBarInterface {
def printFoo: Unit
def printBar: Unit
}
trait PrinterInterface {
//def color: RGB
def print(s: String): Unit
}
For injecting the fooBar logic, the cake-pattern defines:
trait FooBarComponent {
//The components being used in this component:
self: PrinterComponent =>
//Ways for other components accessing this dependency.
def fooBarComp: FooBarInterface
//The implementation of FooBarInterface
class FooBarImpl extends FooBarInterface {
def printFoo = printComp.print("fOo")
def printBar = printComp.print("BaR")
}
}
Note that this implementation does not leave any field unimplemented and when it comes to mixing all these components together, we would have:
val fooBarComp = new FooBarImpl. For the cases where we only have one implementation, we don't have to leave fooBarComp unimplemented. we can have instead:
trait FooBarComponent {
//The components being used in this component:
self: PrinterComponent =>
//Ways for other components accessing this dependency.
def fooBarComp: new FooBarInterface {
def printFoo = printComp.print("fOo")
def printBar = printComp.print("BaR")
}
}
Not all components are like this. For example Printer, the dependency used for printing foo or bar needs to be configured and you want to be able to print text in different colours. So the dependency might be needed to change dynamically, or set at some point in the program.
trait PrintComponent {
def printComp: PrinterInterface
class PrinterImpl(val color: RGB) extends PrinterInterface {
def print(s:String) = ...
}
}
For a static configuration, when mixing this component, we could for example have, say:
val printComp = PrinterImpl(Blue)
Now, the fields for accessing the dependencies do not have to be simple values. They can be functions that take some of the constructor parameters of the dependency implementation to return an instance of it. For instance, we could have Baz with the interface:
trait BazInterface {
def appendString: String
def printBar(s: String): Unit
}
and a component of the form:
trait BazComponent {
//The components being used in this component:
self: PrinterComponent =>
//Ways for other components accessing this dependency.
def bazComp(appendString: String) : Baz = new BazImpl(appendString)
//The implementation of BazInterface
class BazImpl(val appendString: String) extends BazInterface {
def printBaz = printComp.print("baZ" + appendString)
}
}
Now, if we had the FooBarBaz component, we could define:
trait FooBarBazComponent {
//The components being used in this component:
self: BazComponent with FooBarComponent =>
val baz = bazComp("***")
val fooBar = fooBarComp
//The implementation of BazInterface
class BazImpl(val appendString: String) extends BazInterface {
def PrintFooBarBaz = {
baz.printBaz()
fooBar.printFooBar()
}
}
}
So we have seen how a component can be configured:
statically. (mostly the very low level dependencies)
from inside another component. (usually it's one business layer configuring another business layer, see "DEPENDENCIES THAT NEED USER DATA
" in here)
What differed in these two cases is simply the place where the configuration is taking place. One is for the low level dependencies at the very top level of the program, the other is for an intermediate component being configured inside another component. Question is, where should the configuration for a service like Print take place? The two options we have explored so far are out of the question. The way I see it, the only options we have is adding a Components-Configurer that mixes in all the components to be configured and returns the dependency components by mutating the implementations. Here is a simple version:
trait UICustomiserComponent {
this: PrintComponent =>
private var printCompCache: PrintInterface = ???
def printComp: PrintInterface = printCompCache
}
obviously we can have multiple such configurer components and do not have to have only one.

Can I define a class with no public constructor and place a factory method for this class objects in a different class in Scala?

For example (maybe a bit clumsy from a real life view, but just to illustrate):
"User" is a case class containing user name and id. Id can be never set manually, and a User class instance with no id set has no sense.
A UserBase class maintains users base and has a "getUser (name : String) : User" method returning a consistent User instance.
No one other than a UserBase object can know (well, someone can, but really shouldn't rely on this knowledge) a user's id, so constructing a User instance manually makes no sense (and can cause errors in future if someone accidentally hardcodes this and forgets). Moreover, having an orphan User instance not tracked by a UserBase is also undesired.
So the task is to make calling UserBase.getUser the only way to get a User instance.
Can this be implemented in Scala?
You have to put the classes in the same package or make them part of the same class or object. Then:
object O {
class C private[O] (val x: Int) { }
object D { def apply(i:Int) = new C(i) }
def getC(i:Int) = new C(i)
}
scala> O.D(5)
res0: O.C = O$C#5fa6fb3e
scala> new O.C(5)
<console>:10: error: constructor C cannot be accessed in object $iw
new O.C(5)
scala> O.getC(5)
res1: O.C = O$C#127208e4
A case class automatically gets several features, including a companion object with an apply() method for constructing instances of the class. This is why you don't need "new" with case classes. If you try to make an explicit companion with apply() you will get error: method apply is defined twice
If you want to make your own factory method then you should not use case classes. You can still have all of the same features (toString, apply, unapply, etc) but you will have to implement them manually and to your own specification.
You don't actually clarify what a 'base' is in this context, but given your description it sounds like it's really nothing more than a factory for users.
The usual place to put a factory for a class is in the companion object (This is how case classes do it, but the technique isn't restricted to just case classes)
class User private(val id: Int, val name: String) {
...
}
object User {
private def nextId() : Int = ...
def apply(name: String) = new User(nextId(), name)
}
//now create one:
val u = User("Ivan")
Of course, if the User object is immutable (highly recommended), then there's very little reason to hide the id member. You're probably also going to want a (restricted) method to construct a User with a specified ID, mostly for reasons of unit testing.
Working with companions like this, it's also unlikely that you'll still need a distinct UserBase factory. Having your factory named the same as the instances it produces will result in cleaner code.