:: |
prepends a single element to a list. E.g.: 1 :: List(2, 3, 4) List(1, 2, 3, 4) |
+: |
generalized :: introduced in Scala 2.10. E.g.: val head +: tail = List(1, 2, 3) head: Int = 1; tail: List[Int] = List(2, 3) |
:+ |
backwards +: . E.g., val tail :+ head = List(1, 2, 3) tail: List[Int] = List(1, 2); head: Int = 3 |
++ |
concatenates two lists. E.g.: List(1, 2) ++ List(3, 4) List(1, 2, 3, 4) |
::: |
concatenates two lists. E.g.: List(1, 2) ::: List(3, 4) (which is interpreted as List(3, 4).:::(List(1, 2)) ) List(1, 2, 3, 4) So, effectively, it’s equivalent to ++ . |
@ |
is used in pattern-matching, where you want to capture the entire match as a variable. For example, if you want the head as well as the whole list, so that you can repeat the head at the beginning: List(List(2, 3, 4), List(4, 9, 16)).map { case (lst @ head :: _) => head :: lst } List(List(2, 2, 3, 4), List(4, 4, 9, 16)) |
^^ |
connects a Parser match to a post-processing step. For example, """\d+(\.\d*)?""".r ^^ { _.toDouble } parses the regex match as a Double . |
<% |
view bound; specifies adherence to a trait (type class). A <% Ordered[A] , for example, says that the type parameter you’re using, A , must implement the Ordered trait, i.e., it must be viewable as an Ordered[A] . |
<: |
upper type bound; T <: A requires that T is a subtype of A . |
>: |
lower type bound; B >: A requires that B is a supertype of A .List[+A]#sum is declared as def sum[B >: A](implicit num: Numeric[B]): B , which says that the returned value B will be a supertype of the list items. The implicit bit is evidence that the returned value will be numeric, which implies that the list’s items of type A must be a subtype of Numeric[B] . This is more complicated than it really ought to be (def sum[A <: Number]: Number ) since Scala’s numeric types (e.g., Int , Double ), don’t actually inherit a common type ancestor like Number . |
=:= |
generalized type constraint; A =:= B (a.k.a., =:=[A, B] ) specifies that the type A must exactly equal the type B . Inside a trait/class/whatever with some parameterized type a: A , we could define a method def squared(implicit evidence: A =:= Int) = a * a , and then call my_a.squared that would only compile (type check) if A is precisely Int . |
<:< |
generalized type constraint; A <:< B (a.k.a., <:<[A, B] ) specifies that A must be a subtype of B , similar to <: . |
<%< |
generalized type constraint; A <%< B (a.k.a., <%<[A, B] ) specifies that A must be viewable as B , similar to <% (via implicit conversion). |
[+A]
and contravariance [-A]
co(ntra)variance is more a property of inheritance than an immediate property of the specific type it is declared on. Suppose we have:
class Animal
class Mammal extends Animal
class Reptile extends Animal
The covariance annotation on collection.immutable.List[+A]
means that we can treat the items of a List[Mammal]
as instances of Animal
. If we add an Animal
to a List[Mammal]
, it would return a new List[Animal]
. We could also add a Reptile
and have the same effect.
On the other hand, mutable collections like collection.mutable.ListBuffer[A]
are not covariant; if they were, we could add an Animal
to an existing ListBuffer[Mammal]
, which is problematic. The collection is mutable, but its type (parameters) are not, so there has to be a stricter restriction on what type of elements the collection can contain.
The contravariance annotation -A
in Function1[-A,+B]
(a function that takes an A
and returns a B
) means that wherever we need a function of this type, we can alternatively supply a function that converts A
or some supertype of A
, to B
or some subtype of B
.
The following example demonstrates contravariance (not covariance, but covariance can also come into play):
val drawAnimal: Animal => Unit = { animal => println("o~") }
val drawMammal: Mammal => Unit = { mammal => println(":°:") }
val initCanvas = { () => println("---") }
def MammalCanvas(drawFn: Mammal => Unit, mammal: Mammal) = { initCanvas(); drawFn(mammal) }
Now we can call the MammalCanvas
function with drawMammal
, which doesn’t use contravariance:
MammalCanvas(drawMammal, new Mammal)
---
:°:
Or, since drawFn
has the type Function1[-Mammal,+Unit]
, not Function1[Mammal,+Unit]
,
we can use contravariance to call it with drawAnimal
:
MammalCanvas(drawAnimal, new Mammal)
---
o~
References:
Function[-A1,…,+B]
not about allowing any supertypes as parameters?The Scaladoc on performance characteristics is nice.
Iterable |
is the most basic trait of an ordered collection. (It inherits Traversable , but Traversable also applies to unordered types, like Set and plain HashMap .) But it doesn’t necessarily tell you the size, let you index, or iterate the collection more than once. |
Seq |
is the basic trait for indexable ordered collections. Instantiating a Seq creates a LinearSeq , i.e., a List . |
IndexedSeq |
is the first of the two principle subtraits of Seq , best suited for random access to elements and determining the size of the sequence.Vector is the primary implementation. Range and WrappedString are special cases of IndexedSeq , and thus presumably backed by Vector instances. |
LinearSeq |
is the second of the two principle subtraits of Seq , better suited for head and tail access.List is the primary implementation. Stream , Queue , and Stack are other collections based on LinearSeq (Stack has been deprecated). |
List |
is the most basic actual implementation of LinearSeq , and it’s the default implementation of Traversable , Iterable , Seq , LinearSeq , and of course List , meaning you can call any of those as a function, and they’ll all give you back a List .(Unless you’re in mutable-land, in which case Traversable , Iterable , and Seq will all return an ArrayBuffer , while LinearSeq will return a MutableList . There is no mutable.List .)Apparently List is most similar to Java’s LinkedList . |
Vector |
is the most basic actual implementation of IndexedSeq , and it’s the default implementation of IndexedSeq and Vector , meaning you can call either of those as a function, and they’ll all give you back a Vector .(In mutable-land, IndexedSeq returns an ArrayBuffer instead.)Vector is preferable to List if you’re going to be parallelizing over the collection. |
Stream |
derives from LinearSeq , but it’s not really a good name, since it memoizes everything that gets evaluated, instead of discarding it. What I generally think of when I hear Stream is closer to the Iterable level — I think LazyList would be a better name. |
mutable.ArrayBuffer |
is the Scala equivalent of Java’s ArrayList . It sort of derives from IndexedSeq , and it’s the mutable version of Vector . It’s best for random access and random writes, less good at prepending and appending. |
mutable.Queue |
is backed by mutable.MutableList . |
mutable.ListBuffer |
seems to be the mutable version of List . It’s best for prepend and append operations, less suited for random access or random writes. I’m not sure how it differs from mutable.Queue . |
SBT fetches dependencies via resolvers.
Handy SBT Plugins:
The sbt-updates
plugin compares the dependencies listed in build.sbt
to the current version available on Maven Central (or other configured repositories).
To install the plugin for all sbt
projects, create a file at ~/.sbt/0.13/plugins/sbt-updates.sbt
(the filename can be whatever, I think) with the following line:
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.3.3")
Then at the sbt
REPL for your specific project, call:
dependencyUpdates
Show Scala compiler version, e.g., in a REPL:
scala.util.Properties.versionString