I have a non-case class that I'm trying to test for equality. It has > 22 fields so I can't use a case class in Scala 2.10.x:
class Row(
val date: String,
val time: String,
val orderId: String,
val id: String) extends Serializable {
override def toString: String = {
ToStringBuilder.reflectionToString(this);
}
}
What's the simplest way of me implementing an == or equals function so I can test row1 == row2?
You have no choice but to implement your own equals and therefore hashcode method (not easy) since you cannot implement a case class. This article should help you: object equality. These are the factors you need to bear in mind:
Take care with the type signature of the equals method
Override the hashCode()
Avoid dependencies on mutable state
Should implement and use a canEqual method if the class is non-final
In your example, Row is not a case class. It is a standard class, and thus checked for equality in the standard Java way.
Try this:
case class Row(date: String,
time: String,
orderId: String,
id: String)
Another option (though, since Row isn't a case class, still involves writing field-by-field comparison code) would be to provide an instance of the Scalaz Equal typeclass. This has the advantage of being type-safe. For more information, check out the Learning Scalaz series. (The "typeclasses 102" section has an example of providing an Equal instance for a type).
Related
Say I have a case class that has a type parameter T:
case class ProdutOption[T](name: String, value:T)
And this case class is contained in another case class like:
case class Product[T](id: String, options: Set[ProductOption[T]])
What is the correct way to model this?
I want my options parameter to be able to have different types of T... I don't want all items in the set to be forced to a specific type.
Is this scenario possible to model using type parameters like this?
Everything depends on whether your set of possible option types is closed (i.e. known statically) or open (unknown until runtime) and how exactly do you want to process these options.
If you can enumerate all possible options, use an ADT (algebraic data type):
sealed trait ProductOption[+T] {
def name: String
def value: T
}
object ProjectOption {
case class SomeNumericOption(value: Int) extends ProductOption[Int] {
def name: String = "numeric"
}
case class SomeTextualOption(value: String) extends ProductOption[String] {
def name: String = "textual"
}
}
case class Product(id: String, option: Set[ProductOption[_]])
You can then process these options in a type-safe way using pattern matching.
If your option hierarchy is not known then you should introduce some method for processing this option into the base trait, which will no longer be sealed:
trait ProductOption {
def name: String
def processMe(): Whatever = ...
}
case class Product(id: String, option: Set[ProductOption])
What exactly would processMe do depends on your use case.
This is a classical example of so called expression problem.
It's a little unclear what exactly you're looking for, but it may be useful to consider covariance for ProductOption:
case class ProductOption[+T](name: String, value: T)
This says that if S is a supertype of T, ProductOption[T] is a subtype of ProductOption[S].
Specifically this then means that a Product[Any] allows options to be any kind of ProductOption:
Product("my favorite product", Set(ProductOption[String]("color", "blue"), ProductOption[ShirtSize]("size", ShirtSize.TwoXL)) // type is Product[AnyRef]
I used to develop on java, but now I stucked with one thing.
I have some kind of flexible value system.
trait Value[T] {
def get:T
}
I have implementations of this, for example
class StringValue(value : String) extends Value[String] {
override def get : String = value
}
class NumberValue(value : Int) extends Value[Int] {
override def get: Int = value
}
Then, I'm passing Value to Map, but I don't need parameter, as I don't know which implementation should be used.
case class Foo(attributes: Map[Attribute, Value)
On this step I get an error, because Value should have parameter.
I understand that it's might be fundamental difference between Java and Scala, so what should I use in this case?
You can use existential types: Map[Attribute, Value[_]] to express this, but they aren't trivial to use.
I understand that it's might be fundamental difference between Java and Scala
It isn't: in Java you can write Map<Attribute, Value>, but you shouldn't. Instead, you want Map<Attribute, Value<?>> which is more limited than Scala, but expresses the same idea.
You can try something along the lines of
case class Foo[K, V](attributes: Map[K, V])
You need to have the class have generic typed parameters in order to be able to use generic parameters.
I'm trying to discover the differences between using a value class or a case class in a given scenario. Suppose I want to model the integers mod 5 as a unique datatype. The question is which one I should begin with...
class IntegerMod5(val value: Int) extends AnyVal
case class IntegerMod5(value: Int)
Regardless, it seems that I can create an implementation of Numeric fairly easily. With the case class approach, then, I can simply do this:
case class IntegerMod5(value: Int)(implicit ev: Numeric[IntegerMod5]) {
import ev.mkNumericOps
}
However, it seems to be a much more difficult endeavour with value classes, mainly as the benefit is to avoid object creation. Thus, something like
implicit class IntegersMod5Ops(value: IntegerMod5)(implicit ev: Numeric[IntegerMod5]) {
import ev.mkNumericOps
}
Would appear to largely defeat the purpose. (Not sure if it even works, actually.)
The question is that is it possible to use Numeric with a value class, or will I have to bite the bullet and use a case class?
You don't need implicit ev: Numeric[IntegerMod5] as an argument, just define it in the companion object:
object IntegerMod5 {
implicit val numeric: Numeric[IntegerMod5] = ...
}
It will be automatically picked up when you use arithmetic operations on IntegerMod5s, and because it's a val, it's only initialized once (you can use object as well).
I have an application based on Squeryl. I define my models as case classes, mostly since I find convenient to have copy methods.
I have two models that are strictly related. The fields are the same, many operations are in common, and they are to be stored in the same DB table. But there is some behaviour that only makes sense in one of the two cases, or that makes sense in both cases but is different.
Until now I only have used a single case class, with a flag that distinguishes the type of the model, and all methods that differ based on the type of the model start with an if. This is annoying and not quite type safe.
What I would like to do is factor the common behaviour and fields in an ancestor case class and have the two actual models inherit from it. But, as far as I understand, inheriting from case classes is frowned upon in Scala, and is even prohibited if the subclass is itself a case class (not my case).
What are the problems and pitfalls I should be aware in inheriting from a case class? Does it make sense in my case to do so?
My preferred way of avoiding case class inheritance without code duplication is somewhat obvious: create a common (abstract) base class:
abstract class Person {
def name: String
def age: Int
// address and other properties
// methods (ideally only accessors since it is a case class)
}
case class Employer(val name: String, val age: Int, val taxno: Int)
extends Person
case class Employee(val name: String, val age: Int, val salary: Int)
extends Person
If you want to be more fine-grained, group the properties into individual traits:
trait Identifiable { def name: String }
trait Locatable { def address: String }
// trait Ages { def age: Int }
case class Employer(val name: String, val address: String, val taxno: Int)
extends Identifiable
with Locatable
case class Employee(val name: String, val address: String, val salary: Int)
extends Identifiable
with Locatable
Since this is an interesting topic to many, let me shed some light here.
You could go with the following approach:
// You can mark it as 'sealed'. Explained later.
sealed trait Person {
def name: String
}
case class Employee(
override val name: String,
salary: Int
) extends Person
case class Tourist(
override val name: String,
bored: Boolean
) extends Person
Yes, you have to duplicate the fields. If you don't, it simply would not be possible to implement correct equality among other problems.
However, you don't need to duplicate methods/functions.
If the duplication of a few properties is that much of an importance to you, then use regular classes, but remember that they don't fit FP well.
Alternatively, you could use composition instead of inheritance:
case class Employee(
person: Person,
salary: Int
)
// In code:
val employee = ...
println(employee.person.name)
Composition is a valid and a sound strategy that you should consider as well.
And in case you wonder what a sealed trait means — it is something that can be extended only in the same file. That is, the two case classes above have to be in the same file. This allows for exhaustive compiler checks:
val x = Employee(name = "Jack", salary = 50000)
x match {
case Employee(name) => println(s"I'm $name!")
}
Gives an error:
warning: match is not exhaustive!
missing combination Tourist
Which is really useful. Now you won't forget to deal with the other types of Persons (people). This is essentially what the Option class in Scala does.
If that does not matter to you, then you could make it non-sealed and throw the case classes into their own files. And perhaps go with composition.
case classes are perfect for value objects, i.e. objects that don't change any properties and can be compared with equals.
But implementing equals in the presence of inheritance is rather complicated. Consider a two classes:
class Point(x : Int, y : Int)
and
class ColoredPoint( x : Int, y : Int, c : Color) extends Point
So according to the definition the ColorPoint(1,4,red) should be equal to the Point(1,4) they are the same Point after all. So ColorPoint(1,4,blue) should also be equal to Point(1,4), right? But of course ColorPoint(1,4,red) should not equal ColorPoint(1,4,blue), because they have different colors. There you go, one basic property of the equality relation is broken.
update
You can use inheritance from traits solving lots of problems as described in another answer. An even more flexible alternative is often to use type classes. See What are type classes in Scala useful for? or http://www.youtube.com/watch?v=sVMES4RZF-8
In these situations I tend to use composition instead of inheritance i.e.
sealed trait IVehicle // tagging trait
case class Vehicle(color: String) extends IVehicle
case class Car(vehicle: Vehicle, doors: Int) extends IVehicle
val vehicle: IVehicle = ...
vehicle match {
case Car(Vehicle(color), doors) => println(s"$color car with $doors doors")
case Vehicle(color) => println(s"$color vehicle")
}
Obviously you can use a more sophisticated hierarchy and matches but hopefully this gives you an idea. The key is to take advantage of the nested extractors that case classes provide
So here's the situation. I want to define a case class like so:
case class A(val s: String)
and I want to define an object to ensure that when I create instances of the class, the value for 's' is always uppercase, like so:
object A {
def apply(s: String) = new A(s.toUpperCase)
}
However, this doesn't work since Scala is complaining that the apply(s: String) method is defined twice. I understand that the case class syntax will automatically define it for me, but isn't there another way I can achieve this? I'd like to stick with the case class since I want to use it for pattern matching.
The reason for the conflict is that the case class provides the exact same apply() method (same signature).
First of all I would like to suggest you use require:
case class A(s: String) {
require(! s.toCharArray.exists( _.isLower ), "Bad string: "+ s)
}
This will throw an Exception if the user tries to create an instance where s includes lower case chars. This is a good use of case classes, since what you put into the constructor also is what you get out when you use pattern matching (match).
If this is not what you want, then I would make the constructor private and force the users to only use the apply method:
class A private (val s: String) {
}
object A {
def apply(s: String): A = new A(s.toUpperCase)
}
As you see, A is no longer a case class. I am not sure if case classes with immutable fields are meant for modification of the incoming values, since the name "case class" implies it should be possible to extract the (unmodified) constructor arguments using match.
UPDATE 2016/02/25:
While the answer I wrote below remains sufficient, it's worth also referencing another related answer to this regarding the case class's companion object. Namely, how does one exactly reproduce the compiler generated implicit companion object which occurs when one only defines the case class itself. For me, it turned out to be counter intuitive.
Summary:
You can alter the value of a case class parameter before it is stored in the case class pretty simply while it still remaining a valid(ated) ADT (Abstract Data Type). While the solution was relatively simple, discovering the details was quite a bit more challenging.
Details:
If you want to ensure only valid instances of your case class can ever be instantiated which is an essential assumption behind an ADT (Abstract Data Type), there are a number of things you must do.
For example, a compiler generated copy method is provided by default on a case class. So, even if you were very careful to ensure only instances were created via the explicit companion object's apply method which guaranteed they could only ever contain upper case values, the following code would produce a case class instance with a lower case value:
val a1 = A("Hi There") //contains "HI THERE"
val a2 = a1.copy(s = "gotcha") //contains "gotcha"
Additionally, case classes implement java.io.Serializable. This means that your careful strategy to only have upper case instances can be subverted with a simple text editor and deserialization.
So, for all the various ways your case class can be used (benevolently and/or malevolently), here are the actions you must take:
For your explicit companion object:
Create it using exactly the same name as your case class
This has access to the case class's private parts
Create an apply method with exactly the same signature as the primary constructor for your case class
This will successfully compile once step 2.1 is completed
Provide an implementation obtaining an instance of the case class using the new operator and providing an empty implementation {}
This will now instantiate the case class strictly on your terms
The empty implementation {} must be provided because the case class is declared abstract (see step 2.1)
For your case class:
Declare it abstract
Prevents the Scala compiler from generating an apply method in the companion object which is what was causing the "method is defined twice..." compilation error (step 1.2 above)
Mark the primary constructor as private[A]
The primary constructor is now only available to the case class itself and to its companion object (the one we defined above in step 1.1)
Create a readResolve method
Provide an implementation using the apply method (step 1.2 above)
Create a copy method
Define it to have exactly the same signature as the case class's primary constructor
For each parameter, add a default value using the same parameter name (ex: s: String = s)
Provide an implementation using the apply method (step 1.2 below)
Here's your code modified with the above actions:
object A {
def apply(s: String, i: Int): A =
new A(s.toUpperCase, i) {} //abstract class implementation intentionally empty
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
And here's your code after implementing the require (suggested in the #ollekullberg answer) and also identifying the ideal place to put any sort of caching:
object A {
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
//TODO: Insert normal instance caching mechanism here
new A(s, i) {} //abstract class implementation intentionally empty
}
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
And this version is more secure/robust if this code will be used via Java interop (hides the case class as an implementation and creates a final class which prevents derivations):
object A {
private[A] abstract case class AImpl private[A] (s: String, i: Int)
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
//TODO: Insert normal instance caching mechanism here
new A(s, i)
}
}
final class A private[A] (s: String, i: Int) extends A.AImpl(s, i) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
While this directly answers your question, there are even more ways to expand this pathway around case classes beyond instance caching. For my own project needs, I have created an even more expansive solution which I have documented on CodeReview (a StackOverflow sister site). If you end up looking it over, using or leveraging my solution, please consider leaving me feedback, suggestions or questions and within reason, I will do my best to respond within a day.
I don't know how to override the apply method in the companion object (if that is even possible) but you could also use a special type for upper case strings:
class UpperCaseString(s: String) extends Proxy {
val self: String = s.toUpperCase
}
implicit def stringToUpperCaseString(s: String) = new UpperCaseString(s)
implicit def upperCaseStringToString(s: UpperCaseString) = s.self
case class A(val s: UpperCaseString)
println(A("hello"))
The above code outputs:
A(HELLO)
You should also have a look at this question and it's answers: Scala: is it possible to override default case class constructor?
For the people reading this after April 2017: As of Scala 2.12.2+, Scala allows overriding apply and unapply by default. You can get this behavior by giving -Xsource:2.12 option to the compiler on Scala 2.11.11+ as well.
It works with var variables:
case class A(var s: String) {
// Conversion
s = s.toUpperCase
}
This practice is apparently encouraged in case classes instead of defining another constructor. See here.. When copying an object, you also keep the same modifications.
Another idea while keeping case class and having no implicit defs or another constructor is to make the signature of apply slightly different but from a user perspective the same.
Somewhere I have seen the implicit trick, but can´t remember/find which implicit argument it was, so I chose Boolean here. If someone can help me out and finish the trick...
object A {
def apply(s: String)(implicit ev: Boolean) = new A(s.toLowerCase)
}
case class A(s: String)
I faced the same problem and this solution is ok for me:
sealed trait A {
def s:String
}
object A {
private case class AImpl(s:String)
def apply(s:String):A = AImpl(s.toUpperCase)
}
And, if any method is needed, just define it in the trait and override it in the case class.
If you're stuck with older scala where you cant override by default or you dont want to add the compiler flag as #mehmet-emre showed, and you require a case class, you can do the following:
case class A(private val _s: String) {
val s = _s.toUpperCase
}
As of 2020 on Scala 2.13, the above scenario of overriding a case class apply method with same signature works totally fine.
case class A(val s: String)
object A {
def apply(s: String) = new A(s.toUpperCase)
}
the above snippet compiles and runs just fine in Scala 2.13 both in REPL & non-REPL modes.
I think this works exactly how you want it to already. Here's my REPL session:
scala> case class A(val s: String)
defined class A
scala> object A {
| def apply(s: String) = new A(s.toUpperCase)
| }
defined module A
scala> A("hello")
res0: A = A(HELLO)
This is using Scala 2.8.1.final