One of the nice advantages of Scala is the way you can be type safe, so that no undefined values will appear in the application. Mongo, however, is not type safe at all. So, I thought, a kind of conversion to and from Mongo is good, to make sure only the right values are saved (as strings). I have this type in my Scala:
sealed trait Tribe
object Tribe {
def fromString(s:String) = s match {
case "Earth Pony" => EarthPony
case "Pegasus" => Pegasus
case "Unicorn" => Unicorn
case "Alicorn" => Alicorn
case _ => throw new NoSuchElementException
}
}
case object EarthPony extends Tribe {
override def toString = "Earth Pony"
}
case object Pegasus extends Tribe {
override def toString = "Pegasus"
}
case object Unicorn extends Tribe {
override def toString = "Unicorn"
}
case object Alicorn extends Tribe {
override def toString = "Alicorn"
}
Now I want to make a field TribeField which I can employ in a MongoRecord class to make sure this conversion is done when I read the Record, or save it.
Unfortunately, the documentation on Lift's Record seems sparse, and so far I have not found any helpful information on how to do this. Maybe someone here can give me some hints?
I'm fairly sure that lift-record-mongodb uses the ability of lift-record Field instances to serialize/deserialize to and from JSON via Field.asJValue and Field.setFromJValue. To make a completely type safe Tribe Field, you'd want to create your own TypedField[Tribe] and implement those methods along with the other abstract methods that set and access your field. I'd recommend taking a look at StringField or one of the other concrete Field types for pointers on how to do that.
An easier alternative would be to extend StringField itself and add setTribe/asTribe methods.
If you need more info, particularly on Lift's Mongodb integration, I'd recommend you try the Lift Google Group. Tim Nelson who maintains that code is usually pretty quick to respond to questions.
Related
I see some Scala code like this:
case class Team(private val members: List[User]) {
def removed(member: User): Team = {
Team(members.filterNot(_ == member))
}
def added(member: User): Team = {
Team(member :: members)
}
def allNames: List[String] = members.map(_.name)
}
You can see the Team is a case class, but it has a private field members. And in the body, it has several methods to construct a new Team, and a method allNames which export some information of the private members.
I'm not sure if the usage of case class is good, since I think a case class is a data class, we should not use private fields. For this case, I think a normal class is enough:
class Team(members: List[User]) {
def removed(member: User): Team = {
new Team(members.filterNot(_ == member))
}
def added(member: User): Team = {
new Team(member :: members)
}
def allNames: List[String] = members.map(_.name)
}
You can see I removed the case, and also private since for a normal class, the fields of constructor is private by default.
But I'm not sure if there is any good reason to write the code in the first approache.
Private vals in case classes are a little surprising because they're not as private as you might imagine if you think other ways of getting that value are just syntactic sugar.
In particular, pattern matching will give you the underlying value:
whatever match {
case Team(members) => println("I can see "+members.mkString)
}
And the value still plays a role in equality (even if you can't get it by name), and you can create copies with different values using copy.
Sometimes a private val is used to enforce best practices for that class, which is to only use pattern matching to get the values (e.g. because you will often want to pattern match other things, and this enforces consistency). Sometimes it's an indication that the programmer doesn't understand how it works and thinks its enforcing a complete lack of access to the val.
I have a trait that defines a function--I don't want to specify how it will work until later. This trait is mixed in with several case classes, like so:
trait AnItem
trait DataFormatable {
def render():String = "" // dummy implementation
}
case class Person(name:String, age:Int) extends DataFormatable with AnItem
case class Building(numFloors:Int) extends DataFormatable with AnItem
Ok, so now I want includable modules that pimp specific implementations of this render behavior. Trying to use value classes here:
object JSON {
implicit class PersonRender( val p:Person ) extends AnyVal {
def render():String = {
//render json
}
}
// others
}
object XML {
implicit class PersonRender( val p:Person ) extends AnyVal {
def render():String = {
//render xml
}
}
// others
}
The ideal use would look like this (presuming JSON output desired):
import JSON._
val p:AnItem = Person("John",24)
println(p.render())
All cool--but it doesn't work. Is there a way I can make this loadable-implementation thing work? Am I close?
The DataFormatable trait is doing nothing here but holding you back. You should just get rid of it. Since you want to swap out render implementations based on the existence of implicits in scope, Person can't have it's own render method. The compiler will only look for an implicit conversion to PersonRender if Person doesn't have a method named render in the first place. But because Person inherits (or is forced to implement) render from DataFormatable, there is no need to look for the implicit conversion.
Based on your edit, if you have a collection of List[AnItem], it is also not possible to implicitly convert the elements to have render. While each of the sub-classes may have an implicit conversion that gives them render, the compiler doesn't know that when they are all piled into a list of a more abstract type. Particularly an empty trait such as AnItem.
How can you make this work? You have two simple options.
One, if you want to stick with the implicit conversions, you need to remove DataFormatable as the super-type of your case classes, so that they do not have their own render method. Then you can swap out XML._ and JSON._, and the conversions should work. However, you won't be allowed mixed collections.
Two, drop the implicits altogether and have your trait look like this:
trait DataFormatable {
def toXML: String
def toJSON: String
}
This way, you force every class that mixes in DataFormatable to contain serialization information (which is the way it should be, rather than hiding them in implicits). Now, when you have a List[DataFormatable], you can prove all of the elements can both be converted to JSON or XML, so you can convert a mixed list. I think this would be much better overall, as the code should be more straightforward. What imports you have shouldn't really be defining the behavior of what follows. Imagine the confusion that can arise because XML._ has been imported at the top of the file instead of JSON._.
I have the situation where I want to preserve information about some generic type passed within a message to be able to create another generic class with that same type within receive method responsible for processing the message.
At first glance I thought TypeTag is my best friend here, but, after trying that out it seems this is not the best possible solution, or not solution at all. Let me first explain what I have at the moment and what is the outcome.
Message case class
trait MessageTypeTag[T] {
def typeTag: TypeTag[T]
}
case class Message[T](id: Int, payload: T, helper: MyClass[T],
cond: Condition[MyClass[T]])(implicit val typeTag: TypeTag[T])
extends MessageTypeTag[T]
MyClass2
class MyClass2[+T <: Any](_eval: Option[T] = None) {
def getEval = _eval getOrElse None
}
Receive method
def receive() = {
case m#Message(id, payload, helper, cond) => {
// this prints a proper type tag, i.e. String, because type is known in the runtime
println(m.typeTag.tpe)
// compiler complains here because it sees m.typeTag as TypeTag[Any], i.e. exact
// type is not known in the compile time
val temp = new MyClass2[m.typeTag.tpe](...)
}
}
Dirty solution
After reading several articles, discussions, documentation on both Scala and akka I come up with some dirty solution by putting the (call to) factory method case class.
case class Message[T](id: Int, payload: T, helper: MyClass[T],
cond: Condition[MyClass[T]])(implicit val typeTag: TypeTag[T])
extends MessageTypeTag[T] {
def getMyClass2: MyClass2[T] = {
// instantiate an object of type T
val bla = typeTag.mirror.runtimeClass(typeTag.tpe).newInstance.asInstanceOf[T]
// we can call apply here to populate created object or do whathever is needed
...
// instantiate MyClass2 parametrized with type T and return it
new MyClass2[T](Some(bla))
}
}
As you can see this is far from good solution/design because this case class is all but lightweight and actually defeats the purpose of case class itself. It can be improved in a way that reflection call is not coded here but in some external factory which is just called within case class, but I have a feeling there must be a better approach to accomplish this.
Any suggestion would be very appreciated. If there are some more information needed, I can provide it.
And, I believe, similar problem/solution has been described here, but I'm wondering is there a better way. Thanks.
If you want to be able to instantiate a class with reflection then you have to pass it around, there's no way around that. I think a ClassTag based solution is slightly simpler:
val bla = classTag.runtimeClass.newInstance.asInstanceOf[T]
but it's still pretty ugly.
It might be better to pass around a factory as a function rather than using a reflective approach; this lets you work with classes with no no-arg constructor or that require some setup:
case class Message[T](..., factory: () => T) {
def getMyClass2 = new MyClass2[T](Some(factory()))
}
Message(..., {_ => new SomeTThatTakesArguments(3, 4)})
I suspect the best solution will be to change your MyClass2 so that it doesn't depend on the type in the same way - perhaps you can express the constraint MyClass2 needs as a typeclass you can include in the Message, or leave it out entirely. But you'll need to post MyClass2 if you want us to suggest a solution on those lines.
I'm having trouble finding an elegant way of designing a some simple classes to represent HTTP messages in Scala.
Say I have something like this:
abstract class HttpMessage(headers: List[String]) {
def addHeader(header: String) = ???
}
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers)
new HttpRequest("/", List("foo")).addHeader("bar")
How can I make the addHeader method return a copy of itself with the new header added? (and keep the current value of path as well)
Thanks,
Rob.
It is annoying but the solution to implement your required pattern is not trivial.
The first point to notice is that if you want to preserve your subclass type, you need to add a type parameter. Without this, you are not able to specify an unknown return type in HttpMessage
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String):X
}
Then you can implement the method in your concrete subclasses where you will have to specify the value of X:
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers){
type X = HttpRequest
def addHeader(header: String):HttpRequest = new HttpRequest(path, headers :+header)
}
A better, more scalable solution is to use implicit for the purpose.
trait HeaderAdder[T<:HttpMessage]{
def addHeader(httpMessage:T, header:String):T
}
and now you can define your method on the HttpMessage class like the following:
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String)(implicit headerAdder:HeaderAdder[X]):X = headerAdder.add(this,header) }
}
This latest approach is based on the typeclass concept and scales much better than inheritance. The idea is that you are not forced to have a valid HeaderAdder[T] for every T in your hierarchy, and if you try to call the method on a class for which no implicit is available in scope, you will get a compile time error.
This is great, because it prevents you to have to implement addHeader = sys.error("This is not supported")
for certain classes in the hierarchy when it becomes "dirty" or to refactor it to avoid it becomes "dirty".
The best way to manage implicit is to put them in a trait like the following:
trait HeaderAdders {
implicit val httpRequestHeaderAdder:HeaderAdder[HttpRequest] = new HeaderAdder[HttpRequest] { ... }
implicit val httpRequestHeaderAdder:HeaderAdder[HttpWhat] = new HeaderAdder[HttpWhat] { ... }
}
and then you provide also an object, in case user can't mix it (for example if you have frameworks that investigate through reflection properties of the object, you don't want extra properties to be added to your current instance) (http://www.artima.com/scalazine/articles/selfless_trait_pattern.html)
object HeaderAdders extends HeaderAdders
So for example you can write things such as
// mixing example
class MyTest extends HeaderAdders // who cares about having two extra value in the object
// import example
import HeaderAdders._
class MyDomainClass // implicits are in scope, but not mixed inside MyDomainClass, so reflection from Hiberante will still work correctly
By the way, this design problem is the same of Scala collections, with the only difference that your HttpMessage is TraversableLike. Have a look to this question Calling map on a parallel collection via a reference to an ancestor type
I'm in the process of learning Scala for a new project having come from Rails. I've defined a type that is going to be used in a number of my models which can basically be thought of as collection of 'attributes'. It's basically just a wrapper for a hashmap that delegates most of its responsibilities to it:
case class Description(attributes: Map[String, String]) {
override def hashCode: Int = attributes.hashCode
override def equals(other: Any) = other match {
case that: Description => this.attributes == that.attributes
case _ => false
}
}
So I would then define a model class with a Description, something like:
case class Person(val name: String, val description: Description)
However, when I persist a Person with a SalatDAO I end up with a document that looks like this:
{
name : "Russell",
description:
{
attributes:
{
hair: "brown",
favourite_color: "blue"
}
}
}
When in actual fact I don't need the nesting of the attributes tag in the description tag - what I actually want is this:
{
name : "Russell",
description:
{
hair: "brown",
favourite_color: "blue"
}
}
I haven't tried, but I reckon I could get that to work if I made Description extend a Map rather than contain one, but I'd rather not, because a Description isn't a type of Map, it's something which has some of the behaviour of a Map as well as other behaviour of its own I'm going to add later. Composition over inheritance and so on.
So my question is, how can I tell Salat (or Casbah, I'm actually a bit unclear as to which is doing the conversion as I've only just started using them) how to serialize and deserialize the Description class? In the casbah tutorial here it says:
It is also possible to create your own custom type serializers and
deserializers. See Custom Serializers and Deserializers.
But this page doesn't seem to exist. Or am I going about it the wrong way? Is there actually a really simple way to indicate this is what I want to happen, an annotation or something? Or can I simply delegate the serialization to the attributes map in some way?
EDIT: After having a look at the source for the JodaTime conversion helper I've tried the following but have had no luck getting it to work yet:
import org.bson.{ BSON, Transformer }
import com.mongodb.casbah.commons.conversions.MongoConversionHelper
object RegisterCustomConversionHelpers extends Serializers
with Deserializers {
def apply() = {
super.register()
}
}
trait Serializers extends MongoConversionHelper
with DescriptionSerializer {
override def register() = {
super.register()
}
override def unregister() = {
super.unregister()
}
}
trait Deserializers extends MongoConversionHelper {
override def register() = {
super.register()
}
override def unregister() = {
super.unregister()
}
}
trait DescriptionSerializer extends MongoConversionHelper {
private val transformer = new Transformer {
def transform(o: AnyRef): AnyRef = o match {
case d: Description => d.attributes.asInstanceOf[AnyRef]
case _ => o
}
}
override def register() = {
BSON.addEncodingHook(classOf[Description], transformer)
super.register()
}
}
When I call RegisterCustomConversionHelpers() then save a Person I don't get any errors, it just has no effect, saving the document the same way as ever. This also seems like quite a lot to have to do for what I want.
Salat maintainer here.
I don't understand the value of Description as a wrapper here. It wraps a map of attributes, overrides the default equals and hashcode impl of a case class - which seems unnecessary since the impl is delegated to the map anyhow and that is exactly what the case class does anyway - and introduces an additional layer of indirection to the serialized object.
Have you considered just:
case class Person(val name: String, val description: Map[String, String])
This will do exactly what you want out of box.
In another situation I would recommend a simple type alias but unfortunately Salat can't support type aliases right now due to some issues with how they are depicted in pickled Scala signatures.
(You probably omitted this from your example from brevity, but it is best practice for your Mongo model to have an _id field - if you don't, the Mongo Java driver will supply one for you)
There is a working example of a custom BSON hook in the salat-core test package (it handles java.net.URL). It could be that your hook is not working simply because you are not registering it in the right place? But still, I would recommend getting rid of Description unless it is adding some value that is not evident from your example above.
Based on #prasinous' answer I decided this wasn't going to be that easy so I've changed my design a bit to the following, which pretty much gets me what I want. Rather than persisting the Description as a field I persist a vanilla map then mix in a Described trait to the model classes I want to have a description, which automatically converts the map to Description when the object is created. Would appreciate it if anyone can point out any obvious problems to this approach or any suggestions for improvement.
class Description(val attributes: Map[String, String]){
//rest of class omitted
}
trait Described {
val attributes: Map[String, String]
val description = new Description(attributes)
}
case class Person(name: String, attributes: Map[String, String]) extends Described