Last active
May 1, 2017 20:25
-
-
Save petrovg/22a47dd22f5f8a5b9cab to your computer and use it in GitHub Desktop.
Trying to understand the Magnet pattern (as used in spray)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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