Skip to content

Instantly share code, notes, and snippets.

@squito
Last active December 30, 2015 20:39
Show Gist options
  • Select an option

  • Save squito/7882131 to your computer and use it in GitHub Desktop.

Select an option

Save squito/7882131 to your computer and use it in GitHub Desktop.
I first thought of making a union bound using implicit classes, but I realized it would need extra object allocation. The better answer is found here: http://stackoverflow.com/a/3508555/1442961 HOWEVER, that answer doesn't work for varargs
trait Wrapper {
def v: String
}
implicit class StringAsWrapper(s: String) extends Wrapper {
println(s"constructing string wrapper")
def v = s
}
implicit class SymbolAsWrapper(s: Symbol) extends Wrapper {
println(s"constructing symbol as wrapper")
def v = s.name
}
def foo(w: Wrapper) = w.v
foo("hi")
foo("bye")
foo("blah")
foo('wakka)
foo('ooga)
foo('booga)
//if you run this, you'll see you are generating the implicit wrapper on each call
trait WrapperVal extends Any {
def v: String
}
implicit class StringAsWrapperVal(val s: String) extends AnyVal with WrapperVal {
def v = s
}
implicit class SymbolAsWrapperVal(val s: Symbol) extends AnyVal with WrapperVal {
def v = s.name
}
def blah(w:WrapperVal) = w
//I can't modify this example to show this, b/c you can't add any other statements in
// the the constructor of a value class. I think I'm getting multiple instances
// based on this rule:
//
// http://docs.scala-lang.org/overviews/core/value-classes.html
// A value class is actually instantiated when:
// 1. a value class is treated as another type.
// ...
// I'm not sure how, but this comparison returns true
blah("foo") == blah("foo")
//but if you look at the returned value, you can see we're allocating actual objects
scala> blah("foo")
res21: WrapperVal = StringAsWrapperVal@18cc6
scala> blah("ooga")
res22: WrapperVal = StringAsWrapperVal@3422ba
// the Witness version works, though, w/out any extra allocations
trait UnionBound[T]
object UnionBound {
//these are just objects, so nothing could possibly be getting allocated
implicit object StringWitness extends UnionBound[String]
implicit object SymbolWitness extends UnionBound[Symbol]
}
def ooga[T: UnionBound] (t: T) = t match {
case str: String => str
case sym: Symbol => sym.name
}
ooga("blah")
ooga("foo")
ooga('wakka)
ooga(1)//compiler error, our union bound works!
// BUT! unfortunately, we get into trouble if we try to use varargs
//wrapper version works:
def foos(ws: Wrapper*) = ws.map{_.v}
scala> foos("blah", 'hi, 'there, "everybody")
constructing string wrapper
constructing symbol as wrapper
constructing symbol as wrapper
constructing string wrapper
res12: Seq[String] = ArrayBuffer(blah, hi, there, everybody)
//but "witness" does not
def oogas[T: UnionBound](ts: T*) = ts.map{t => t match {
case str: String => str
case sym: Symbol => sym.name
}}
scala> oogas("hi", "there")
res14: Seq[String] = ArrayBuffer(hi, there)
scala> oogas('symbol, 'ok)
res16: Seq[String] = ArrayBuffer(symbol, ok)
scala> oogas("mixed", 'fails)
<console>:13: error: could not find implicit value for evidence parameter of type UnionBound[java.io.Serializable]
oogas("mixed", 'fails)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment