diff --git a/tutorials/FAQ/breakout.md b/tutorials/FAQ/breakout.md new file mode 100644 index 0000000000..6eb626214f --- /dev/null +++ b/tutorials/FAQ/breakout.md @@ -0,0 +1,230 @@ +--- +layout: tutorial +title: What is breakOut, and how does it work? + +disqus: true + +tutorial: FAQ +num: 5 +--- +You might have encountered some code like the one below, and wonder what is +`breakOut`, and why is it being passed as parameter? + + import scala.collection.breakOut + val map : Map[Int,String] = List("London", "Paris").map(x => (x.length, x))(breakOut) + + +The answer is found on the definition of `map`: + + def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That + +Note that it has two parameters. The first is your function and the second is +an implicit. If you do not provide that implicit, Scala will choose the most +_specific_ one available. + +**About `breakOut`** + +So, what's the purpose of `breakOut`? Consider the example given at the +beginning , You take a list of strings, transform each string into a tuple +`(Int, String)`, and then produce a `Map` out of it. The most obvious way to do +that would produce an intermediary `List[(Int, String)]` collection, and then +convert it. + +Given that `map` uses a `Builder` to produce the resulting collection, wouldn't +it be possible to skip the intermediary `List` and collect the results directly +into a `Map`? Evidently, yes, it is. To do so, however, we need to pass a +proper `CanBuildFrom` to `map`, and that is exactly what `breakOut` does. + +Let's look, then, at the definition of `breakOut`: + + def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) = + new CanBuildFrom[From, T, To] { + def apply(from: From) = b.apply() ; def apply() = b.apply() + } + +Note that `breakOut` is parameterized, and that it returns an instance of +`CanBuildFrom`. As it happens, the types `From`, `T` and `To` have already been +inferred, because we know that `map` is expecting `CanBuildFrom[List[String], +(Int, String), Map[Int, String]]`. Therefore: + + From = List[String] + T = (Int, String) + To = Map[Int, String] + +To conclude let's examine the implicit received by `breakOut` itself. It is of +type `CanBuildFrom[Nothing,T,To]`. We already know all these types, so we can +determine that we need an implicit of type +`CanBuildFrom[Nothing,(Int,String),Map[Int,String]]`. But is there such a +definition? + +Let's look at `CanBuildFrom`'s definition: + + trait CanBuildFrom[-From, -Elem, +To] + extends AnyRef + +So `CanBuildFrom` is contra-variant on its first type parameter. Because +`Nothing` is a bottom class (ie, it is a subclass of everything), that means +*any* class can be used in place of `Nothing`. + +Since such a builder exists, Scala can use it to produce the desired output. + +**About Builders** + +A lot of methods from Scala's collections library consists of taking the +original collection, processing it somehow (in the case of `map`, transforming +each element), and storing the results in a new collection. + +To maximize code reuse, this storing of results is done through a _builder_ +(`scala.collection.mutable.Builder`), which basically supports two operations: +appending elements, and returning the resulting collection. The type of this +resulting collection will depend on the type of the builder. Thus, a `List` +builder will return a `List`, a `Map` builder will return a `Map`, and so on. +The implementation of the `map` method need not concern itself with the type of +the result: the builder takes care of it. + +On the other hand, that means that `map` needs to receive this builder somehow. +The problem faced when designing Scala 2.8 Collections was how to choose the +best builder possible. For example, if I were to write `Map('a' -> +1).map(_.swap)`, I'd like to get a `Map(1 -> 'a')` back. On the other hand, a +`Map('a' -> 1).map(_._1)` can't return a `Map` (it returns an `Iterable`). + +The magic of producing the best possible `Builder` from the known types of the +expression is performed through this `CanBuildFrom` implicit. + +**About `CanBuildFrom`** + +To better explain what's going on, I'll give an example where the collection +being mapped is a `Map` instead of a `List`. I'll go back to `List` later. For +now, consider these two expressions: + + Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length) + Map(1 -> "one", 2 -> "two") map (_._2) + +The first returns a `Map` and the second returns an `Iterable`. The magic of +returning a fitting collection is the work of `CanBuildFrom`. Let's consider +the definition of `map` again to understand it. + +The method `map` is inherited from `TraversableLike`. It is parameterized on +`B` and `That`, and makes use of the type parameters `A` and `Repr`, which +parameterize the class. Let's see both definitions together: + +The class `TraversableLike` is defined as: + + trait TraversableLike[+A, +Repr] + extends HasNewBuilder[A, Repr] with AnyRef + + def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That + + +To understand where `A` and `Repr` come from, let's consider the definition of +`Map` itself: + + trait Map[A, +B] + extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]] + +Because `TraversableLike` is inherited by all traits which extend `Map`, `A` +and `Repr` could be inherited from any of them. The last one gets the +preference, though. So, following the definition of the immutable `Map` and all +the traits that connect it to `TraversableLike`, we have: + + trait Map[A, +B] + extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]] + + trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] + extends MapLike[A, B, This] + + trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] + extends PartialFunction[A, B] with IterableLike[(A, B), This] with Subtractable[A, This] + + trait IterableLike[+A, +Repr] + extends Equals with TraversableLike[A, Repr] + + trait TraversableLike[+A, +Repr] + extends HasNewBuilder[A, Repr] with AnyRef + +If you pass the type parameters of `Map[Int, String]` all the way down the +chain, we find that the types passed to `TraversableLike`, and, thus, used by +`map`, are: + + A = (Int,String) + Repr = Map[Int, String] + +Going back to the example, the first map is receiving a function of type +`((Int, String)) => (Int, Int)` and the second map is receiving a function of +type `((Int, String)) => Int`. I use the double parenthesis to emphasize it is +a tuple being received, as that's the type of `A` as we saw. + +With that information, let's consider the other types. + + map Function.tupled(_ -> _.length): + B = (Int, Int) + + map (_._2): + B = Int + +We can see that the type returned by the first `map` is `Map[Int,Int]`, and the +second is `Iterable[String]`. Looking at `map`'s definition, it is easy to see +that these are the values of `That`. But where do they come from? + +If we look inside the companion objects of the classes involved, we see some +implicit declarations providing them. On object `Map`: + + implicit def canBuildFrom [A, B] : CanBuildFrom[Map, (A, B), Map[A, B]] + +And on object `Iterable`, whose class is extended by `Map`: + + implicit def canBuildFrom [A] : CanBuildFrom[Iterable, A, Iterable[A]] + +These definitions provide factories for parameterized `CanBuildFrom`. + +Scala will choose the most specific implicit available. In the first case, it +was the first `CanBuildFrom`. In the second case, as the first did not match, +it chose the second `CanBuildFrom`. + +**Back to the first example** + +Let's see the first example, `List`'s and `map`'s definition (again) to +see how the types are inferred: + + val map : Map[Int,String] = List("London", "Paris").map(x => (x.length, x))(breakOut) + + sealed abstract class List[+A] + extends LinearSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqLike[A, List[A]] + + trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]] + extends SeqLike[A, Repr] + + trait SeqLike[+A, +Repr] + extends IterableLike[A, Repr] + + trait IterableLike[+A, +Repr] + extends Equals with TraversableLike[A, Repr] + + trait TraversableLike[+A, +Repr] + extends HasNewBuilder[A, Repr] with AnyRef + + def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That + +The type of `List("London", "Paris")` is `List[String]`, so the types `A` and +`Repr` defined on `TraversableLike` are: + + A = String + Repr = List[String] + +The type for `(x => (x.length, x))` is `(String) => (Int, String)`, so the type +of `B` is: + + B = (Int, String) + +The last unknown type, `That` is the type of the result of `map`, and we +already have that as well: + + val map : Map[Int,String] = + +So, + + That = Map[Int, String] + +That means `breakOut` must, necessarily, return a type or subtype of +`CanBuildFrom[List[String], (Int, String), Map[Int, String]]`. + diff --git a/tutorials/FAQ/finding-symbols.md b/tutorials/FAQ/finding-symbols.md new file mode 100644 index 0000000000..1876e72da9 --- /dev/null +++ b/tutorials/FAQ/finding-symbols.md @@ -0,0 +1,195 @@ +--- +layout: tutorial +title: Finding Symbols + +disqus: true + +tutorial: FAQ +num: 1 +outof: 5 +--- +Let's divide the operators, for the purpose of teaching, into **four categories**: + +* Keywords/reserved symbols +* Automatically imported methods +* Common methods +* Syntactic sugars/composition + +And let's see some arbitrary examples: + + -> // Automatically imported method + <- // Keyword + ||= // Syntactic sugar + ++= // Syntactic sugar/composition or common method + <= // Common method + _+_ // Keyword/composition + :: // Common method or object + :+= // Common method + +The exact meaning of most of these methods depend on the class that is defining +them. For example, `<=` on `Int` means _"less than or equal to"_, but it might +mean something else in another class. `::` is probably the method defined on +`List` but it _could_ also be the object of the same name. + +So, let's see them. + +Keywords/reserved symbols +------------------------- + +There are some symbols in Scala that are special. Two of them are considered +proper keywords, while others are just "reserved". They are: + + // Keywords + <- // Used on for-comprehensions, to separate pattern from generator + => // Used for function types, function literals and import renaming + + // Reserved + ( ) // Delimit expressions and parameters + [ ] // Delimit type parameters + { } // Delimit blocks + . // Method call and path separator + // /* */ // Comments + # // Used in type notations + : // Type ascription or context bounds + <: >: <% // Upper, lower and view bounds + " """ // Strings + ' // Indicate symbols and characters + @ // Annotations and variable binding on pattern matching + ` // Denote constant or enable arbitrary identifiers + , // Parameter separator + ; // Statement separator + _* // vararg expansion + _ // Many different meanings + +These are all _part of the language_, and, as such, can be found in any text +that properly describe the language, such as [Scala Specification][1](PDF) +itself. + +The last one, the underscore, deserve a special description, because it is so +widely used, and has so many different meanings. Here's a sample: + + import scala._ // Wild card -- all of Scala is imported + import scala.{ Predef => _, _ } // Exception, everything except Predef + def f[M[_]] // Higher kinded type parameter + def f(m: M[_]) // Existential type + _ + _ // Anonymous function placeholder parameter + m _ // Eta expansion of method into method value + m(_) // Partial function application + _ => 5 // Discarded parameter + case _ => // Wild card pattern -- matches anything + f(xs: _*) // Sequence xs is passed as multiple parameters to f(ys: T*) + case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequence + +I probably forgot some other meaning, though. + +Automatically imported methods +------------------------------ + +So, if you did not find the symbol you are looking for in the list above, then +it must be a method, or part of one. But, often, you'll see some symbol and the +documentation for the class will not have that method. When this happens, +either you are looking at a composition of one or more methods with something +else, or the method has been imported into scope, or is available through an +imported implicit conversion. + +These _can still be found_ on [ScalaDoc][2]: you just have to know where to +look for them. Or, failing that, look at the [index][3] (presently broken on +2.9.1, but available on nightly). + +Every Scala code has three automatic imports: + + // Not necessarily in this order + import _root_.java.lang._ // _root_ denotes an absolute path + import _root_.scala._ + import _root_.scala.Predef._ + +The first two only make classes and singleton objects available. The third one +contains all implicit conversions and imported methods, since [`Predef`][4] is +an object itself. + +Looking inside `Predef` quickly show some symbols: + + class <:< + class =:= + object <%< + object =:= + +Any other symbol will be made available through an _implicit conversion_. Just +look at the methods tagged with `implicit` that receive, as parameter, an +object of type that is receiving the method. For example: + + "a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter + +In the above case, `->` is defined in the class [`ArrowAssoc`][5] through the +method `any2ArrowAssoc` that takes an object of type `A`, where `A` is an +unbounded type parameter to the same method. + +Common methods +-------------- + +So, many symbols are simply methods on a class. For instance, if you do + + List(1, 2) ++ List(3, 4) + +You'll find the method `++` right on the ScalaDoc for [List][6]. However, +there's one convention that you must be aware when searching for methods. +Methods ending in colon (`:`) bind _to the right_ instead of the left. In other +words, while the above method call is equivalent to: + + List(1, 2).++(List(3, 4)) + +If I had, instead `1 :: List(2, 3)`, that would be equivalent to: + + List(2, 3).::(1) + +So you need to look at the type found _on the right_ when looking for methods +ending in colon. Consider, for instance: + + 1 +: List(2, 3) :+ 4 + +The first method (`+:`) binds to the right, and is found on `List`. The second +method (`:+`) is just a normal method, and binds to the left -- again, on +`List`. + +Syntactic sugars/composition +----------------------------- + +So, here's a few syntactic sugars that may hide a method: + + class Example(arr: Array[Int] = Array.fill(5)(0)) { + def apply(n: Int) = arr(n) + def update(n: Int, v: Int) = arr(n) = v + def a = arr(0); def a_=(v: Int) = arr(0) = v + def b = arr(1); def b_=(v: Int) = arr(1) = v + def c = arr(2); def c_=(v: Int) = arr(2) = v + def d = arr(3); def d_=(v: Int) = arr(3) = v + def e = arr(4); def e_=(v: Int) = arr(4) = v + def +(v: Int) = new Example(arr map (_ + v)) + def unapply(n: Int) = if (arr.indices contains n) Some(arr(n)) else None + } + + var ex = new Example + println(ex(0)) // calls apply(0) + ex(0) = 2 // calls update(0, 2) + ex.b = 3 // calls b_=(3) + val ex(c) = 2 // calls unapply(2) and assigns result to c + ex += 1 // substituted for ex = ex + 1 + +The last one is interesting, because *any* symbolic method can be combined to +form an assignment-like method that way. + +And, of course, there's various combinations that can appear in code: + + (_+_) // An expression, or parameter, that is an anonymous function with + // two parameters, used exactly where the underscores appear, and + // which calls the "+" method on the first parameter passing the + // second parameter as argument. + + + [1]: http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf + [2]: http://www.scala-lang.org/api/current/index.html + [3]: http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/index.html#index.index-_ + [4]: http://www.scala-lang.org/api/current/index.html#scala.Predef$ + [5]: http://www.scala-lang.org/api/current/scala/Predef$$ArrowAssoc.html + [6]: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List + diff --git a/tutorials/FAQ/stream-view-iterator.md b/tutorials/FAQ/stream-view-iterator.md new file mode 100644 index 0000000000..c707676396 --- /dev/null +++ b/tutorials/FAQ/stream-view-iterator.md @@ -0,0 +1,42 @@ +--- +layout: tutorial +title: What is the difference between view, stream and iterator? + +disqus: true + +tutorial: FAQ +num: 4 +--- +First, they are all _non-strict_. That has a particular mathematical meaning +related to functions, but, basically, means they are computed on-demand instead +of in advance. + +`Stream` is a lazy list indeed. In fact, in Scala, a `Stream` is a `List` whose +`tail` is a `lazy val`. Once computed, a value stays computed and is reused. +Or, as you say, the values are cached. + +An `Iterator` can only be used once because it is a _traversal pointer_ into a +collection, and not a collection in itself. What makes it special in Scala is +the fact that you can apply transformation such as `map` and `filter` and +simply get a new `Iterator` which will only apply these transformations when +you ask for the next element. + +Scala used to provide iterators which could be reset, but that is very hard to +support in a general manner, and they didn't make version 2.8.0. + +Views are meant to be viewed much like a database view. It is a series of +transformation which one applies to a collection to produce a "virtual" +collection. As you said, all transformations are re-applied each time you need +to fetch elements from it. + +Both `Iterator` and views have excellent memory characteristics. `Stream` is +nice, but, in Scala, its main benefit is writing infinite sequences +(particularly sequences recursively defined). One _can_ avoid keeping all of +the `Stream` in memory, though, by making sure you don't keep a reference to +its `head` (for example, by using `def` instead of `val` to define the +`Stream`). + +Because of the penalties incurred by views, one should usually `force` it after +applying the transformations, or keep it as a view if only few elements are +expected to ever be fetched, compared to the total size of the view. + diff --git a/tutorials/FAQ/strictness.md b/tutorials/FAQ/strictness.md new file mode 100644 index 0000000000..a70c06257c --- /dev/null +++ b/tutorials/FAQ/strictness.md @@ -0,0 +1,10 @@ +--- +layout: tutorial +title: What does "strict", "non-strict" and "lazy" mean? + +disqus: true + +tutorial: FAQ +num: 3 +--- + diff --git a/tutorials/FAQ/yield.md b/tutorials/FAQ/yield.md new file mode 100644 index 0000000000..449a6858b0 --- /dev/null +++ b/tutorials/FAQ/yield.md @@ -0,0 +1,156 @@ +--- +layout: tutorial +title: How does yield work? + +disqus: true + +tutorial: FAQ +num: 2 +--- +Though there's a `yield` in other languages such as Python and Ruby, Scala's +`yield` does something very different from them. In Scala, `yield` is part +of for comprehensions -- a generalization of Ruby and Python's list-comprehensions. + +Scala's "for comprehensions" are equivalent to Haskell's "do" notation, and it +is nothing more than a syntactic sugar for composition of multiple monadic +operations. As this statement will most likely not help anyone who needs help, +let's try again... :-) + +Translating for-comprehensions +------------------------------ + +Scala's "for comprehensions" is syntactic sugar for composition of multiple +operations with map, flatMap and filter. Or foreach. Scala actually translates +a for-expression into calls to those methods, so any class providing them, or a +subset of them, can be used with for comprehensions. + +First, let's talk about the translations. There are very simple rules: + +1) This + + for(x <- c1; y <- c2; z <-c3) {...} + +is translated into + + c1.foreach(x => c2.foreach(y => c3.foreach(z => {...}))) + +2) This + + for(x <- c1; y <- c2; z <- c3) yield {...} + +is translated into + + c1.flatMap(x => c2.flatMap(y => c3.map(z => {...}))) + +3) This + + for(x <- c; if cond) yield {...} + +is translated on Scala 2.7 into + + c.filter(x => cond).map(x => {...}) + +or, on Scala 2.8, into + + c.withFilter(x => cond).map(x => {...}) + +with a fallback into the former if method `withFilter` is not available but +`filter` is. Please see the edit below for more information on this. + +4) This + + for(x <- c; y = ...) yield {...} + +is translated into + + c.map(x => (x, ...)).map((x,y) => {...}) + + +When you look at very simple for comprehensions, the map/foreach alternatives +look, indeed, better. Once you start composing them, though, you can easily get +lost in parenthesis and nesting levels. When that happens, for comprehensions +are usually much clearer. + +I'll show one simple example, and intentionally ommit any explanation. You can +decide which syntax was easier to understand. + + l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length)) + +or + + for{ + sl <- l + el <- sl + if el > 0 + } yield el.toString.length + + +About `withFilter`, and strictness +---------------------------------- + + +Scala 2.8 introduced a method called `withFilter`, whose main difference is +that, instead of returning a new, filtered, collection, it filters on-demand. +The `filter` method has its behavior defined based on the strictness of the +collection. To understand this better, let's take a look at some Scala 2.7 with +`List` (strict) and `Stream` (non-strict): + + scala> var found = false + found: Boolean = false + + scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x)) + 1 + 3 + 7 + 9 + + scala> found = false + found: Boolean = false + + scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x)) + 1 + 3 + +The difference happens because filter is immediately applied with `List`, +returning a list of odds -- since `found` is `false`. Only then `foreach` is +executed, but, by this time, changing `found` is meaningless, as `filter` has +already executed. + +In the case of `Stream`, the condition is not immediatelly applied. Instead, as +each element is requested by `foreach`, `filter` tests the condition, which +enables `foreach` to influence it through `found`. Just to make it clear, here +is the equivalent for-comprehension code: + + for (x <- List.range(1, 10); if x % 2 == 1 && !found) + if (x == 5) found = true else println(x) + + for (x <- Stream.range(1, 10); if x % 2 == 1 && !found) + if (x == 5) found = true else println(x) + +This caused many problems, because people expected the `if` to be considered +on-demand, instead of being applied to the whole collection beforehand. + +Scala 2.8 introduced `withFilter`, which is _always_ non-strict, no matter the +strictness of the collection. The following example shows `List` with both +methods on Scala 2.8: + + scala> var found = false + found: Boolean = false + + scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x)) + 1 + 3 + 7 + 9 + + scala> found = false + found: Boolean = false + + scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x)) + 1 + 3 + +This produces the result most people expect, without changing how `filter` +behaves. As a side note, `Range` was changed from non-strict to strict between +Scala 2.7 and Scala 2.8. + diff --git a/tutorials/index.md b/tutorials/index.md index 00ab5712bd..014d39060c 100644 --- a/tutorials/index.md +++ b/tutorials/index.md @@ -41,3 +41,27 @@ title: Tutorials {% endif %} +
+
+

FAQ

Frequently Asked Questions (and their answers!)

+
+ {% for pg in site.pages %} + {% if pg.tutorial == "FAQ" and pg.outof %} + {% assign totalPages = pg.outof %} + {% endif %} + {% endfor %} + + {% if totalPages %} + + {% else %} **ERROR**. Couldn't find the total number of pages in this set of tutorial articles. Have you declared the `outof` tag in your YAML front matter? + {% endif %} +
+