I have the code that instance.get returns value, and based on the type I process accordingly.
instance.get match {
case v:Range => {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
case v:Encoding => {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
...
}
In the code, I have duplication for the Range and Encoding type. How can I merge the two cases?
I tried the | operator, but it doesn't work.
case v:Range | v:Encoding
This can't work, because Range.size and Encoding.size are two completely different methods despite the fact that they are named the same. And same is true for Range.decode and Edncoding.decode.
So, when you write v.size, the type of v has to be known, it has to be either v:Encoding or v:Range, not v:Encoding|v:Range.
How to fix this? Make a common trait like this:
trait SomethingWithDecodeAndSize {
def size: Int
def decode(bytes: Array[Byte]): Whatever
}
And then, change the definitions of Range and Encoding:
class Range extends SomethingWithDecodeAndSize { ... }
class Encoding extends SomethingWithDecodeAndSize { ... }
Now you can just do case v: SomethingWithDecodeAndSize => ... in your match clause.
Also ... Don't do instance.get, that's bad taste. Do instead
instance match {
Some(v: SomethingWithDecodeAndSize) => ...
}
Update
If you cannot modify the definitions of the original classes, you can use an extractor:
object SomethingWithDecodeAndSize {
def unapply(a: Any): Option[SomethingWithDecodeAndSize] = a match {
case r: Range => Some(new SomethingWithDecodeAndSize {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
})
case r: Encoding => Some(new SomethingWithDecodeAndSize {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
})
case _ => None
}
}
Now, you can do case Some(SomethingWithDecodeAndSize(v)) => ... in your match.
An alternate solution to #Dima's in case you can't change definition of Range and Encoding (and there is no supertype with required methods):
trait RangeOrEncoding {
def size: Int
def decode(bytes: Array[Byte]): Whatever
}
implicit def liftRange(r: Range): RangeOrEncoding = new RangeOrEncoding {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
}
// similar conversion for Encoding
// can also be a local def
private def handleRangeOrEncoding(v: RangeOrEncoding) = {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
instance match {
case Some(v: Range) => handleRangeOrEncoding(v)
case Some(v: Encoding) => handleRangeOrEncoding(v)
...
}
I remember the cheerleaders in high school asking us, "How loose is your goose?"
scala> class C { def f(i: Int) = 2 * i }
defined class C
scala> class D { def f(i: Int) = 3 * i }
defined class D
scala> def test(x: Any) = x match { case y: { def f(i: Int): Int } => y.f(42) }
<console>:11: warning: a pattern match on a refinement type is unchecked
def test(x: Any) = x match { case y: { def f(i: Int): Int } => y.f(42) }
^
warning: there was one feature warning; re-run with -feature for details
test: (x: Any)Int
scala> test(new C)
res0: Int = 84
scala> test(new D)
res1: Int = 126
scala> test(42)
java.lang.NoSuchMethodException: java.lang.Integer.f(int)
at java.lang.Class.getMethod(Class.java:1786)
at .reflMethod$Method1(<console>:11)
at .test(<console>:11)
... 32 elided
I believe the answer was: "Loose, baby, loose."
Edit:
scala> import reflect.runtime._,universe._,language.reflectiveCalls
import reflect.runtime._
import universe._
import language.reflectiveCalls
scala> class C { def f(i: Int) = 2 * i }
defined class C
scala> class D { def f(i: Int) = 3 * i }
defined class D
scala> def f[A](a: A)(implicit tt: TypeTag[A]) = a match {
| case b: { def f(i: Int): Int }
| if tt.tpe <:< typeOf[{ def f(i: Int): Int }] =>
| b.f(42)
| }
<console>:19: warning: a pattern match on a refinement type is unchecked
case b: { def f(i: Int): Int }
^
f: [A](a: A)(implicit tt: reflect.runtime.universe.TypeTag[A])Int
scala> f(new C)
res0: Int = 84
scala> f(new D)
res1: Int = 126
scala> f(3) // now an ordinary MatchError
scala.MatchError: 3 (of class java.lang.Integer)
at .f(<console>:18)
... 32 elided
So you can express it as an ordinary type bounds:
scala> def f[A <: { def f(i: Int): Int }](a: A) = a.f(42)
f: [A <: AnyRef{def f(i: Int): Int}](a: A)Int
scala> f(new C)
res3: Int = 84
scala> f(17)
<console>:20: error: inferred type arguments [Int] do not conform to method f's type parameter bounds [A <: AnyRef{def f(i: Int): Int}]
f(17)
^
<console>:20: error: type mismatch;
found : Int(17)
required: A
f(17)
^
You still need to accept the cost of the reflective call, of course.
Related
I have some overloaded methods that take in multiple types and return the same type:
def foo(x: Int): Foo = ...
def foo(x: String): Foo = ...
def foo(x: Boolean): Foo = ...
def foo(x: Long): Foo = ...
Now I want to define a single way to call the method, something like:
def bar(x: Int | String | Boolean | Long) = foo(x) // how to do this?
I can do it the "naive" way which I don't like very much:
def bar(x: Any) = x match {
case i:Int => foo(i)
case s:String => foo(s)
case b:Boolean => foo(b)
case l:Long => foo(l)
case _ => throw new Exception("Unsupported type")
}
Is there a better way, perhaps using Scalaz or some other library?
Try type class
trait FooDoer[T] {
def foo(x: T): Foo
}
object FooDoer {
implicit val int: FooDoer[Int] = (x: Int) => foo(x)
implicit val string: FooDoer[String] = (x: String) => foo(x)
implicit val boolean: FooDoer[Boolean] = (x: Boolean) => foo(x)
implicit val long: FooDoer[Long] = (x: Long) => foo(x)
}
def bar[T](x: T)(implicit fooDoer: FooDoer[T]): Foo = fooDoer.foo(x)
bar(1)
bar("a")
bar(true)
bar(1L)
// bar(1.0) // doesn't compile
Also sometimes the following can help
def bar[T](x: T)(implicit ev: (T =:= Int) | (T =:= String) | (T =:= Boolean) | (T =:= Long)) = ???
trait |[A, B]
trait LowPriority_| {
implicit def a[A, B](implicit a: A): A | B = null
}
object | extends LowPriority_| {
implicit def b[A, B](implicit b: B): A | B = null
}
How to define "type disjunction" (union types)?
A typeclass might work like this:
trait CanFoo[T] {
def foo(t: T): Foo
}
object CanFoo {
implicit object intFoo extends CanFoo[Int] {
def foo(i: Int) = Foo(i)
}
implicit object stringFoo extends CanFoo[String] {
def foo(s: String) = Foo(s)
}
implicit object boolFoo extends CanFoo[Boolean] {
def foo(i: Boolean) = Foo(i)
}
implicit object longFoo extends CanFoo[Long] {
def foo(i: Long) = Foo(i)
}
}
def bar[T](x: T)(implicit ev: CanFoo[T]) =
ev.foo(x)
bar(0)
bar("hello")
bar(true)
bar(0.toLong)
Scala compiler detects the following two map functions as duplicates conflicting with each other:
class ADT {
def map[Output <: AnyVal](f: Int => Output): List[Output] = ???
def map[Output >: Null <: AnyRef](f: Int => Output): List[Output] = ???
}
The class type of Output parameter is different. First one limits to AnyVal and second one limits to AnyRef. How can I differentiate them?
The problem is not differentiating AnyVal from AnyRef so much as getting around the fact that both method signatures become the same after erasure.
Here is a neat trick to get around this kind of problem. It is similar to what #som-snytt did, but a bit more generic, as it works for other similar situations as well (e.g. def foo(f: Int => String): String = ??? ; def foo(f: String => Int): Int = ??? etc.):
class ADT {
def map[Output <: AnyVal](f: Int => Output): List[Output] = ???
def map[Output >: Null <: AnyRef](f: Int => Output)(implicit dummy: DummyImplicit): List[Output] = ???
}
The cutest thing is that this works "out of the box". Apparently, a DummyImplicit is a part of standard library, and you always have the thing in scope.
You can have more than two overloads this way too by just adding more dummies to the list.
scala 2.13.0-M5> :pa
// Entering paste mode (ctrl-D to finish)
object X {
def map[Output <: AnyVal](f: Int => Output) = 1
def map[O](f: Int => O)(implicit ev: O <:< AnyRef) = 2
}
// Exiting paste mode, now interpreting.
defined object X
scala 2.13.0-M5> X.map((x: Int) => x*2)
res0: Int = 1
scala 2.13.0-M5> X.map((x: Int) => "")
res1: Int = 2
You could use a typeclass for that map method.
Using your exact example:
trait MyTC[Output]{
def map(f: Int => Output): List[Output]
}
object MyTC{
def apply[A](a : A)(implicit ev : MyTC[A]) : MyTC[A] = ev
implicit def anyRefMyTc[A <: AnyRef] : MyTC[A] = new MyTC[A]{
def map(f: Int => A): List[A] = { println("inside sub-AnyRef"); List.empty }
}
implicit def anyValMyTc[A <: AnyVal] : MyTC[A] = new MyTC[A]{
def map(f: Int => A): List[A] = { println("inside sub-AnyVal"); List.empty }
}
}
import MyTC._
val r1 = Option("Test1")
val r2 = List(5)
val v1 = true
val v2 = 6L
// The functions here are just to prove the point, and don't do anything.
MyTC(r1).map(_ => None)
MyTC(r2).map(_ => List.empty)
MyTC(v1).map(_ => false)
MyTC(v2).map(_ => 10L)
That would print:
inside sub-AnyRef
inside sub-AnyRef
inside sub-AnyVal
inside sub-AnyVal
The advantage of this approach is that, should you then choose to specialise the behaviour further for just some specific type (e.g. say you want to do something specific for Option[String]), you can do that easily:
// This is added to MyTC object
implicit val optMyTc : MyTC[Option[String]] = new MyTC[Option[String]]{
def map(f: Int => Option[String]): List[Option[String]] = { println("inside Option[String]"); List.empty }
}
Then, re-running the code will print:
inside Option[String]
inside sub-AnyRef
inside sub-AnyVal
inside sub-AnyVal
Suppose I've got partial function parf
val parf: PartialFunction[Int, String] = { case 0 => "!!!" }
Now I've got also case class A(x: Int) and I need a function to transform PartialFunction[Int, String] to PartialFunction[A, String]:
def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = ???
For example, foo(parf) should return {case A(0) => "!!!" }. How would you write function foo ?
To maintain the correct functionality, you need to check if the inner partial function is defined on a parameter you're going to pass:
val parf: PartialFunction[Int, String] = { case 0 => "!!!" }
case class A(x: Int)
def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = {
case A(i) if pf.isDefinedAt(i) => pf(i)
}
If you plan to do it on a larger scale, you might want to convert a partial function to an extractor object, so it can be used in pattern matches directly with a better syntax:
trait Extractor[A, B] {
def unapply(a: A): Option[B]
}
object Extractor {
implicit def partialFunctionAsExtractor[A, B](pf: PartialFunction[A, B]): Extractor[A, B] =
new Extractor[A, B] {
def unapply(a: A) = if (pf.isDefinedAt(a)) Some(pf(a)) else None
}
}
def foo2(pf: Extractor[Int, String]): PartialFunction[A, String] = {
case A(pf(str)) => str
}
foo2(parf) // implicit conversion magic
I don't see what got you confused about it? You just need to match-extract the Int out of A and then let the PF behave as it wants to behave.
scala> case class A(x: Int)
// defined class A
scala> val parf: PartialFunction[Int, String] = { case 0 => "!!!" }
// parf: PartialFunction[Int,String] = <function1>
scala> def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = {
| case A(x) if pf.isDefinedAt(x) => pf(x)
| }
// foo: (pf: PartialFunction[Int,String])PartialFunction[A,String]
scala> val parfA = foo(parf)
// parfA: PartialFunction[A,String] = <function1>
scala> parfA(A(0))
//res0: String = !!!
scala> parfA(A(1))
// scala.MatchError: A(1) (of class A)
// at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254)
// at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:252)
// at $anonfun$1.applyOrElse(<console>:11)
// at $anonfun$1.applyOrElse(<console>:11)
// at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
// at $anonfun$foo$1.applyOrElse(<console>:13)
// at $anonfun$foo$1.applyOrElse(<console>:13)
// at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
// ... 28 elided
#Oleg Pyzhcov already provided a great solution. Another approach would be to create a PartialFunction[A, Int] that is defined at A(0), and use andThen to chain it with parf:
val parf: PartialFunction[Int, String] = { case 0 => "!!!" }
case class A(n: Int)
val bar: PartialFunction[A, Int] = { case a: A if a.n == 0 => a.n }
def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] =
bar andThen pf
// foo: (pf: PartialFunction[Int,String])PartialFunction[A,String]
foo(parf)
// res1: PartialFunction[A,String] = <function1>
Given any method, eg
def add(x: Int, y: Int) = {
x + y
}
Can I use any inspection/reflection library to obtain the arity of add?
Something like arity(add), since the function object does not seems to have a property to provide that information.
One type-safe solution is to overload your Node's constructor for each Function* trait that corresponds to the arity of a function that you will pass as a parameter:
scala> class Node {
| def this(f: Function0[Int]) = { this(); println(0) }
| def this(f: Function1[Int, Int]) = { this(); println(1) }
| def this(f: Function2[Int, Int, Int]) = { this(); println(2) }
| }
defined class Node
scala> new Node(add _)
2
res7: Node = Node#427128a6
If your situation requires a reflection-based approach somehow, you can count the number of parameters of the apply method that all the Function* traits share, as follows:
scala> def arity(f: AnyRef): Option[Int] = {
| val apply = f.getClass.getMethods.find(_.getName == "apply")
| apply.map(_.getParameterCount)
| }
arity: (f: AnyRef)Option[Int]
scala> arity(add _)
res0: Option[Int] = Some(2)
Or you might want to consider using typed patterns:
def arity(f: AnyRef): Int = f match {
case _: Function0[_] => 0
case _: Function1[_, _] => 1
case _: Function2[_, _, _] => 2
...
}
So, basically, what I want to do is:
object WithoutWrap {
def f[T: ClassTag](x: String): T = {
println("Class of T is really… " ++ implicitly[ClassTag[T]].toString)
??? : T
}
def y: Int = f("abc")
def z: Int = f[Int]("abc")
}
In both cases I’d like the inferred T to be Int. Let’s run this:
scala> WithoutWrap.y
Class of T is really… Nothing
scala.NotImplementedError: an implementation is missing
scala> WithoutWrap.z
Class of T is really… Int
scala.NotImplementedError: an implementation is missing
Unfortunately it’s Nothing in the first case.
However, if we return the T wrapped in something,
object WithWrap {
trait Wrap[T]
def f[T: ClassTag](x: String): Wrap[T] = {
println("Class of T is really… " ++ implicitly[ClassTag[T]].toString)
??? : Wrap[T]
}
def y: Wrap[Int] = f("abc")
def z: Wrap[Int] = f[Int]("abc")
}
… the T is inferred correctly in both cases:
scala> WithWrap.y
Class of T is really… Int
scala.NotImplementedError: an implementation is missing
scala> WithWrap.z
Class of T is really… Int
scala.NotImplementedError: an implementation is missing
How to get Int in both cases without wrapping?
Depending on what you're trying to accomplish, overload resolution is sensitive to expected type:
scala> case class A(s: String) ; case class B(s: String)
defined class A
defined class B
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X {
def f(s: String): A = A(s)
def f(s: String)(implicit d: DummyImplicit): B = B(s)
}
// Exiting paste mode, now interpreting.
defined object X
scala> val x: A = X f "hi"
x: A = A(hi)
scala> val y: B = X f "hi"
y: B = B(hi)