Scala: lock extended class - scala

I'd like to "lock" a class, which is extended from a trait. Is it possible in Scala?
For example I have:
trait A {
val boris: String
val john: String
val number: Int
}
class B extends A {
// do something with these values
}
but can I ensure, that in class B no new values will be added if those aren't declared in trait A?
Thanks for your answers.

You cannot.
But if you simply mark the trait as sealed and provide a default implementation:
sealed trait A { val boris: String }
final class B(val boris: String) extends A {}
then people are free to create implicit value classes that make it look like new functionality has been added (except without actually creating the class):
implicit class MyB(val underlying: B) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B("fish")).sirob // "hsif"
You can also let the classes take a type parameter as a marker if you want to keep them straight at compile-time (though not runtime):
sealed trait A[T] { val boris: String }
final class B[T](val boris: String) extends A[T] {}
implicit class MyB(val underlying: B[Int]) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B[Int]("fish")).sirob // "hsif"
(new B[Char]("fish")).sirob // error: value sirob is not a member of B[Char]
So you could--especially with 2.10--simply lock everything and let users enrich the original interface this way.
I'm not sure if this covers your intended use case, though; it doesn't provide any inheritance.

Based on your example and my guess at what you are actually trying to do, you may want to consider just using case classes.
Extending a case class is generally avoided (I think it will spit out deprecation warnings if you try), so that will prevent people from wanting to extend your class in order to add functionality.
Translating your example into a case class:
case class A (boris: String, john: String, number: Int)
Then instead of extending A to change its values, you'd just make a new instance, e.g.
val a2 = someOtherA.copy(john="Doe")

Related

Why can we use a new class as type of parent class in Scala?

In the simplified implementation of Actor in the RedBook, they use node-based MPSC node based queue for Actor. They define the node by this line of code:
private class Node[A](var a: A = null.asInstanceOf[A]) extends AtomicReference[Node[A]]
But how can we use Node[A] as the type parameter of AtomicReference because we do not have class Node[A] yet? Is it a way of declaring recursive type in Scala?
You are allowed to use recursion in class/trait definition:
abstract class Example[A] extends (A => Example[A])
def example(prefix: String): Example[String] = new Example[String] {
def apply(s: String): Example[String] = {
val t = prefix + s
println(t)
example(t)
}
}
example("1")("2")("3")
//12
//123
If you have X extends F[X] then you ended up with something known to C++ developers as curiously recurring template pattern and in type theory in general as F-bounded types.
You can find it even in Java because each enum X is underneath abstract class X extends Enum[X].

Organizing Scala implicits associated with a type

I'd like to introduce some types to represent possible values of a field in a larger type. This fields needs to be possible to encode/decode to/from JSON and also be able to be written/read to a database.
I'm still new to Scala and the type I would like is the sum type Status = NotVerified | Correct | Wrong. Since I want to have a string representation associated with each constructor, I created a sealed case class with a String parameter and then objects extending that case class. In order to be able to encode/decode, I also need to have implicits, but I'm not sure how to structure this. I could put them in a new object inside the object, like this:
sealed case class Status(name: String)
object Status {
object NotVerified extends Status("not_verified")
object Correct extends Status("correct")
object Wrong extends Status("wrong")
object implicits {
implicit val encodeStatusJson: Encoder[Status] =
_.name.asJson
implicit val decodeStatusJson: Decoder[Status] =
Decoder.decodeString.map(Status(_))
implicit val encodeStatus: MappedEncoding[Status, String] =
MappedEncoding[Status, String](_.name)
implicit val decodeStatus: MappedEncoding[String, Status] =
MappedEncoding[String, Status](Status(_))
}
}
… and then explicitly import these where needed, but that's quite … explicit.
What is a good way of organizing such collections of a type + implicits?
The common approach is to define a sealed trait:
sealed trait Status {
def name: String
}
object Status {
case object NotVerified extends Status {
val name = "not_verified"
}
case object Correct extends Status {
val name = "correct"
}
case object Wrong extends Status {
val name = "wrong"
}
}
Or a sealed abstract class, which may look nicer in the current Scala versions:
sealed abstract class Status(val name: String)
object Status {
case object NotVerified extends Status("not_verified")
case object Correct extends Status("correct")
case object Wrong extends Status("wrong")
}
To avoid the need to import implicits, they can be placed directly in the companion object of the type. See also the question Where does Scala look for implicits? for more details, especially the section Companion Objects of a Type.
And yes, defining implicits for enumerations like that easily gets repetitive. You have to resort to reflection or macros. I recommend using the Enumeratum library, which also has integrations with Circe and Quill.
Here is an example for Circe:
import enumeratum.values._
sealed abstract class Status(val value: String) extends StringEnumEntry {
def name: String = value
}
object Status extends StringEnum[Status] with StringCirceEnum[Status] {
val values = findValues
case object NotVerified extends Status("not_verified")
case object Correct extends Status("correct")
case object Wrong extends Status("wrong")
}
And you can use it without defining any encoders/decoders explicitly or importing anything from Status:
scala> import io.circe.syntax._
scala> val status: Status = Status.Correct
status: Status = Correct
scala> status.asJson
res1: io.circe.Json = "correct"
scala> Decoder[Status].decodeJson(Json.fromString("correct"))
res2: io.circe.Decoder.Result[Status] = Right(Correct)
If you add an apply method you can create the appropriate Status from a String, which should make the Decoder work properly. And making Status abstract
sealed abstract class Status(name: String)
object Status {
object NotVerified extends Status("not_verified")
object Correct extends Status("correct")
object Wrong extends Status("wrong")
def apply(name: String): Status = name match {
case "not_verified" => NotVerified
case "correct" => Correct
case _ => Wrong
}
}
I think your existing implicits will still work, but I don't know those specific libraries...

Type Class Pattern alternative for enriching ADT with methods in Scala

I wrote a basic Algebraic Data Type defined as follows
sealed trait Fruit {def name: String}
case class Apple(name: String) extends Fruit
case class Orange(name: String, color: String) extends Fruit
What I'd love to do is to define a common method across Apple and Orange. So I decided to offer this feature by a Type Class pattern.
sealed trait ServingFruit[T] {
def peel(fruit: T): String
}
object FruitManager {
def retrievePeelColor[T: ServingFruit](fruit: T): String =
implicitly[ServingFruit[T]].peel(fruit)
implicit object ApplePeelColor extends ServingFruit[Apple] {
def peel(fruit: Apple): String = "GREEN"
}
implicit object OrangePeelColor extends ServingFruit[Orange] {
def peel(fruit: Orange): String = fruit.color
}
}
For a necessary (and unfortunate) constraint I have to handle fruits as bounded instances of the shared base trait Fruit
def myCodeMethod[F <: Fruit](fruit: F, out: String) = {
import FruitManager._
FruitManager.retrievePeelColor(fruit)
}
And it brings me to the following (somehow expected) exception.
could not find implicit value for evidence parameter of type my.path.to.fruit.ServingFruit[F] [error]FruitManager.retrievePeelColor(fruit)
Then, AFAIU here and here Type Class Pattern is type independent and perhaps the latter is not well fitting my scenario.
The point is I'm struggling on figuring out a valuable solution to integrate my ADT with a common method available also to the base trait and - at the same time - I'd like to avoid providing the methods within the ADT (I'd try to stay FP oriented) and to use such workarounds as to add an additional Fruit converter to my Type Class.
Any help'd be really appreciated, thank you.
Andrea
You need to make the type class witness passed into retrievePeelColor as an implicit parameter:
scala> def retrievePeelColor[T](fruity: T)(implicit peeler: ServingFruit[T]) = peeler.peel(fruity)
retrievePeelColor: [T](fruity: T)(implicit peeler: ServingFruit[T])String
scala> retrievePeelColor(Apple("granny smith"))
res0: String = GREEN
scala> retrievePeelColor(Orange("bloody", "RED"))
res1: String = RED
And as for the design: I'm not an experienced design guy, but I wouldn't say that having some methods in a sealed trait isn't "FP style". If only fruits are peelable, and there are finitely many, it's OK to have one place for peel, IMHO (by this I'm talking about a method in Fruit matching on this, or a static member in the Fruit companion object).

May mix-in traits extend case classes from a technical perspective?

I read repeatedly on SO that case classes shall not be extended because a case class implements an equality method by default and that leads to issues of equality. However, if a trait extends a case class, is that also problematic?
case class MyCaseClass(string: String)
trait MyTrait extends MyCaseClass
val myCT = new MyCaseClass("hi") with MyTrait
I guess it boils down to the question, whether MyTrait is only forced to be mixable only into instantiations of MyCaseClass or whether MyTrait is inheriting the class members (field values and methods) of MyTrait and thus overwriting them. In the first case it would be okay to inherit from MyCaseClass, in the latter case it would not be okay. But which one is it?
To investigate, I advanced my experiment with
trait MyTrait extends MyCaseClass {
def equals(m: MyCaseClass): Boolean = false
def equals(m: MyCaseClass with MyTrait): Boolean = false
}
val myC = new MyCaseClass("hi")
myCT.equals(myC) // res0: Boolean = true
letting me to believe that the equals of MyCaseClass was used, not the one of MyTrait. This would suggest that it is okay for a trait to extend a case class (while it is not okay for a class to extend a case class).
However, I am not sure whether my experiment is legit. Could you shed some light on the matter?
Basically, trait can extend any class, so it's better to use them with regular classes (OOP-style).
Anyway, your equals contract is still broken regardless of your trick (note that standard Java's equals is defined on Any, that is used by default let's say in HashMap or even ==):
scala> trait MyTrait extends MyCaseClass {
| override def equals(m: Any): Boolean = false
| }
defined trait MyTrait
scala> val myCT = new MyCaseClass("hi") with MyTrait
myCT: MyCaseClass with MyTrait = MyCaseClass(hi)
scala> val myC = new MyCaseClass("hi")
myC: MyCaseClass = MyCaseClass(hi)
scala> myC.equals(myCT)
res4: Boolean = true
scala> myCT.equals(myC)
res5: Boolean = false
Besides, Hashcode/equals isn't the only reason...
Extending case class with another class is unnatural because case class represents ADT so it models only data - not behavior.
That's why you should not add any methods to it (in OOD terms case classes are designed for anemic approach). So, after eliminating methods - a trait that can only be mixed with your class becomes nonsense as the point of using traits with case classes is to model disjunction (so traits are interfaces here - not mix-ins):
//your data model (Haskell-like):
data Color = Red | Blue
//Scala
trait Color
case object Red extends Color
case object Blue extends Color
If Color could be mixed only with Blue - it's same as
data Color = Blue
Even if you require more complex data, like
//your data model (Haskell-like):
data Color = BlueLike | RedLike
data BlueLike = Blue | LightBlue
data RedLike = Red | Pink
//Scala
trait Color extends Red
trait BlueLike extends Color
trait RedLike extends Color
case class Red(name: String) extends RedLike //is OK
case class Blue(name: String) extends BlueLike //won't compile!!
binding Color to be only Red doesn't seem to be a good approach (in general) as you won't be able to case object Blue extends BlueLike
P.S. Case classes are not intended to be used in OOP-style (mix-ins are part of OOP) - they interact better with type-classes/pattern-matching. So I would recommend to move your complex method-like logic away from case class. One approach could be:
trait MyCaseClassLogic1 {
def applyLogic(cc: MyCaseClass, param: String) = {}
}
trait MyCaseClassLogic2 extends MyCaseClassLogic {
def applyLogic2(cc: MyCaseClass, param: String) = {}
}
object MyCaseClassLogic extends MyCaseClassLogic1 with MyCaseClassLogic2
You could use self-type or trait extends here but you can easily notice that it's redundant as applyLogic is bound to MyCaseClass only :)
Another approach is implicit class (or you can try more advanced stuff like type-classes)
implicit class MyCaseClassLogic(o: MyCaseClass) {
def applyLogic = {}
}
P.S.2 Anemic vs Rich. ADT is not precisely anemic model as it applies to immutable (stateless) data. If you read the article, Martin Fowler's approach is OOP/OOD which is stateful by default - that's what he assumes in most of the part of his article by implying that service layer and business layer should have separate states. in FP (at least in my practice) we still separate domain logic from service-logic, but we also separate operations from data (in every layer), which is another matter.
Extending case classes is a bad practice (generally), because it has concrete meaning -- "data container" (POJO / ADT). For example, Kotlin does not allow to do that.
Also, if you really want some trait to extend case class, you'd better use requires dependency (to avoid pitfalls with cases classes inheritance):
scala> case class A()
defined class A
scala> trait B { self: A => }
defined trait B
scala> new B{}
<console>:15: error: illegal inheritance;
self-type B does not conform to B's selftype B with A
new B{}

get the class of "case class" from it's companion

I have the following code:
trait Base[A,B] {
def name: String
}
trait BaseCompanion[A,B] {
def classOfBase: Class[_ <: Base[A,B]] // Can I implement something generic here ?
}
case class First(name: String) extends Base[Int,String]
object First extends BaseCompanion[Int,String] {
override def classOfBase: Class[_ <: Base[Int, String]] = classOf[First] // Can this part be generic ?
}
I don't want to override the classOfBase method in every concrete class that will extend BaseCompanion.This can be achieved by changing BaseCompanion to:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
}
object First extends BaseCompanion[Int,String,First]
But I don't really like this solution, is there a way to do this without changing the signature of BaseCompanion and implement something generic inside the it ?
By the way today Companion object of any case class "defines" apply(...) method. Given the example above there will be a method similar to this:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
/* No need to implement in the companion of a case class that extends Base */
def apply(name: String): Base[A,B]
}
The return type of this apply method is known to the Companion perhaps there is a way to use this information.
Yes, it can be done with this change:
def classOfBase = this.getClass.getMethods.find(_.getName == "apply").get.
getReturnType.asInstanceOf[Class[_ <: Base[A,B]]]
Note that this assumes there is precisely one apply method. In practice, you should check this assumption.
Assuming that if what you want would work, the following would be possible:
case class First(name: String) extends Base[Int, String]
object First extends BaseCompanion[Int, String]
assert(First.baseClass == classOf[First])
Now if that would work, what would stop you from doing the following?
class Second extends BaseCompanion[Int, String]
val second = new Second
println(second.baseClass)
or
// case class Third not defined
object Third extends BaseCompanion[Int, String]
println(Third.baseClass)
What would that result in? Second and Third are not a companion object with an associated class. Second is a class itself!
The problem is that you cannot force your BaseCompanion trait to only be inherited by something that is a companion object. BaseCompanion therefore cannot use the special relation that companion objects and associated classes have. If you want information about the associated class with a companion object, you have to give BaseCompanion that information manually in the definition of your companion object.
The Scala compiler won't allow you to do this. You can work around this with reflection if you want, but whatever solution remains that accomplishes this has to take into account that you are effectively creating unpredictable runtime behaviour. In my opinion, it's best to just help the compiler figure it out, and supply the proper information at compile time.