Skip to content

Instantly share code, notes, and snippets.

@petrovg
Last active May 1, 2017 20:25
Show Gist options
  • Select an option

  • Save petrovg/22a47dd22f5f8a5b9cab to your computer and use it in GitHub Desktop.

Select an option

Save petrovg/22a47dd22f5f8a5b9cab to your computer and use it in GitHub Desktop.
Trying to understand the Magnet pattern (as used in spray)
// Trying to understand the Magnet pattern (as used in spray)
// http://spray.io/blog/2012-12-13-the-magnet-pattern/
/**
* A simple utility that writes things to strings.
* We'd like it to be able to work for multiple different types
*/
object Writer {
/**
* We want this to work for multiple types that we don't know yet,
* so we make it take a magnet. We'll define implicit converstions
* for some of these types in the magnet's companion
*/
def write(magnet: WriteMagnet): String = magnet()
}
sealed trait WriteMagnet {
def apply(): String
}
/**
* But some of these types we know, so we define the conversions in
* the WriteMagnet companion object
*/
object WriteMagnet {
implicit def fromInt(i: Int) = new WriteMagnet {
override def apply = i.toString
}
// The next two functions couldn't have been defined if using
// method overloading, because of type erasure
implicit def fromStringList(list: List[String]) = new WriteMagnet {
override def apply(): String = list.mkString("-")
}
implicit def fromList[T <% WriteMagnet](list: List[T]) = new WriteMagnet {
override def apply(): String = list.map(Writer.write(_)).mkString(",")
}
}
// And it works - for
Writer.write(10)
Writer.write(1 :: 34 :: 100 :: Nil)
Writer.write(List("A", "B", "C"))
// One of the types we'd like it to work for is not known in advance,
//so we couldn't pre-bake it in the magnet's companion object
case class Person(id: Int, name: String)
// But we can put it here, in it's own companion object, and
// Writer.write will still work for it
object Person {
implicit def toWriteMagnet(p: Person) = new WriteMagnet {
override def apply(): String = s"(:${p.id},${p.name}:)"
}
}
// Let's try if this works:
val adam = Person(1, "Adam")
val jeremy = Person(2, "Jeremy")
Writer.write(adam)
Writer.write(List(adam, jeremy))
// And the method can be lifted too - write becomes a function
// write: WriteMagnet => String = <function1>
val write = Writer.write _
write(1)
write(List(jeremy, adam))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment