Created
July 1, 2011 05:42
-
-
Save gseitz/1057935 to your computer and use it in GitHub Desktop.
Create 1-line extractors for traits
This file contains 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
abstract class Traitor[T:Manifest] { | |
def unapply(any: AnyRef) ={ | |
if (manifest[T].erasure.isAssignableFrom(any.getClass)) Some(any.asInstanceOf[T]) | |
else None | |
} | |
} | |
// this is especially useful when you want to check whether something has a certain trait mixed in | |
// and want to combine it with retronym's && pattern matching conjunction combinator. | |
// see: http://stackoverflow.com/questions/2261358/pattern-matching-with-conjunctions-patterna-and-patternb | |
// | |
// The combination of Traitor and &&: | |
// Splitter to apply two pattern matches on the same scrutinee. | |
object && { | |
def unapply[A](a: A) = Some((a, a)) | |
} | |
trait T1 | |
trait T2 | |
object T1 extends Traitor[T1] | |
object T2 extends Traitor[T2] | |
new T1 with T2 {} match { | |
case T1(t1) && T2(t2) => true // do something with t1 and t2 | |
case _ => false // yawn | |
} |
This file contains 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
scala> trait YouCantMatchMe | |
defined trait YouCantMatchMe | |
scala> object YesICan extends Traitor[YouCantMatchMe] | |
defined module YesICan | |
scala> def uncatchable_?(any: Any) = any match { | |
| case YesICan(uncatchable) => Some(uncatchable) | |
| case _ => None | |
| } | |
uncatchable_$qmark: (any: Any)Option[YouCantMatchMe] | |
scala> uncatchable_?(new YouCantMatchMe{}) // Some(...) | |
res0: Option[YouCantMatchMe] = Some($anon$1@c678c7) | |
scala> uncatchable_?(4) // None | |
res1: Option[YouCantMatchMe] = None |
Thanks. The kudos for && go to @retronym.
Little known fact: you can pattern match on intersection types.
scala> trait A; trait B; class C extends A with B
defined trait A
defined trait B
defined class C
scala> new C match { case ab: A with B => true; case _ => false }
res3: Boolean = true
Thanks, but I could swear I tried it and I got different results depending on whether I used "A with B" or "B with A", which didn't seem too practical in the end. Can't remember though.
I can't repro that. If you can, let me know, it's a bug.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That is very cool. The && trick also.