In my web application authorized user has at least 4 "facets": http session related data, persistent data, facebook data, runtime business data.
I've decided to go with case class composition instead of traits for at least two reasons:
traits mixing can cause name clashes
i want the free case class goodies like pattern matching and copy method
I'd like to know experienced scalaists opinions on this subject. It looks like traits and/or cake pattern should be suitable for such tasks but as i've mentioned above there are problems... Its obvious that not only i want to implement it fast and easy but also to understand it in depth for using in future.
So does my decision have any flaws and misunderstanding or is it right?
Related code looks like this:
case class FacebookUserInfo(name: String, friends: List[Long])
case class HttpUserInfo(sessionId: String, lastInteractionTime: Long, reconnect: Boolean)
case class RuntimeQuizUserInfo(recentScore: Int)
trait UserState {
def db: User
def http: HttpUserInfo
}
case class ConnectingUser(db: User, http: HttpUserInfo) extends UserState
case class DisconnectedUser(db: User, http: HttpUserInfo, facebook: Option[FacebookUserInfo]) extends UserState
case class AuthorizedUser(db: User, http: HttpUserInfo, facebook: FacebookUserInfo,
quiz: RuntimeQuizUserInfo) extends UserState
I think the answer is easy: Go with inheritance, as long as everything really "belongs" to your object, as long as everything is in the same "problem domain".
The intention of the cake pattern is to factor out parts of the object that are somehow required, but are not really part of it, e.g. a strategy, a decoration, a configuration, a context etc. Logging would be a typical example. Generally we're talking about situations you don't want to "hard-wire" things, e.g. cases you would consider to use a DI framework (like Guice or Spring) in Java. See http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html for a good example.
A question that often helps to decide what to do is: "How could I test the object behavior?". If you find it difficult to set up a proper test environment, chances are that you should decouple things, and that means DI, which can be often realized conveniently with the cake pattern.
The third option is to use implicit converters aka "pimp my library," which probably is not necessary since you have the control of the code.
It all depends on how opaque (or transparent) you want to be about certain aspect of your object. You can pretend its a plain old case class to the rest of the world, but internally make it do extra work by using implicits. The use of case class to hold data is appropriate but I also feel that it's awkward to represent the same object using three classes (ConnectingUser, DisconnectedUser, AuthenticatedUser) depending on her state of authentication.
For the UserState, you could provide an extractor so it behaves like a case class:
object UserState {
def unapply(state: UserState) = Some(state.db, state.http)
}
this can be used in a match state as follows:
val user = ConnectingUser(User(), HttpUserInfo("foo", 0, false))
user match {
case UserState(db, http) => println(http)
}
Related
I am creating a cache, and want to make sure that the key type overrides hashCode.
If hashCode was not already defined on Object, something like this would work
trait Key {
def hashCode: Int
}
If the keys are always case classes it is obviously not a problem, but I want to make sure that if somebody passes a regular class it will fail. Is there a way to do it in Scala?
On a side note: My key is specifications for a SQL query which currently is represented as case classes. For example
case class Filter(age: Option[Int], gender: Option[String])
But eventually, I want to represent it using a cleaner specification pattern implementation (for example: https://gist.github.com/lbialy/912fad3c909374b81ce7)
If you want to explicitly whitelist classes that are allowed to use their hashCode, you cannot use inheritance for that, but you can provide your own typeclass:
trait HasApprovedHashCode[X] {
def hashCode(x: X): Int
}
and then modify all the methods that crucially rely on a proper implementation of hashCode like this:
def methodRelyingOnHashCode[K: HasApprovedHashCode, V](...) = ...
Now you can explicitly whitelist only those classes that you deem as having good enough implementation of hashCode.
Usually, I would say: hash code of the used key is not your responsibility. If the user of your library insists on shooting h(im/er)self in the foot, you cannot prevent it. You shouldn't facilitate it, or even create a situation where this is almost inevitable, but it's not your responsibility to hunt down every single class out there that could somehow misbehave when used as a key of a map.
Suppose we have the following case classes:
abstract sealed class Tree
case class Leaf(i: Int) extends Tree
case class Node(left: Tree, right: Tree) extends Tree
Every time we call a case class constructor, a new object is created in memory. For instance, in the code below:
val a = Leaf(0)
val b = Leaf(0)
a and b point to distinct objects in memory:
a == b // true
a eq b // false
I would like to override the "apply" method of the case classes, to make them return a cached object, in case it already exists, so that, in the minimal example above, "a eq b" would return true.
I found these two related answers in Stackoverflow:
How to override apply in a case class companion (shows how to override "apply" method)
Why do each new instance of case classes evaluate lazy vals again in Scala? (shows a simple way to cache case class instances)
I am planning to implement my overriding "apply" method with caching in a way that combines the two approaches linked above. But I am wondering if there are alternative ways that I should consider. If you know any, could you please share your solution here?
Caching instances of case classes seems to be a very useful and natural thing to do to reduce memory consumption. And yet, the solution I am planning to implement (based on the two answers linked above) seems quite convoluted, requiring a lot of boilerplate code that will compromise the elegance and succinctness of case classes. Does anyone know if future versions of the Scala language might allow us to achieve case class instance caching by writing something simple like this:
abstract sealed class Tree
cached case class Leaf(i: Int) extends Tree
cached case class Node(left: Tree, right: Tree) extends Tree
??
Caching instances of case classes seems to be a very useful and natural thing to do to reduce memory consumption.
Note that this isn't even remotely an automatic improvement, and very much depends on usage pattern of the case class (not just yours, but anybody who uses your library):
You need to take into account the memory cache needs and inability to garbage collect instances referenced from the cache (note that using a WeakHashMap won't help: it requires "that value objects do not strongly refer to their own keys, either directly or indirectly").
If the keys are primitives (as in Leaf), they need to be boxed before lookup which will often already be a constructor call.
Lookup in a map is significantly slower than a trivial constructor call.
Escape analysis will often ensure the objects aren't actually constructed, while making sure your program works as if they were. Of course, caching will ensure that objects do escape.
But neglecting all that, you can write a macro annotation which will allow you #cached case class Leaf(i: Int) extends Tree and generate the code you want (or at least #cachedcase class; I am not sure if you'll be able to override apply otherwise). Because of the above I just wouldn't expect it to be a part of the language any time soon.
Some open source libraries like twitters seem to have a convention for marking case classes as final.
My team is deciding whether to adopt this convention but we don't yet understand the pro's of doing this. Currently the only possible advantage I can perceive is that it stops accidental inheritance from case classes.
But are there any other advantages? Does it improve compile times or allow the compiler to add internal optimizations?
I was hoping that it would aid with detecting missing values in pattern matches but it doesn't seem to do that either. In a simple script like this, the compiler generates a warning for matchSealed but not for matchFinal:
sealed case class Sealed(one: Option[Int], two: Option[Int])
def matchSealed(s: Sealed): Unit = s match {
case Sealed(Some(i), None) => println(i)
}
final case class Final(one: Option[Int], two: Option[Int])
def matchFinal(f: Final): Unit = f match {
case Final(Some(i), None) => println(i)
}
My impression of final is that it's a stronger restriction than sealed, so it is odd that this does not generate a warning.
Here is an explanation of some benefits:
A final case class cannot be extended by any other class. This means you can make stronger guarantees about how your code behaves. You know that nobody can subclass your class, override some methods, and make something goofy happen. This is great when you are debugging code – you don’t have to go hunting all over the object hierarchy to work out which methods are actually being called.
Of course making classes final does mean that you lose a form of extensibility. If you do find yourself wanting to allow users to implement functionality you should wrap that functionality up in a trait and use the type class pattern instead.
I'm new to Scala and trying to understand how I should be modeling these objects.
The goal here is to have an object that will be stored into a database. The data to store will come from a POST. The post does not contain all of the data that will be persisted.
The OO side of me says to make a base class with the common fields. Extend it represent the data that is posted, and extend that to represent the object that is persisted. However, it seems that case classes are used for this sort of thing, and case class inheritance is discouraged/deprecated/buggy, so I'm not quite sure what I should be doing.
Also, the repetition feels very... wrong.
I am hoping someone a bit more experienced can offer some insight on how to approach this.
abstract class TestBase(val someField: String)
case class TestPost(override val someField: String) extends TestBase(someField)
case class Test(testId: String, override val someField: String) extends TestBase(someField)
Also, if I did continue with this approach, how would you copy fields from a TestPost instance to a Test instance?
although you are doing OOP and you can in Scala you should also be pressing on the functional way of doing things, functional programming states your objects should be immutable and case classes that's what they are for, they represent the value object pattern built right in the language. My advice would be to use composition instead.
case class A(field : Field)
case class B(a : A, moreFields : Fields)
I am not sure how you are trying to persist things to a database.
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.