Given
trait A
case class B extends A
trait C
I'm trying to implement something akin to this:
val m = scala.collection.mutable.HashMap[String, C=>Option[A]](
... //some pre-defined mappings
).withDefaultValue((_:C) => None)
This will give me a type mismatch:
expected: C=>Option[A], actual: C=>None.type
I heard scala expects None to be returned from a catch clause, so I tried the very ugly
val m = scala.collection.mutable.HashMap[String, C=>Option[A]](
... //some pre-defined mappings
).withDefaultValue((_:C) => try {
throw new RuntimeException()
Some(B())
} catch{ case _ => None}
)
But that (thankfully) didn't work either:
type mismatch, expected: C=>Option[A], actual: C=>Option[B]
What's the proper way to do what I am trying to?
None is an instance of Option[Nothing]. But Option is covariant in its type parameter, and Nothing is a subtype of everything.
This means that None is a subtype of Option[A]. Just say so:
None: Option[A]
But type inference can usually do it for you. If you create the function in advance,
val default = (c: C) => None
then you'll get the wrong return type and need to specify it, but withDefaultValue should already know the type of your map.
Related
I want to create a general purpose method def getOptionalArgs[T](): List[String] such that when passed a type, it returns the list of all arguments to that type that are an Option[_]
E.g. I have a case class Foo(bar: String, baz: Option[String]). In this case, getOptionalArgs[Foo]() would return List("baz").
I've been messing around with the reflections library, and I think I'm close via:
import scala.reflect.runtime.{universe, universe => ru}
def getOptionalArgs[T]() = {
val constructor = ru.typeOf[T].decl(ru.termNames.CONSTRUCTOR).asMethod
...
}
But I cant figure out how map/filter the reflected constructors parameters. What is missing here?
Update
constructor.paramLists.head.map(t => (t.name.toString, t.info)) will return List[(String, reflect.runtime.universe.Type)] = List((bar,Int), (baz,Option[Int])). So Its very close. Now I have to be able to figure out how to test equality between Type, and no, equals doesn't seem to work.
The solution is:
val constructor = ru.typeOf[I].decl(ru.termNames.CONSTRUCTOR).asMethod
val notOptionalColNames = constructor.paramLists.head
.map(t => (t.name.toString, t.info))
.filter(t => !(t._2 <:< typeTag[Option[_]].tpe)).map(_._1)
I'm trying to come up with a generic function that can take primitive data types and also other objects that extends scala.math.Ordering.
I checked How to get to type parameters of a reflect.runtime.universe.Type in scala?
and I want to get the type of a variable at runtime and I could't get my answer.
Example below:
import scala.reflect.runtime.universe._
import scala.collection.SortedSet
def getTypeTag[T: TypeTag](obj: T) = typeTag[T]
def createSortedSet[A: TypeTag](y: A) = typeOf[A] match{
//handle the primitive data types
case t1 if t1 =:= typeOf[Int] =>
SortedSet(y)(implicitly[Ordering[Int]].reverse)
case t2 if t2 =:= typeOf[Long] =>
SortedSet(y)(implicitly[Ordering[Long]].reverse)
.....
// last part handle any object that implements Comparable
case tx if tx.getClass.getInterfaces.exists( _.toString == "interface java.lang.Comparable") =>
{// trying to get the type of the variable and then pass in to the Ordering
val TT: Type = getTypeTag(t).tpe
SortedSet(y)(implicitly[Ordering[TT]].reverse)}
case _ => ...
}
so in order to pass in a object and let the Ordering do its job, I need to pass in the type to the Ordering, Say I create a case class that extends Ordering
case class Value(i: Int) extends Ordered[Value] {def compare(that: Value) = this.i - that.i}
val v1 = Value(3)
// now I want to get a SortedSet instance by calling the createSortedSet
createSortedSet(v1)
I got error when I made the above call, so I think reflect.runtime.universe.Type is not really can be used as Type. Is my approach wrong?
You can make it much simpler:
def sortedSet[T : Ordering](t:T) = SortedSet(t)(implicitly[Ordering[T]].reverse)
That works for the use case you describe, don't need to differentiate between primitives and other objects, or get the actual type at runtime. When calling this function, the compiler will make sure there's an Ordering available for the type being used (Or fail if there's not).
In your case with Value, he will implicitly provide one, based on your implementation of Ordered
if i have a class that accepts a Type argument for example Seq[T] , and i've many objects of this class. and i want to split them depending on type Argument T
for example :
val x = List(Seq[Int](1,2,3,4,5,6,7,8,9,0),Seq[String]("a","b","c"))
x.foreach { a =>
a match{
case _ : Seq[String] => print("String")
case _ : Seq[Int] => print("Int")
}
}
the result of this code is StringString.
it only matches the class Seq not the Type also , what should i do to force it to match the Type ?
What you're seeing happens due to Type Erasure (http://docs.oracle.com/javase/tutorial/java/generics/erasure.html), some IDEs can warn you for errors like these.
You could have a look at Manifests, for example check out What is a Manifest in Scala and when do you need it?
Edit: like Patryk said, TypeTag replaced Manifest in Scala 2.10, see Scala: What is a TypeTag and how do I use it?
TypeTag Approach
The Java runtime requires generic type param erasure. Scala compiler combats this by 'injecting' type info into methods declared with TypeTag type arg:
def typeAwareMethod[T: TypeTag] (someArg: T) {
... // logic referring to T, the type of varToCheck
}
(alternatively, can use an equivalent, more long-winded implicit param - not shown)
When scala compiles an invocation of a method having (1) type arg [T: TypeTag] and (2) normal arg someArg: T, it collects type param metadata for someArg from the calling context and augments the type arg T with this metadata. T's value plus tag data are externaly type-inferred from calls:
val slimesters = List[Reptile](new Frog(...), new CreatureFromBlackLagoon(...))
typeAwareMethod(slimesters)
Logic Referring to T (within above method) - runtime reflection
import scala.reflection.runtime.universe._ : contents of the universe object of type scala.relection.api.JavaUniverse. NB: subject to evolutionary API change
Direct TypeTag comparison:
The tag info can be obtained via method typeTag[T], then directly tested/pattern matched for (exact) equality with other type tags:
val tag: TypeTag[T] = typeTag[T]
if (typeTag[T] == typeTag[List[Reptile]]) ...
typeTag[T] match {
case typeTag[List[Reptile]] => ...
}
Limitations: not subtype aware (above won't match List[Frog]); no additional metadata obtainable through TypeTag.
Smarter Type-comparison operations:
Convert to Type via typeOf[T] (or typeTag[T].tpe). Then use the gammut of Type ops, including pattern-matching. NB: in reflection typespace, =:= means type equivalance (analogue of :), <:< means type conformance (analogue of <:)
val tType: Type = typeOf[T] // or equivalently, typeTag[T].tpe
if (typeOf[T] <:< typeOf[List[Reptile]]) ... // matches List[Frog]
typeOf[T] match {
case t if t <:< typeOf[List[Reptile]] => ...
}
// Running Example:
def testTypeMatch[T: TypeTag](t: T) = if (typeOf[T] <:< typeOf[Seq[Int]]) "yep!!!"
test(List[Int](1, 2, 3)) // prints yep!!!
Method still needs type param [T: TypeTag] or you'll get the type-erasure view of the world...
Introspect on Type metadata
I lied in 2 ;). For your case, typeOf[T] actually returns TypeRef (a subtype of Type), since you're instantiating a type declared elsewhere. To get at the full metadata, you need to convert Type to TypeRef.
typeTag[T].tpe match {
case t: TypeRef => ... // call t.args to access typeArgs (as List[Type])
case _ => throw IllegalArgumentException("Not a TypeRef")
}
instead of t: TypeRef, can extract parts via pattern match on:
case TypeRef(prefixType, typeSymbol, typeArgsListOfType) =>
Type has method:
def typeSymbol: Symbol
Symbol has methods:
def fullName: String
def name: Name
Name has methods:
def decoded: String // the scala name
def encoded: String // the java name
Solution For Your Case
Solution based on (3):
import scala.reflect.runtime.universe._
def typeArgsOf[T: TypeTag](a: T): List[Type] = typeOf[T] match {
case TypeRef(_, _, args) => args
case _ => Nil
}
val a = Seq[Int](1,2,3,4,5,6,7,8,9,0)
val b = Seq[String]("a","b","c")
// mkString & pring for debugging - parsing logic should use args, not strings!
print("[" + (typeArgsOf(a) mkString ",") + "]")
print("[" + (typeArgsOf(b) mkString ",") + "]")
Aside: there's an issue with this test case:
val x = List(Seq[Int](1,2,3,4,5,6,7,8,9,0),Seq[String]("a","b","c"))
Type of x is List[Seq[Any]]. Any is the lowest common ancestor of String and Int. In this case there's nothing to introspect, since all types descend from Any , and there's no further type information available. To get stronger typing, separate the two Seqs, either via separate variables or a tuple/pair - but once separated, no higher order common mapping / folding across the two. "Real world" cases shouldn't have this problem.
I would argue it's equally sensible to def the logic with multiple prototypes one per sequence type, than go into those type-erasure workarounds. The 2.10 compiler doesn't warn about type erasure, and at runtime it seems to work well in my case.
Presumably this avoids the problem, producing more intelligible code.
How can I fix this type error?
object Test extends App {
def printOption[A](a: Option[A]): Option[A] = { println(a getOrElse("none")); a }
def printHashCodeAndMap[A, B](fn: Option[A] => Option[B], list: List[Option[A]]): List[Option[B]] = {
for (elem <- list) yield fn(elem.map{a => println(a.hashCode()); a})
}
val optListA = List(Some("aa"), None, Some(5))
val optListB = printHashCodeAndMap(printOption, optListA)
for (x <- optListB) printOption(x)
}
The error I get is:
error: type mismatch;
found : Option[Nothing] => Option[Nothing]
required: Option[Any] => Option[Nothing]
val optListB = printHashCodeAndMap(printOption, optListA)
The problem is with how scala infers type parameters. Types information flows from left to right across parameter groups but not within the same parameter group.
What that means is: the type parameter of printOption, A can be inferred only if A has been bound to a real type in a parameter group that precedes it's occurrence. In your printHashCodeAndMap, this is not the case. So, there are two ways to get this to work.
i. You can forsake the type inference and explicitly specify the types of fn by passing it printOption[Any]. Or you could just specify the type parameters of printHashCodeAndMap when you call it (i.e. printHashCodeAndMap[Any, Any](printOption, optListA))
ii. If you wanted to use scala's type inferrence, you'd want the type information for A to come from optListA which is of type List[Option[Any]]. To make that happen the parameter list has to be in a parameter group that precedes fn. Like this:
def printHashCodeAndMap[A, B](list: List[Option[A]])(fn: Option[A] => Option[B]): List[Option[B]] = { ... }
Then you will be able to call it like this:
printHashCodeAndMap(optListA)(printOption)
val optListB = printHashCodeAndMap(printOption[Any], optListA)
The types of symbols class A[_] or of def a[_](x: Any) have a type parameter that can't be referenced in the body, thus I don't see where it is useful for and why it compiles. If one tries to reference this type parameter, an error is thrown:
scala> class A[_] { type X = _ }
<console>:1: error: unbound wildcard type
class A[_] { type X = _ }
^
scala> def a[_](x: Any) { type X = _ }
<console>:1: error: unbound wildcard type
def a[_](x: Any) { type X = _ }
^
Can someone tell me if such a type has a use case in Scala? To be exact, I do not mean existential types or higher kinded types in type parameters, only those litte [_] which form the complete type parameter list.
Because I did not get the answers I expected, I brought this to scala-language.
I paste here the answer from Lars Hupel (so, all credits apply to him), which mostly explains what I wanted to know:
I'm going to give it a stab here. I think the use of the feature gets
clear when talking about type members.
Assume that you have to implement the following trait:
trait Function {
type Out[In]
def apply[In](x: In): Out[In]
}
This would be a (generic) function where the return type depends on
the input type. One example for an instance:
val someify = new Function {
type Out[In] = Option[In] def
apply[In](x: In) = Some(x)
}
someify(3) res0: Some[Int] = Some(3)
So far, so good. Now, how would you define a constant function?
val const0 = new Function {
type Out[In] = Int
def apply[In](x: In) = 0
}
const0(3) res1: const0.Out[Int] = 0
(The type const0.Out[Int] is equivalent to Int, but it isn't
printed that way.)
Note how the type parameter In isn't actually used. So, here's how
you could write it with _:
val const0 = new Function {
type Out[_] = Int
def apply[In](x: In) = 0
}
Think of _ in that case as a name for the type parameter which
cannot actually be referred to. It's a for a function on the type
level which doesn't care about the parameter, just like on value
level:
(_: Int) => 3 res4: Int => Int = <function1>
Except …
type Foo[_, _] = Int
<console>:7: error: _ is already defined as type _
type Foo[_, _] = Int
Compare that with:
(_: Int, _: String) => 3 res6: (Int, String) => Int = <function2>
So, in conclusion:
type F[_] = ConstType // when you have to implement a type member def
foo[_](...) // when you have to implement a generic method but don't
// actually refer to the type parameter (occurs very rarely)
The main thing you mentioned, class A[_], is completely symmetric to
that, except that there's no real use case.
Consider this:
trait FlyingDog[F[_]] { def swoosh[A, B](f: A => B, a: F[A]): F[B] }
Now assume you want to make an instance of FlyingDog for your plain
old class A.
new FlyingDog[A] { ... }
// error: A takes no type parameters, expected: one
// (aka 'kind mismatch')
There are two solutions:
Declare class A[_] instead. (Don't do that.)
Use a type lambda:
new FlyingDog[({ type λ[α] = A })#λ]
or even
new FlyingDog[({ type λ[_] = A })#λ]
I had some casual ideas about what it could mean here:
https://issues.scala-lang.org/browse/SI-5606
Besides the trivial use case, asking the compiler to make up a name because I really don't care (though maybe I'll name it later when I implement the class), this one still strikes me as useful:
Another use case is where a type param is deprecated because
improvements in type inference make it superfluous.
trait T[#deprecated("I'm free","2.11") _, B <: S[_]]
Then, hypothetically,
one could warn on usage of T[X, Y] but not T[_, Y].
Though it's not obvious whether the annotation would come before (value parameter-style) or after (annotation on type style).
[Edit: "why it compiles": case class Foo[_](i: Int) still crashes nicely on 2.9.2]
The underscore in Scala indicates an existential type, i.e. an unknown type parameter, which has two main usage:
It is used for methods which do not care about the type parameter
It is used for methods where you want to express that one type parameter is a type constructor.
A type constructor is basically something that needs a type parameter to construct a concrete type. For example you can take the following signature.
def strangeStuff[CC[_], B, A](b:B, f: B=>A): CC[A]
This is a function that for some CC[_] , for example a List[_], creates a List[A] starting from a B and a function B=>A.
Why would that be useful? Well it turns out that if you use that mechanism together with implicits and typeclasses, you can get what is called ad-hoc polymorphism thanks to the compiler reasoning.
Imagine for example you have some higher-kinded type: Container[_] with a hierarchy of concrete implementations: BeautifulContainer[_], BigContainer[_], SmallContainer[_]. To build a container you need a
trait ContainerBuilder[A[_]<:Container[_],B] {
def build(b:B):A[B]
}
So basically a ContainerBuilder is something that for a specific type of container A[_] can build an A[B] using a B.
While would that be useful ? Well you can imagine that you might have a function defined somewhere else like the following:
def myMethod(b:B)(implicit containerBuilder:ContainerBuilder[A[_],B]):A[B] = containerBuilder.build(b)
And then in your code you might do:
val b = new B()
val bigContainer:BigContainer[B] = myMethod(b)
val beautifulContainer:BeautifulContainer[B] = myMethod(b)
In fact, the compiler will use the required return type of myMethod to look for an implicit which satisfies the required type constraints and will throw a compile error if there is no ContainerBuilder which meets the required constraints available implicitely.
That's useful when you deal with instances of parametrized types without caring of the type parameter.
trait Something[A] {
def stringify: String
}
class Foo extends Something[Bar] {
def stringify = "hop"
}
object App {
def useSomething(thing: Something[_]) :String = {
thing.stringify
}
}