currently i have this:
private def isCollectionLike[T](manifest: Manifest[T]):Boolean = {
manifest.runtimeClass.toString.contains("scala.collection")
}
I don't like this solution, can you purpose a better one?
Just callingClass#isAssignable should be enough:
def isCollectionLike[T](manifest: Manifest[T]):Boolean = {
classOf[scala.collection.TraversableLike[_,_]].isAssignableFrom(manifest.runtimeClass)
}
Mandatory REPL test:
scala> isCollectionLike(manifest[List[Int]])
res17: Boolean = true
scala> isCollectionLike(manifest[String])
res18: Boolean = false
scala> isCollectionLike(manifest[scala.collection.SeqLike[Int,_]])
res19: Boolean = true
Note though that this won't work with arrays, for the simple reason that scala arrays now (since scala 2.8) map directly to the udnerlying JVM arrays,
and as such do not inherit TraversableLike (If interested you can have a look at http://docs.scala-lang.org/sips/completed/scala-2-8-arrays.html).
scala> isCollectionLike(manifest[Array[String]])
res20: Boolean = false
So you'll have to handle it as a special case, or find a better way to test for a collection.
As a side note, these days there is an alternative to java reflection scala's own reflection api (and in addition Manifest is deprecated in favor of TypeTag),
which has the immense advantage of understanding all the scala specific features
(that Class instance retruned by runtimeClass does not know anything about scala).
But it is also more complex, and (currently) not thread safe at all, which is a major limitation.
Plus in your case you will still have to handle arrays as a special case anyway.
Related
I just had a look into the cats library in scala, more specifically the State Monad.
As a toy example I wanted to create some logic that splits a potentially large string (the StringBuilder) and returns the split up String and the remaining StringBuilder:
object Splitter {
def apply(maxSize: Int, overlap: Int): State[StringBuilder, String] = State(
builder => {
val splitPoint = math.min(builder.size, maxSize + overlap)
(builder.drop(maxSize), builder.substring(0, splitPoint))
}
)
}
Running one step of the State monad works fine but I wanted to chain all the steps until the StringBuilder eventually is empty:
val stop = State.inspect((s: StringBuilder) => s.isEmpty)
Splitter(3, 2).untilM[Vector](stop).run(new StringBuilder("tarsntiars"))
However, this doesn't work as untilM is a member of the Monad trait and there are no implicit conversions in scope. What works is:
val monad = StateT.catsDataMonadForStateT[Eval, StringBuilder]
monad.untilM[List, String](Splitter(3, 2))(stop).run(new StringBuilder("tarsntiars"))
However, I think the shorter is much more readable so I am wondering why it doesn't work? Why does the usual MonadOps mechanism doesn't work here?
After SI-2712 was fixed, the Unapply workaround was removed from Cats: https://github.com/typelevel/cats/pull/1583. Now you need the -Ypartial-unification compiler flag (assuming you are using Scala 2.11 or 2.12) in order for State to be treated as a Monad.
Scalaz still has the Unapply machinery so your code should work with Scalaz without the compiler flag.
In my team, I often see teammates writing
list.filter(_.isInstanceOf[T]).map(_.asInstanceOf[T])
but this seems a bit redundant to me.
If we know that everything in the filtered list is an instance of T then why should we have to explicitly cast it as such?
I know of one alternative, which is to use match.
eg:
list.match {
case thing: T => Some(thing)
case _ => None
}
but this has the drawback that we must then explicitly state the generic case.
So, given all the above, I have 2 questions:
1) Is there another (better?) way to do the same thing?
2) If not, which of the two options above should be preferred?
You can use collect:
list collect {
case el: T => el
}
Real types just work (barring type erasure, of course):
scala> List(10, "foo", true) collect { case el: Int => el }
res5: List[Int] = List(10)
But, as #YuvalItzchakov has mentioned, if you want to match for an abstract type T, you must have an implicit ClassTag[T] in scope.
So a function implementing this may look as follows:
import scala.reflect.ClassTag
def filter[T: ClassTag](list: List[Any]): List[T] = list collect {
case el: T => el
}
And using it:
scala> filter[Int](List(1, "foo", true))
res6: List[Int] = List(1)
scala> filter[String](List(1, "foo", true))
res7: List[String] = List(foo)
collect takes a PartialFunction, so you shouldn't provide the generic case.
But if needed, you can convert a function A => Option[B] to a PartialFunction[A, B] with Function.unlift. Here is an example of that, also using shapeless.Typeable to work around type erasure:
import shapeless.Typeable
import shapeless.syntax.typeable._
def filter[T: Typeable](list: List[Any]): List[T] =
list collect Function.unlift(_.cast[T])
Using:
scala> filter[Option[Int]](List(Some(10), Some("foo"), true))
res9: List[Option[Int]] = List(Some(10))
but this seems a bit redundant to me.
Perhaps programmers in your team are trying to shield that piece of code from someone mistakenly inserting a type other then T, assuming this is some sort of collection with type Any. Otherwise, the first mistake you make, you'll blow up at run-time, which is never fun.
I know of one alternative, which is to use match.
Your sample code won't work because of type erasure. If you want to match on underlying types, you need to use ClassTag and TypeTag respectively for each case, and use =:= for type equality and <:< for subtyping relationships.
Is there another (better?) way to do the same thing?
Yes, work with the type system, not against it. Use typed collections when you can. You haven't elaborated on why you need to use run-time checks and casts on types, so I'm assuming there is a reasonable explanation to that.
If not, which of the two options above should be preferred?
That's a matter of taste, but using pattern matching on types can be more error-prone since one has to be aware of the fact that types are erased at run-time, and create a bit more boilerplate code for you to maintain.
Is there a way to tell whether a class was implemented in Scala?
I'm building on a serialization system for the JVM that deals extensively with reflection. Java classes are already handled but the method is inadequate for Scala classes (for example, in Scala List[Int] turns into List[Object] in Java's reflection system, but this lost information is recoverable with scala's reflection). It like a switch to say whether I should perform scala-specific handling of a class.
def isJavaClass( cls: Class[_] ): Boolean = {
import scala.reflect.runtime.{universe=>ru}
val sym = ru.runtimeMirror(cls.getClassLoader).classSymbol(cls)
sym.isJava
}
REPL test:
scala> isJavaClass(classOf[List[Any]])
res0: Boolean = false
scala> isJavaClass(classOf[java.util.List[Any]])
res1: Boolean = true
I have code that monitors the progress of a foreach method but needs to be able to detect whether the foreach loop will happen in parallel to choose the appropriate progress tracking algorithm. Spent time tracking down a bug and isolated it to this:
scala> Vector(1,2,3).iterator.isParallel
res11: Boolean = false
scala> Vector(1,2,3).isParallel
res12: Boolean = false
scala> Vector(1,2,3).par.isParallel
res13: Boolean = true
...
scala> Vector(1,2,3).par.splitter.isParallel
res13: Boolean = false
scala> Vector(1,2,3).par.iterator.isParallel
res14: Boolean = false
Is this a bug or do I misunderstand the function?
the isParallel method is defined in the TraversableOps class, which you get from various of the collection classes via an implicit conversion. The relevant source snippet (from scala/collection/parallel/package.scala) is:
implicit def traversable2ops[T](t: scala.collection.GenTraversableOnce[T]) = new TraversableOps[T] {
def isParallel = t.isInstanceOf[Parallel]
...
}
As can be seen from this, a class needs to extend the Parallel marker trait to return true from this method. As it turns out, the various parallelised collections do this, but their iterators don't. That is, it appears that Parallel has only been used to mark the actual collections, not their helpers. I don't know whether that is as intended or if it could be argued to be an oversight.
Does Scala provide a built-in class, utility, syntax, or other mechanism for converting (by wrapping) an Iterator with an Iterable?
For example, I have an Iterator[Foo] and I need an Iterable[Foo], so currently I am:
val foo1: Iterator[Foo] = ....
val foo2: Iterable[Foo] = new Iterable[Foo] {
def elements = foo1
}
This seems ugly and unnecessary. What's a better way?
Iterator has a toIterable method in Scala 2.8.0, but not in 2.7.7 or earlier. It's not implicit, but you could define your own implicit conversion if you need one.
You should be very careful about ever implicitly converting an Iterator into an Iterable (I normally use Iterator.toList - explicitly). The reason for this is that, by passing the result into a method (or function) which expects an Iterable, you lose control of it to the extent that your program might be broken. Here's one example:
def printTwice(itr : Iterable[String]) : Unit = {
itr.foreach(println(_))
itr.foreach(println(_))
}
If an Iterator were somehow implicitly convertible into an Iterable, what will the following would print?
printTwice(Iterator.single("Hello"))
It will (of course) only print Hello once. Very recently, the trait TraversableOnce has been added to the collections library, which unifies Iterator and Iterable. To my mind, this is arguably a mistake.
My personal preference is to use Iterator explicitly wherever possible and then use List, Set or IndexedSeq directly. I have found that I can rarely write a method which is genuinely agnostic of the type it is passed. One example:
def foo(trades: Iterable[Trade]) {
log.info("Processing %d trades", trades.toList.length) //hmmm, converted to a List
val shorts = trades.filter(_.side.isSellShort)
log.info("Found %d sell-short", shorts.toList.length) //hmmm, converted to a List again
//etc