Scala factory pattern improve design - scala

I have written the following class and corresponding companion object:
class Tile(val tileCoordinate: Int, val pieceOnTile: Piece) {
override def toString(): String = {
if(isOccupied()) {
pieceOnTile.toString()
}
"-"
}
def isOccupied(): Boolean = pieceOnTile != null
}
object Tile {
def apply(coordinate: Int, piece: Piece): Tile = {
new Tile(coordinate, piece)
}
def apply(coordinate: Int): Tile = {
new Tile(coordinate, ??) // what is the best design here?An Option?
}
}
My question is, when the factory method to create a Tile without a piece on it is invoked, what is the appropriate argument to pass in to the Tile constructor? I don't want to pass in null, that seems like a poor design choice. Should I have the main constructor take an Option[Piece] and pass in None?
That seems sort of ugly too because when I want to create a tile I'd need to say:
val t = Tile(1, Some(new Knight()));

Personally I would ditch the class and companion object completely, and instead go for a case class:
case class Tile(tileCoordinate: Int, pieceOnTile: Option[Piece] = None) {
override def toString(): String = pieceOnTile.map(_.toString).getOrElse("-")
}
This allows you to later do the following when checking for values:
... match {
case Tile(c, Some(p)) => ...
case Tile(c, None) => ...
}
Having the second parameter default to None allows you to call it as Tile(coord), Tile(coord, None) and Tile(coord, Some(piece))

I would code the following:
class Tile(val tileCoordinate: Int, val pieceOnTile: Option[Piece]) {
// A little bit more scala-idiomatic, and a probable bug corrected
override def toString(): String = pieceOnTile.map(_.toString).getOrElse("-")
def isOccupied : Boolean = pieceOnTile.isDefined
}
object Tile {
def apply(coordinate: Int, piece: Piece): Tile = {
new Tile(coordinate, Some(piece))
}
def apply(coordinate: Int): Tile = {
new Tile(coordinate, None)
}
}

If pieceOnTile is optional, then you should use Option for sure. If you don't like the ugliness of having to wrap the Pieces in Some when creating new instances of Tile, then hide it within apply:
class Tile(val tileCoordinate: Int, val pieceOnTile: Option[Piece]) { ... }
object Tile {
def apply(coordinate: Int, piece: Piece): Tile = new Tile(coordinate, Some(piece))
def apply(coordinate: Int): Tile = new Tile(coordinate, None)
}
Then even isOccupied will look more scala-like:
def isOccupied() : Boolean = pieceOnTile.isDefined

Another alternative could be to define empty/occupied cases as separate case classes:
sealed abstract class Tile(val isOccupied: Boolean)
case object EmptyTile extends Tile(false) {
override def toString: String = "-"
}
case class OccupiedTile(piece: Piece) extends Tile(true) {
override def toString: String = piece.toString
}
You can use EmptyTile, create OccupiedTile(piece) and you can check a Tile either by the isOccupied flag or by pattern matching.
One possible advantage of this approach is that if you add more methods that assume a contained piece, you will not have to add checks of occupiedness to each method because you could define them only in OccupiedTile in the first place.

Related

Changing implicit value in scala response of nested object

I have a controller
def getCars(notation: Option[Boolean] = Some(false)) = identified.auth(hasOceanScope).async { implicit request =>
carService.getCars().map {
case Seq() => Response.NotFound
case cars => Response.Ok(cars)
}
}
Car case class looks like this:
case class Car(
name: String,
createdAt: LocalDateTimeOffset,
wheels: Seq[Wheel]
)
object Car{
implicit val wheelFormat = Wheel.format
implicit def toOffset(date: LocalDateTime): LocalDateTimeOffset = LocalDateTimeOffset.apply(date)
implicit val format = Json.format[Car]
case class Wheel(
name: String,
createdAt: LocalDateTimeOffset
)
object Wheel{
implicit val format = Json.format[Wheel]
implicit def toOffset(date: LocalDateTime): LocalDateTimeWithOffset = LocalDateTimeWithOffset.apply(date)
)
When notation query parameter is true -> want to return createdAt Car object and Wheel object field with notation => 2022-10-22T00:00:00#1
When notation query parameter is false -> want to return createdAt Car object and Wheel object field without notation => 2022-10-22T00:00:00
That is why I have create two formats in LocalDateTimeOffset object
case class LocalDateTimeWithOffset(dt: LocalDateTime, offset: Int) {
val localDateTimeWithOffsetReads: Reads[LocalDateTimeWithOffset] = Reads.of[String].flatMap {
str => if (str.contains("#")) {
val (dt, offset) = str.splitAt(str.indexOf("#"))
Reads.pure(LocalDateTimeWithOffset(LocalDateTime.parse(dt), offset.drop(1).toInt))
} else {
Reads.pure(LocalDateTimeWithOffset(LocalDateTime.parse(str), 1))
}
}
val localDateTimeWithOffsetWrites: Writes[LocalDateTimeWithOffset] = new Writes[LocalDateTimeWithOffset] {
override def writes(a: LocalDateTimeWithOffset): JsValue = JsString(a.dt.format(dateTimeUTCFormatter) + s"#${a.offset}")
}
val localDateTimeWithOffsetWritesOff: Writes[LocalDateTimeWithOffset] = new Writes[LocalDateTimeWithOffset] {
override def writes(a: LocalDateTimeWithOffset): JsValue = JsString(a.dt.format(dateTimeUTCFormatter))
}
val localDateTimeWithoutOffsetFormat: Format[LocalDateTimeWithOffset] = Format(localDateTimeWithOffsetReads, localDateTimeWithOffsetWritesOff)
val localDateTimeWithOffsetFormat: Format[LocalDateTimeWithOffset] = Format(localDateTimeWithOffsetReads, localDateTimeWithOffsetWrites)
implicit var format: Format[LocalDateTimeWithOffset] = localDateTimeWithoutOffsetFormat
}
But how can I use two different formats from controller based on notation query parameter value?
Well just looking at your question's title, changing implicit value is not something you would see Scala developers do, because compiler is responsible to lookup for implicit values, and you would definitely want to avoid ambiguous implicits found error. instead, you see developers using something so called type class instance constructor or something similar. This is how it works in your case:
Assuming you have a class A, which can be formatted to/from Json in many ways:
case class A(field1: String) // could have more fields
object A {
val formatFirstApproach: Format[A] = ???
val formatSecondApproach: Format[A] = ???
// note that the above instances are not implicit
def getFormat(somePredicate: Boolean): Format[A] = {
// input parameters can be anything, these are the parameters you need,
// in order to be able to decide which instance to return
if (somePredicate) formatFirstApproach else formatSecondApproach
}
}
And then, given a class B which has an instance variable of type A in it, you can use the type class instance constructor:
case class B(a: A, field2: Int)
object B {
// this is the type class instance constructor, since it constructs an instance of a type class (Format in this case)
implicit def format(implicit aFormatter: Format[A]): Format[B] = Json.format
}
And the thing is, you probably would not care about the serialization unless in the controller layer, so in the controller layer you can do:
def someApi(flag: Boolean) = Action async { req =>
implicit val aFormatter = A.getFormat(flag) // that's it, you don't need to mention anything more anywhere
businessLogic().map {
case Seq() => Response.NotFound
case cars => Response.Ok(Json.toJson(cars))
}
}

Can I avoid using structural typing in this scenario?

I have some code that uses both a third-party library and my own library. In my own library, I don't want to have a dependency on the third-party one so I want one of my methods to accept a more generic type as a parameter. Unfortunately, I cannot extend or mixin a trait to the 3rd party classes since they are generated using factory methods & the classes are final.
I can get around this issue by using structural typing but I was wondering if there is an alternative? I don't want to have to iterate through each record returned by the factory method and "new up" instances of a separate type if possible.
I've boiled it down to a scenario like the following:
Third-party library code that cannot be changed
// Class inside library cannot be extended due to it being 'final'
final class SpecificRecord(val values: IndexedSeq[String]) {
def get(i: Int): String = {
values(i)
}
}
// A companion object simply to create some sample data in an iterator
object SpecificRecord{
def generateSpecificRecords(): Iterator[SpecificRecord] = new Iterator[SpecificRecord] {
var pointerLocation: Int = 0
private val state = IndexedSeq(
IndexedSeq("Row1 Col1", "Row1 Col2", "Row 1 Col3"),
IndexedSeq("Row2 Col1", "Row2 Col2", "Row 2 Col3")
)
override def hasNext: Boolean = {
if (pointerLocation < state.length) true else false
}
override def next(): SpecificRecord = {
val record = new SpecificRecord(state(pointerLocation))
pointerLocation += 1
record
}
}
}
As you can see above, the SpecificRecord class is final and the specificRecords val is an Iterator with a bunch of SpecificRecord in it. I don't want to have to iterate through each specificRecord and create a new, more generic, object if possible.
My code that can be changed
val specificRecords: Iterator[SpecificRecord] = SpecificRecord.generateSpecificRecords()
type gettable = {
def get(i: Int): String
}
def printRecord(records: Iterator[gettable]): Unit = {
for (record <- records) {
println(record.get(0), record.get(1), record.get(2))
}
}
printRecord(specificRecords)
This correctly prints:
(Row1 Col1,Row1 Col2,Row 1 Col3)
(Row2 Col1,Row2 Col2,Row 2 Col3)
I have a printRecord method that doesn't really care what type is passed in, as long as it has a method like get(Int): String. This a pretty decent solution but I was wondering if it would be possible to do this without structural typing?
This is a typical use case for type classes.
trait Gettable[T] {
def get(t: T, i: Int): String
}
object Gettable {
implicit object SpecificRecordGettable extends Gettable[SpecificRecord] {
def get(sr: SpecificRecord, i: Int) = sr.get(i)
}
}
def printRecord[T : Gettable](records: Iterator[T]) = {
val getter = implicitly[Gettable[T]]
records.foreach { record =>
println(getter.get(record, 0), getter.get(record, 1), getter.get(record, 2))
}
}
This is a bit more verbose than your approach with structured types: for each type you want to be gettable, you have to add an implicit object implementing the get, but it works without reflection, which is a good thing.
Another advantage of this approach is its flexibility: the underlying type does not have to have get specifically, you can implement anything with the implicit. E.g.:
implicit object ArrayGettable extends Gettable[Array[String]] {
def get(a: Array[String], i: Int) = a(i)
}
implicit object ProductGettable extends Gettable[Product] {
def get(p: Product, i: Int) = p.productIterator.drop(i).next.toString
}
Now, your printRecord works with string arrays too (as long as they have at least three elements), and even tuples and case classes.
Try this:
printRecord[Product](Iterator((1,2, "three"), ("foo", "bar", 5)))
Or this:
case class Foo(x: String, y: Int, z: Seq[Int])
printRecord[Product](Iterator(Foo("bar", 1, 1::2::Nil), ("foo", "bar", "baz")))
A similar but a little bit less verbose approach is to just define an implicit 'getter' without bothering with type classes:
def printRecord[T](records: Iterator[T])(implicit getter: (T,Int) => String) =
records.foreach { record =>
println(getter(record, 0), getter(record, 1), getter(record, 2))
}
object Getters {
implicit def getter(sr: SpecificRecord, i: Int) = sr.get(i)
implicit def getter(a: Array[String], i: Int) = a(i)
implicit def getter(p: Product, i: Int) = p.productIterator.drop(i).next.toString
}
This is fairly equivalent in usage, the difference being that type class lets you potentially define more than one method, but if you only ever need get, then this would save you a few keystrokes.

Using abstract type parameters with a factory function to generate new objects of the correct type

I have an abstract class that will be implemented in many different ways. I am trying to create a method that can take any one of these implementors as a parameter, and return a new instance of the same type. I am trying to implement this behavior by passing a "factory" function to the method that yields a new object of an abstract type (which will be set appropriately in each implementor).
I've tried to breakdown the problem I'm having into the following code:
My parent abstract class:
abstract class Parent(val x: Int) {
type Self <: Parent
def factory: Int ⇒ Self
def me = "Parent"
}
An example of a Child class:
class Child(x: Int) extends Parent(x) {
type Self = Child
override def factory: Int ⇒ Self = {
(v: Int) ⇒ new Child(v)
}
override def me = "Child"
}
I'm trying to use the Self type parameter as a way to ensure that the factory method generates an object of the correct type.
Now the method itself:
object Parent {
def transform[T <: Parent](input: T#Self, factory: (Int ⇒ T#Self)): T#Self = {
//do stuff with input
input.me
val result = 123
factory(result)
}
}
Now when I try to actually wire this all up:
class Transformer[T <: Parent] {
var everyone: List[T#Self] = List.empty
def start() = {
val updated = for (e ← everyone) yield {
Parent.transform[T](e, e.factory)
}
everyone = updated
}
}
I get a compile error when I try to pass the factory to the transform method
Type mismatch, expected (Int) => T#Self, actual (Int) => Parent.this.Self
I've tried a variety of things to get this to work, but no luck. I'm very new to this still, so it's possible (probably likely) I'm trying to do something crazy here. A better alternative would be greatly appreciated, but I'm still interested to see if it's possible to get something like this to work. The end goal is to have a way for the transform method to generate new instances of the exact same type that was provided as a parameter.
Any help is greatly appreciated. Thanks!
I'm trying to use the Self type parameter as a way to ensure that the
factory method generates an object of the correct type.
This reminds me of tpolecat's Returning the "Current" Type in Scala:
I have a type hierarchy … how do I declare a supertype method that returns the “current” type?
We can adapt the F-Bounded Types approach discussed in that post to your Parent and Child hierarchy:
trait Parent[A <: Parent[A]] { this: A =>
def x: Int
def factory: Int ⇒ A
def me = "Parent"
}
class Child(override val x: Int) extends Parent[Child] {
override def factory = (v: Int) ⇒ new Child(v)
override def me = "Child"
}
class OtherChild(override val x: Int) extends Parent[OtherChild] {
override def factory = (v: Int) ⇒ new OtherChild(v)
override def me = "OtherChild"
}
object Parent {
def transform[A <: Parent[A]](input: A): A = {
//do stuff with input
input.me
val result = 123
input.factory(result)
}
}
And then, following the Bonus Round: How do we deal with collections? section, your Transformer becomes something like this:
class Transformer {
import scala.language.existentials
var everyone = List[A forSome { type A <: Parent[A] }](new Child(1), new OtherChild(2))
def start() = {
val updated = everyone.map(Parent.transform(_))
everyone = updated
}
}

How to set instance members from constructor in Scala?

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.

Method polymorphism

I am trying to write a generic method f[T](id:String) that is something like this:
case class A(x:String)
case class B(y:String)
case class C(z:String)
def f[T](id:String): T = { /* equivalent to T(id) */ }
val result1:A = f[A]("123") // returns A("123")
val result2:B = f{B]("345") // returns B("345")
val result3:C = f[C]("567") // returns C("567")
Unfortunately I cannot figure out how to work with the type T inside the method, besides using reflection. By "working with the type T" i mean for example being able to do something like the following, which I know doesn't work (for illustration purposes only):
T match {
case A => A(id)
case B => B(id)
}
or simply invoke T(ID) to create a new object of whatever type T is.
I can of course break up this into three methods:
def f1(id:String): A = { A(id) }
def f2(id:String): B = { B(id) }
def f3(id:String): C = { C(id) }
val result1:A = f1("123") // returns A("123")
val result2:B = f2("345") // returns B("345")
val result3:C = f3("567") // returns C("567")
but I'm hoping there is a way to keep it as one generic method to avoid some ugly boilerplate code duplication, and still be nearl as fast as the tree method version.
If you do not want to use reflection (ClassTag or TypeTag), you could use a Factory type class to achieve the desired functionality (unless it defeats the purpose of your generic function by generating a lot of duplicated simple code ;)).
case class A(s: String)
case class B(s: String)
case class C(s: String)
trait Factory[T] extends ((String) => T) {
def apply(arg: String): T
}
object Factory {
implicit object AFactory extends Factory[A] {
override def apply(arg: String): A = A(arg)
}
implicit object BFactory extends Factory[B] {
override def apply(arg: String): B = B(arg)
}
implicit object CFactory extends Factory[C] {
override def apply(arg: String): C = C(arg)
}
}
def create[T : Factory](arg: String): T = implicitly[Factory[T]].apply(arg)
create[A]("foo") | -> res0: A = A(foo)