everyone . Please forgive me asking a stupid question on Scala.
Though I have been programming in Scala for about 2 years, I still find it hard to understand implicit usage. Let's take an example for discussion:
Array(1,2,3,4).map(x => x)
If you look up the scaladoc, you cant' find the method map on Array class. The reason that map can apply on Array(1,2,3,4) is that there is an implicit function implicit def intArrayOps (xs: Array[Int]): ArrayOps[Int] defined in scala.Predef.
However, there are two parameter lists, where the second one is written as implicit bf: CanBuildFrom[Array[T], B, That]). Now I wonder where the compiler finds a proper argument for type CanBuildFrom when applying map on Array(1,2,3,4).
The implicit resolution includes searching the companion object for the type of the implicit parameter as well as the companion objects for the type parameters of the implicit parameter. In the example above the signature of map is the following
def map[B, That](f: (Int) => B)(implicit bf: CanBuildFrom[Array[Int], B, That]): That
Since we have no type requirements for That we can ignore it for now. After we look in the local and container scopes and find no matching implicits, the next place to look for an implicit would be the companion object for CanBuildFrom. However it has no companion object. So we continue on and look in Array for an implicit. We find one in the form of
implicit def canBuildFrom[T](implicit m: ClassManifest[T]): CanBuildFrom[Array[_], T, Array[T]]
Since we have no type requirements and a matching implicit, "That" is forced to be of type Array[Int] and completes our typing.
This question is partially answered with other question on StackOverflow. Let me give a try to summarize them:
The first part you need to know is where the Scala compiler looks for implicits. You can find some more detail about CanBuildFrom here.
If you have understood what is mentioned in the answers about implicits ‣you should take a look to the construction of Scala Collections. Their inheritance-hierarchy is explained here and for List here. All of them are build up with Builders. This is explained in detail in a question about breakOut.
To round up your knowledge, you should know how to pimp the Collections. Also, this is explained on StackOverflow in this question.
Please note, the best answers on StackOverflow are summarized in the Scala-Tag-Wiki.
Related
In cats there are 2 semigroup types classes: Semigroup and SemigroupK with the latter working on type constructors.
I fail to see the advantages of the latter over the former. If I look at the list instances they are providing Monoid (although there is a MonoidK), whereas NonEmptyList is providing a SemigroupK. Note that NonEmptyList is also providing a Semigroup via the following method:
implicit def catsDataSemigroupForNonEmptyList[A]: Semigroup[NonEmptyList[A]] =
SemigroupK[NonEmptyList].algebra[A]
Why the discrepancy?
Then it seems that most semigroup operations are only available on Semigroup and not SemigroupK (there's reduceK in Reducible but that's the only one I saw, and it delegates to reduce which works on Semigroup).
So, given a type T[_], what would you gain by having both a SemigroupK[T] and a Semigroup[T[A]] for some A?
Edit
There's now an issue to remove MonoidK and SemigroupK: https://github.com/typelevel/cats/issues/1932
One thing you can do with SemigroupK which you can't do with Semigroup is to compose instances for Nested:
implicit def catsDataSemigroupKForNested[F[_]: SemigroupK, G[_]]: SemigroupK[Nested[F, G, ?]]
If you try to write an equivalent for Semigroup, I think the closest you would get is
implicit def catsDataSemigroupForNested[F[_], G[_], A](implicit sg: Semigroup[F[G[A]]]): Semigroup[F[G[A]]] // or Semigroup[Nested[F, G, A]]
which is not very useful! From search, I can't see anything else which is implemented for SemigroupK and can't be done using Semigroup, but I might have missed something.
But the main point of SemigroupK is that once you have it, you can automatically get a Semigroup too, exactly like NonEmptyList does.
I am new to Scala and I was learning "context bound" from posts. But I found many of those are explaining "context bound" using ClassManifest as example. For instance,
def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
I find it weird that the implicit parameter m is required but never used in the function body. Thus I would like to know what ClassManifest is and what its relationship is with context bound. Thanks!
EDIT:
I have seen What is a Manifest in Scala and when do you need it? before, but it's asking for Manifest not ClassManifest, and there is no explanation regarding ClassManifest in that post, thus I ask this similar (but, IMO, not duplicate) question.
You can find explanation about ClassManifest for old scala versions (before 2.10) here. Please, read all answers, some of them explain not only Manifest but ClassManifest too:
There exists also a weaker form named ClassManifest which can be
constructed from knowing just the top-level class of a type, without
necessarily knowing all its argument types.
In Scala 2.11.8, 2.12-M4 ClassManifest is deprecated and became an alias to ClassTag :
type ClassManifest[T] = ClassTag[T]
It's deprecated since 2.10.0.
P.S. Actually this post from scala documentation that you probably read is completely outdated, even the view bounds (<%) described there are deprecated too (for a quite long time) so you should avoid them as well (using this simple trick if you really need them, but implicit views are not recommended in any form)
There are a lot of places in the Scala API, particularly in collections, where method signatures are wrong.
For example, the scaladoc signature for Map.flatMap says
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): Map[B]
But the actual signature is
flatMap[B, That](f: ((A, B)) ⇒ GenTraversableOnce[B])
(implicit bf: CanBuildFrom[Map[A, B], B, That]): That
This one especially makes no sense because the scaladoc signature includes Map[B], but Map has two type parameters, not one.
What's going on here? Is this a mistake?
The incorrect signatures you're see in the generated documentation are called "use cases". They're supposed to clarify the documentation by showing idealized API, similar to the real one but omitting tedious details (like the pervasive implicit CanBuildFrom parameter which bothers some people).
For methods with use cases, you can get to the real signature by clicking the method name to show the details for that method, and then clicking "Full Signature" to expand another section that shows the signature.
References
Scala issue SI-3448, created May 2010, deals specifically with the wrong number of type parameters being shown for Map. This issue as closed "Won't Fix" in July 2012.
Paul Phillips' talk Scala Collections: Why Not? from January 2014 scorns the use cases as "lies" in slide 1, slide 2, slide 3.
In GenTraversableLike.scala you can see an example of a directive which causes use case documentation to be generated:
#usecase def flatMap[B](f: A => TraversableOnce[B]): $Coll[B]
Similar questions
Why does the scaladoc say HashMap.toArray returns Array[A] instead of Array[(A,B)]?
The List :: method and covariance ... why do they hide the real signature?
scaladoc for map on Map ... is the documentation wrong, or am I missing something?
What's going on here with scala.collection.immutable.Stack.+: (prepend)? ...
Why do some method descriptions in Scaladoc start with [use case]?
How to explain Map.map result
For example, Exception.allCatch is defined as
def allCatch[T]: Catch[T]
Why not just
val allCatch: Catch[Nothing]
when Catch is covariant in its argument?
Or, why PartialFunction object defines
def empty[A, B]: PartialFunction[A, B]
instead of just
val empty: PartialFunction[Any,Nothing]
?
Update: So far it seems that the answers miss the point. So please include a specific examples in your answer that really target the question. For example: Show a piece of code that works with def empty[A, B]: PartialFunction[A, B] but doesn't work (or is less convenient) with val empty: PartialFunction[Any,Nothing].
This saves the need for casting later and allows to treat the args type as T instead of Any, which is usually more convenient.
Here is an example:
scala> def func1[T](arg : T) : T = { arg }
func1: [T](arg : T)T
scala> def func2(arg : Any) : Any = { arg }
func2: (arg: Any)Any
scala> func1(4)
res4: Int = 4
scala> func2(4)
res7: Any = 4
Looking at the source of PartialFunction available here we can see that it in fact calls a private method on the PartialFunction object:
private[this] val empty_pf: PartialFunction[Any, Nothing]
So the return type of empty will always be PartialFunction[Any, Nothing]. As for the reasoning behind I have no idea. Maybe someone else have better insight as to why. You could try the language mailing list as well...
If you hard-code the type, like PartialFunction[Any,Nothing], you cannot restrict your function to take a more specific parameter than Any.
By using a generic type parameter, you can end up with a more flexible satisfying all cases and especially making the function safe.
Let's assume you want a function aiming to take an Animal as parameter and returning an Integer.
Let's assume that function is declared as being:
def myFunction: PartialFunction[Any,Nothing]
Firstly, PartialFunction would not be specialized to Animal at parameter side but to Any. What about if I pass a Human as parameter...., it would pass.. What about safety?
Secondly, If this function is declared as returning Nothing, you can't return from it any value but Nothing! Indeed, Nothing subclasses all classes in Scala.
This leads to the known rule that return type parameter must always be covariant in order to make a function interesting, not the case with Nothing.
In fact, Nothing is interesting only when dealing with the empty method of PartialFunction. Logic since an empty PartialFunction by definition involves nothing to return and should be forced to do it :)
You would ask: "So why don't we change the return type to Any?"
Answer: Because you'd lose all the benefit of generic erasure time making compiler to add needed casts automatically => You wouldn't retrieve directly the Integer value, but Any. annoying..
Actually, it seems that Scala standard library has some more places where generic type parameter is redundant (because of type variance). For example, see my question about foreach. My guess, based on #Peter's answer, is that these redundant generics make the interface more clear. Thanks to them, we don't have to remember which types are covariant, contravariant and invariant. Also, this makes things way simpler for people who are not familiar with variance, which is rather an advanced feature of Scala.
I'm kind of new to Scala and I have a question about the type system.
The flatten method works on nested collections, so if I have a List of Lists it will flatten it into a List. But it does not make sense to call flatten on a collection that is already flat. And sure enough the Scala type checker will flag that as an error.
List(List(1,2,3),List(4,5,6)).flatten // produces List(1,2,3,4,5,6)
List(1,2,3,4).flatten // type error
I understand that this somehow relies on an implicit parameter to flatten. But I don't know where the implicit value comes from and how it is used to assert the type of the object flatten is called on. Also, why doesn't the implicit parameter show up in the scaladocs for List.flatten?
To understand how this works, we need to have a look at the type signature of flatten:
def flatten[B](implicit asTraversable: (A) ⇒ GenTraversableOnce[B]): List[B]
A is the element type of the list and B is the type of the elements of each element. In order for flatten to work, there has to be an implicit conversion from the element types to a GenTraversableOnce[B]. That is only the case for collections or if you implement your own implicit conversion. For example, you could define one for pairs:
implicit def pairToList[A](p:(A,A)) = List(p._1, p._2)
List(1->2,2->3).flatten //compiles! List(1,2,2,3)
The trick is an implicit witness that ensures that the elements in the list are traversable. Here is the (slightly simplified) signature of flatten taken from GenericTraversableTemplate:
def flatten[B](implicit asTraversable: A => TraversableOnce[B])
: GenTraversable[B] =
In your case, the witness cannot be found for elements of type Int, and the invocation of flatten is therefore rejected by the compiler.
If you wanted to make your example compile, you could use the following implicit definition:
implicit def singleToList[A](a: A) = List(a)
(As a side-note: I'd consider such an implicit as quite dangerous, since it's applicability is very general, which can result in unpleasant surprises because the compiler might inject invocations at various places without you being aware of it.)