scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Sample code from "Scala by example" book is slightly misleading #9259

Closed scabug closed 4 years ago

scabug commented 9 years ago

I'm going through the book "Scala by example" downloaded from : http://www.scala-lang.org/docu/files/ScalaByExample.pdf

and discovered on the page 45 a small inconsistency. Since the method print is declared in the Expr abstract class, it could be made use of it in the Sum#print method.

abstract class Expr {
  def eval: Int
  def print
}

class Number(n: Int) extends Expr {
  def eval: Int = n
  def print { Console.print(n) }
  }

class Sum(e1: Expr, e2: Expr) extends Expr {
  def eval: Int = e1.eval + e2.eval
  def print {
    Console.print("(")
    print(e1)
    Console.print("+")
    print(e2)
    Console.print(")")
  }
}

should be changed to this form :

abstract class Expr {
  def eval: Int
  def print
}

class Number(n: Int) extends Expr {
  def eval: Int = n
  def print { Console.print(n) }
  }

class Sum(e1: Expr, e2: Expr) extends Expr {
  def eval: Int = e1.eval + e2.eval
  override def print: Unit = {
    Console.print("(")
    e1.print
    Console.print("+")
    e2.print
    Console.print(")")
  }
}
scabug commented 9 years ago

Imported From: https://issues.scala-lang.org/browse/SI-9259?orig=1 Reporter: Marius Grama (mariusneo)

scabug commented 9 years ago

Marius Grama (mariusneo) said: Additional issue found in the book, at page 67, for the Zipping lists example :

def zip[B](that: List[B]): List[(a,b)] =
  if (this.isEmpty || that.isEmpty) Nil
  else (this.head, that.head) :: (this.tail zip that.tail)
```scala

should be probably changed to :
{code: language=scala}

def zip[B](that: List[B]): List[(A,B)] =
  if (this.isEmpty || that.isEmpty) Nil
  else (this.head, that.head) :: (this.tail zip that.tail)
scabug commented 9 years ago

Marius Grama (mariusneo) said: At page 70 in the book, there is presented an example on how to produce a mapping operation on the elements of a list :

abstract class List[A] { ...
  def map[B](f: A => B): List[B] = this match {
     case Nil => this
     case x :: xs => f(x) :: xs.map(f)
  }
}

In the case that the current instance(this) is empty it can't be returned because it has the type List[A] , but the method is expected to return List[B]

I made a function on my own to implement the example and did it in the following manner :

  def mapList[A,B](f: A => B)(xs:List[A]):List[B] = xs match {
    case Nil => Nil
    case x :: xs1 => f(x) :: mapList(f)(xs1)
  }
scabug commented 9 years ago

Marius Grama (mariusneo) said: At page 106 (in the Iterators chapter), I found another possible issue

    fromArray(xs)
      .zip(from(0))
      .filter ( case (x, i) => x > limit )
      .map ( case (x, i) => i )

which fails to compile in Scala 2.11

I found the solution on how to change the code on the following web resource : http://java.dzone.com/articles/scala-pattern-matching-pair

??dwins: scala requires that “case” statements be inside curly braces. The code should look like this :

    fromArray(xs)
      .zip(from(0))
      .filter { case (x, i) => x > limit }
      .map { case (x, i) => i }
scabug commented 9 years ago

Marius Grama (mariusneo) said: At page 100, chapter 12 Computing with streams there is presented the following code block :

{code:language=scala} range(1000, 10000) filter isPrime at 1


I didn't find the operation _at_ between the operations of _List_ type and I am wondering if the code block shouldn't actually look like :

{code:language=scala}
range(1000, 10000) filter isPrime apply 1
scabug commented 9 years ago

Marius Grama (mariusneo) said: I've found another small issue on the page 114, on the chapter Implicit parameters and conversions :

The code sample which in its actual form doesn't successfully compile :

{code:language=scala} def sum[A](xs: List[A])(m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(m)(xs.tail)


should actually be 

{code:language=scala}
  def sum[A](xs:List[A])(m:Monoid[A]):A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail)(m))
scabug commented 9 years ago

Marius Grama (mariusneo) said (edited on Apr 7, 2015 7:20:00 PM UTC): Page 116, chapter Implicit Parameters and Conversions , View Bounds subchapter

{code:language=scala} def sort[A <% Ordered[A]](xs: List[A]): List[A] = if (xs.isEmpty || xs.tail.isEmpty) xs else { val {ys, zs} = xs.splitAt(xs.length / 2) merge(ys, zs) }


The construct didn't compile with Scala 2.11 and I've replaced it with :
{code:language=scala}
def sort[A <% Ordered[A]](xs: List[A]): List[A] =
    if (xs.isEmpty || xs.tail.isEmpty) xs
    else {
      val (ys, zs) = xs.splitAt(xs.length / 2)
      merge(ys, zs)
    }

Moreover, it seems that the view bounds are deprecated as of Scala 2.11

7629

The sort sample out of which this example makes part of doesn't compile when using implicit keyword. This is due to the fact that the implicit int2ordered function is causing ambiguity for the compiler because it provides the same functionality as the LowPriorityImplicits#intWrapper function.

I've slightly modified the sample code like this :

{code:language=scala} type OrderedView[A] = A => Ordered[A]

def sort[A: OrderedView](xs: List[A]): List[A] = if (xs.isEmpty || xs.tail.isEmpty) xs else { val (ys, zs) = xs.splitAt(xs.length / 2) merge(ys, zs) }

def merge[A: OrderedView](xs: List[A], ys: List[A]): List[A] = if (xs.isEmpty) ys else if (ys.isEmpty) xs else if (xs.head < ys.head) xs.head :: merge(xs.tail, ys) else ys.head :: merge(xs, ys.tail)

implicit def num2ordered(x: Num): Ordered[Num] = new Ordered[Num] { override def compare(y: Num): Int = if (x.value < y.value) -1 else if (x.value > y.value) 1 else 0 } }

case class Num(value: Int) { override def toString: String = value.toString }


Sample code that uses the code above :

{code:language=scala}
def main(args: Array[String]) {
    val xs = List(new Num(1), new Num(4), new Num(2), new Num(6),new Num(3))
    val sortedXs = sort(xs)(num2ordered)
    print(sortedXs.mkString(","))
  }
scabug commented 9 years ago

Marius Grama (mariusneo) said: On page 127, Chapter 17 Abstractions for concurrency in order to be able to run the code with Scala 2.8+, there should be added a small change The generic type BoundedBuffer[A] should be BoundedBuffer[A:ClassTag]

{code:language=scala} class BoundedBuffer[A:ClassTag](N: Int) { var in = 0; var out = 0; var n = 0 val elems: Array[A] = new ArrayA

def put(x: A) = synchronized { while (n >= N) wait() elems(in) = x; in = (in + 1) % N; n += 1 if (n == 1) notifyAll() }

def get: A = synchronized { while (n == 0) wait() val x = elems(out); out = (out + 1) % N; n -= 1 if (n == N - 1) notifyAll() x } } {code}

SethTisue commented 4 years ago

Scala by Example has been superseded by https://docs.scala-lang.org/tour/tour-of-scala.html