开发者

Scala Set implementation to use within business model?

Let's say we want to build a big social network (because social networks are all the rage at the moment). We'll start with a simple premise that anyone who wants to use our social network should be able to register under their name and then become friends or fall out with other people registred with us:

import scala.collection._

class Person (var name: String) {
    private val _friends = new mutable.HashSet[Person]

    def befriends     (p: Person) { _friends+=p }
    def fallsOutWith  (p: Person) { _friends-=p }
    def friends () = _friends toSet
    override def toString = name
}

So far so good:

val brad     = new Person("Brad Pitt")
val angelina = new Person("Angelina Jolie")

brad befriends angelina
angelina befriends brad 

Good stuff! A final touch, let's see the list of all Brad's friends:

brad.friends.foreach(println)

It works, and we're about to take the world by a storm with our wonderful social network that is all 100% Scala!

Now on to the boring, technical bits. We'd need to be able to persist data and db4o seems as a good choice, some more code:

 db store brad // job done!

And then restore Brad from hard drive:

 val q = db.query       
 q.constrain(classOf[Person])
 q.descend("name").constrain("Brad Pitt")           
 val brad = q.execute.get(0)                

See the list of friends once again...

 brad.friends.foreach(println)

and BANG! NullPointerException! With a bit of debugging it t开发者_如何学Curns out that underlying data store of mutable.HashSet that we're relying on to keep track of friends is defined as transient in scala.collection.mutable.FlatHashTable:

@transient protected var table: Array[AnyRef] = new Array(initialCapacity) 

and hence when we telling db4o to store a Person the actual list of friends in not serialised. It seems that db4o ought to be using readObject and writeObject methods of HashSet instead.

I wonder if there is way of telling db4o to serialise / deserialise HashSet correctly or if there is a more suitable Scala Set implementation that is db4o friendly?


Is there a particular reason why you need to use db4o? As with many Java persistence frameworks, it assumes that mutability in objects is okay, which really doesn't mesh too well with idiomatic Scala.

You might have more joy using Squeryl or one of the multiple NoSQL stores that Akka is able to deal with. In absence of further information, I'd probably recommend Squeryl at this stage.

Having done that, you'll also want to avoid the bidirectional friend relationships held in your Person objects - they'll make immutable "updates" almost impossible. Lifting this information into a dedicated Relationship object will help out a great deal, it'll also allow you easily add more information about the nature of relationships as your system evolves.

Your original question then becomes irrelevant :)


scala.collection.immutable.HashSet doesn't suffer from the same serialisation issue, re-writing Person class to rely on the immutable HashSet solves the problem:

import scala.collection._ 

class Person (var name: String) { 
    private var _friends = new immutable.HashSet[Person] 

    def befriends     (p: Person) { _friends=_friends+p } 
    def fallsOutWith  (p: Person) { _friends=_friends-p } 
    def friends () = _friends
    override def toString = name 
} 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜