Is it appropriate to define a non-trivial Scala case class? - scala

I'm defining a Scala class today, and I think "I need an equals method and a hashCode method; and a copy method would be handy too. I'll turn this into a case class." My class already has a bunch of other code, and is in no way trivial.
So fine, it all works and everything, but when the text books deal with case classes, all of the examples define them for use as value classes or 'data transfer objects'. Is it appropriate to define a non-trivial case class? Is the thought process described above OK, or do I need to think of case classes differently?

A case class provides, equals, hashCode and toString methods based on the main constructor parameters, all of which are turned into val too. In addition, the object companion gets an apply and an unapply methods, again based on the main constructor parameters.
Also, a case class inherits from Serializable and from Product, and should not be extended by other classes.
If all of these things are appropriate for your class, then feel free to declare it as a `case class'.

Feel free, provided it doesn't have descendants. Extending case classes is a bad idea.

Related

Abstract class and trait use case [duplicate]

What is the advantage of using an abstract class instead of a trait (apart from performance)? It seems like abstract classes can be replaced by traits in most cases.
I can think of two differences
Abstract classes can have constructor parameters as well as type parameters. Traits can have only type parameters. There was some discussion that in future even traits can have constructor parameters
Abstract classes are fully interoperable with Java. You can call them from Java code without any wrappers. Traits are fully interoperable only if they do not contain any implementation code
There's a section in Programming in Scala called "To trait, or not to trait?" which addresses this question. Since the 1st ed is available online, I'm hoping it's OK to quote the whole thing here. (Any serious Scala programmer should buy the book):
Whenever you implement a reusable collection of behavior, you will
have to decide whether you want to use a trait or an abstract class.
There is no firm rule, but this section contains a few guidelines to
consider.
If the behavior will not be reused, then make it a concrete class. It
is not reusable behavior after all.
If it might be reused in multiple, unrelated classes, make it a trait.
Only traits can be mixed into different parts of the class hierarchy.
If you want to inherit from it in Java code, use an abstract class.
Since traits with code do not have a close Java analog, it tends to be
awkward to inherit from a trait in a Java class. Inheriting from a
Scala class, meanwhile, is exactly like inheriting from a Java class.
As one exception, a Scala trait with only abstract members translates
directly to a Java interface, so you should feel free to define such
traits even if you expect Java code to inherit from it. See Chapter 29
for more information on working with Java and Scala together.
If you plan to distribute it in compiled form, and you expect outside
groups to write classes inheriting from it, you might lean towards
using an abstract class. The issue is that when a trait gains or loses
a member, any classes that inherit from it must be recompiled, even if
they have not changed. If outside clients will only call into the
behavior, instead of inheriting from it, then using a trait is fine.
If efficiency is very important, lean towards using a class. Most Java
runtimes make a virtual method invocation of a class member a faster
operation than an interface method invocation. Traits get compiled to
interfaces and therefore may pay a slight performance overhead.
However, you should make this choice only if you know that the trait
in question constitutes a performance bottleneck and have evidence
that using a class instead actually solves the problem.
If you still do not know, after considering the above, then start by
making it as a trait. You can always change it later, and in general
using a trait keeps more options open.
As #Mushtaq Ahmed mentioned, a trait cannot have any parameters passed to the primary constructor of a class.
Another difference is the treatment of super.
The other difference between classes and traits is that whereas in classes, super calls are statically bound, in traits, they are dynamically bound. If you write super.toString in a class, you know exactly which method implementation will be invoked. When you write the same thing in a trait, however, the method implementation to invoke for the super call is undefined when you define the trait.
See the rest of Chapter 12 for more details.
Edit 1 (2013):
There is a subtle difference in the way abstract classes behaves compared to traits. One of the linearization rules is that it preserves the inheritance hierarchy of the classes, which tends to push abstract classes later in the chain while traits can happily be mixed in. In certain circumstances, it's actually preferable to be in latter position of the class linearization, so abstract classes could be used for that. See constraining class linearization (mixin order) in Scala.
Edit 2 (2018):
As of Scala 2.12, trait's binary compatibility behavior has changed. Prior to 2.12, adding or removing a member to the trait required recompilation of all classes that inherit the trait, even if the classes have not changed. This is due to the way traits were encoded in JVM.
As of Scala 2.12, traits compile to Java interfaces, so the requirement has relaxed a bit. If the trait does any of the following, its subclasses still require recompilation:
defining fields (val or var, but a constant is ok – final val without result type)
calling super
initializer statements in the body
extending a class
relying on linearization to find implementations in the right supertrait
But if the trait does not, you can now update it without breaking binary compatibility.
For whatever it is worth, Odersky et al's Programming in Scala recommends that, when you doubt, you use traits. You can always change them into abstract classes later on if needed.
Other than the fact that you cannot directly extend multiple abstract classes, but you can mixin multiple traits into a class, it's worth mentioning that traits are stackable, since super calls in a trait are dynamically bound (it is referring a class or trait mixed before current one).
From Thomas's answer in Difference between Abstract Class and Trait:
trait A{
def a = 1
}
trait X extends A{
override def a = {
println("X")
super.a
}
}
trait Y extends A{
override def a = {
println("Y")
super.a
}
}
scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1#6e9b6a
scala> xy.a
Y
X
res0: Int = 1
scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1#188c838
scala> yx.a
X
Y
res1: Int = 1
When extending an abstract class, this shows that the subclass is of a similar kind. This is not neccessarily the case when using traits, I think.
In Programming Scala the authors say that abstract classes make a classical object oriented "is-a" relationship while traits are a scala-way of composition.
Abstract classes can contain behaviour - They can parameterized with constructor args (which traits can't) and represent a working entity. Traits instead just represent a single feature, an interface of one functionality.
A class can inherit from multiple traits but only one abstract class.
Abstract classes can have constructor parameters as well as type parameters. Traits can have only type parameters. For example, you can’t say trait t(i: Int) { }; the i parameter is illegal.
Abstract classes are fully interoperable with Java. You can call them from Java code without any wrappers. Traits are fully interoperable only if they do not contain any implementation code.

Scala: importance during implementation of case class private

I understand that using something like
case class private A()
new A()#This will be a invalid call as A is private
But what I do not understand that as from an implementation perspective, what advantage does this provide while coding? Because calling A() twice will give 2 instances of the class anyways. If this syntax is not used to prevent instantiation like Java, then why would I want to not let someone instantiate my class using new?
Marking a case class constructor private is useless. As you've notices, case classes get a synthetic companion object with an apply method whose implementation is simply a call to the actual constructor.
Scala case classes have been designed to just "classes + the case modifier", meaning that everything that works on classes also works on case classes, which also include the (pointless) ability to specify access modifiers on the constructor.

Why not make every Scala class a case class?

case classes have some nice percs, like copy, hashCode, toString, Pattern Matching. Why not make every Scala class a case class?
A case class is extremely good to hold complex values, like entity objects. They are thought precisely for that case, so they provide you methods that make sense precisely for this use case by synthesizing the methods you mentioned and furthermore making your class Serializable and creating a companion object with a "factory" method (other than the extractor for pattern matching).
The drawbacks are the following:
some of the properties that a case class has may not be interesting for the class you're creating: would you want an equals method on an object holding a database connection? Would it make sense for it to be Serializable? And if it did, would it be secure?
all these features are not free: they require the compiler to do some extra work and add to your final artifact size; why having these if you don't need the extra features a case class provides?
you cannot inherit from case class to another case class, which may go against how you are modeling your domain. Why? Short answer: equality. You can find a longer answer here.
Case classes have clear semantics -- data container (much better POJOs or ADT blocks, depends on your background).
Sometimes methods like copy or unapply can have confusing meaning -- e.g. if fields are mutable. Case classes are designed to be used in "idiomatic scala style", that might not be applicable everywhere.
Last but not the least -- technical disadvantages (more code in .class, more code to serialize, issues with inheritance).

When should I use a regular class in Scala?

It seems to me that I can make just about anything using object, trait, abstract class and in rare occasions, case class. Most of this is in the form object extends trait. So, I'm wondering, when should I, if ever, use a plain, standard class?
This is not a right place to ask this question
Looks like you are new Scala
Class is a specification for something(some entity) you want to model . It contains behavior and state
There is only one way to declare so called regular class using keyword class
Both trait and abstract class are used for inheritance.
trait is used for inheritance (generally to put common behavior in there). trait is akin to interface in Java. multiple inheritance possible with traits but not abstract class.
A class can extends one class or abstract class but can mixin any number of traits. Traits can have behavior and state.
case class is a nothing but a class but compiler produces some boilerplate code for us to make things easy and look good.
object is used when you want to declare some class but you want to have single instance of the class in the JVM (remember singleton pattern).
If an object performs stateful computations on its members i.e. its members are declared with vars;
Or, even if its member are only declared with vals but those vals store mutable data structures which can be edited in place, then it should be an ordinary (mutable) class akin to a Java mutable object.
The idiomatic way of using Case classes in Scala is as immutable types i.e. all the constructor arguments are vals. We could use vars but then we lose the advantages of case classes like equality comparisons will break over time.
Some advise from Programming in Scala by Odersky et al on deciding between using traits, abstract classes and concrete classes:
If the behavior will not be reused, then make it a concrete class. It is not reusable behavior after all.
If it might be reused in multiple, unrelated classes, make it a trait.
Only traits can be mixed into different parts of the class hierarchy.
If you want to inherit from it in Java code, use an abstract class.
Since traits with code do not have a close Java analog, it tends to be
awkward to inherit from a trait in a Java class. Inheriting from a
Scala class, meanwhile, is exactly like inheriting from a Java class.
As one exception, a Scala trait with only abstract members translates
directly to a Java interface, so you should feel free to define such
traits even if you expect Java code to inherit from it. See Chapter 29
for more information on working with Java and Scala together.
If you plan to distribute it in compiled form, and you expect outside
groups to write classes inheriting from it, you might lean towards
using an abstract class. The issue is that when a trait gains or loses
a member, any classes that inherit from it must be recompiled, even if
they have not changed. If outside clients will only call into the
behavior, instead of inheriting from it, then using a trait is fine.
If efficiency is very important, lean towards using a class. Most Java
runtimes make a virtual method invocation of a class member a faster
operation than an interface method invocation. Traits get compiled to
interfaces and therefore may pay a slight performance overhead.
However, you should make this choice only if you know that the trait
in question constitutes a performance bottleneck and have evidence
that using a class instead actually solves the problem.
If you still do not know, after considering the above, then start by
making it as a trait. You can always
change it later, and in general using a trait keeps more options open.

How to determine to use trait to 'with' or class to 'inject'?

I'm puzzled to choose a trait or class when writing scala code.
At first, I have a controller which with several traits:
class MyController extends Controller
with TransactionSupport
with JsonConverterSupport
with LoggerSupport
In these traits, I defined some methods and fields which can be used in MyController directly.
But my friend says: when you extends or with a trait, it should be a that trait.
Look at the MyController, it is a Controller, but it isn't a TransactionSupport, not a JsonConverterSupport, not a LoggerSupport, so it should not with them.
So the code becomes:
class MyController(tranSupport: TransactionSupport,
jsonConverter: JsonConverterSupport,
loggerSupport: LoggerSupport) extends Controller
But I don't feel good about this code, it just seems strange.
I see traits used heavily in scala code, when should I use it or use classes to inject?
I'll refer you to Interfaces should be Adjectives. Though some traits may play the part of a class (and, therefore, be nouns and respect the "is-a" relationship), when used as mixins they'll tend to play the part of interfaces.
As an "adjective", the trait will add a qualifying property to whatever they are extending. For example, they may be Comparable or Serializable.
It can be a bit hard to find an adjective to fit -- what adjective would you use for LoggerSupport? -- so don't feel overly constrained by that. Just be aware that it is completely wrong to thing of traits as necessarily an "is-a" relationship.
I would try to avoid using traits to replace "has-a" relationships, though.
My opinion is that it doesn't have to be it. Mixing-in is a different concept than inheritance. Even though syntactically it is the same, it doesn't mean the same. Typical use case for mixing-in is logging just like you wrote. It doesn't mean that if your service class mixes-in a Logging trait that it is a logger. It's just a yet another way how to compose functionality into working objects.
Odersky proposes that if you are not sure and you can, use traits because they are more flexible. You can change trait to class in the future if you need.
Sometime when I feel that mixing-in trait doesn't look good, I use module pattern like this:
trait JsonConverterModule {
protected def jsonConverter: JsonConverter
protected trait JsonConverter {
def convert(in: Json): Json
}
}
class MyController extends Controller with JsonConverterModule {
private doSmth = jsonConverter.convert(...)
}
MyController in this case looks more like a Controller, and all Json-related stuff is hidden from MyController 'client'
Your first example with traits is the "cake pattern" and your second example is "constructor injection". Both are perfectly valid ways to do dependency injection in Scala. The cake pattern is powerful, you can inject type members, the different traits can easily talk to each other (we don't have to create separate objects and pass them to each other object, often requiring setter injection rather than simple constructor injection), etc. However, the type has to be realized at compile-time, and a separate class must be realized for every combination of traits. Constructor injection lets you build your object at run-time and scales better for a large number of combinations.