Page 184 (PDF page 225):
The book states that “The two pairs of definitions [defining `height` and
`width` as `def`s vs. `val`s] are completely equivalent from a client’s
point of view.” This is not completely accurate, since defining them as
`val`s will result in a null pointer exception later on when
instantiating an instance of the `UniformElement` class as given on p.
235.
`height` and `width` must be defined as `def`s to avoid the exception.
|
Page 188 (PDF page 229):
Section 10.4, last paragraph.
Class ArrayElement is “composed” out of class Array[String]
should be
Class ArrayElement is “composed” out of Array[String]
|
Page 190 (PDF page 231):
Sorry, this is nitpicking, but the claim "It's as if the class had been
written as follows, where x123 ..." is not quite true. (Maybe change to
"almost as if".)
It makes a difference when using named arguments. With the definition
class ArrayElement(val contents : Array[String]) ...
I can use 'new ArrayElement(contents = something)'. But with
class ArrayElement(x123 : Array[String]) ...
I can't.
Btw: great book!
|
Page 192 (PDF page 233):
In Section 10.8 it is stated that "Scala requires such a modifier for all
members that override a concrete member in a parent class.". However,
playing with factory objects using private subclasses, I found that the
compiler does not require the override modifier in a parametric field
definition in a private inner subclass and that the expected override
does not occur:
Contents of ObjWithPrivSubClass.scala:
package scalafeaturestest
class ConcretePubSuperClass {
val a: Int = 1
}
/**
* Using the override modifier in the parametric field definition
* of a public subclass is required by the compiler.
* But the compiler does not require the override modifier
* if the subclass is a private inner class (see below).
*
*/
class PubSubClass( override val a: Int ) extends ConcretePubSuperClass {
}
abstract class AbstractPubSuperClass {
val a: Int
}
/**
* Object containing inner private sub classes that attempt to
* override 'a' with the value 2 in the public superclasses above.
*
*/
object ObjWithPrivSubClass {
// For a concrete superclass, not using the override modifier
// in the private subclass parametric field definition compiles.
private class PrivSubClass1( a: Int ) extends ConcretePubSuperClass {
}
// But a factory method using this subclass definition
// does not override 'a'; it retains the superclass value.
// Note, the factory method must return the public super class type
// because the subclass is private.
val
instancePrivSubClassExtendsConcretePubSuperClassNoParameterOverrideModifie
r: ConcretePubSuperClass = new PrivSubClass1( 2 )
// For a concrete superclass, using the override modifier
// in the subclass parametric field definition compiles.
private class PrivSubClass2( override val a: Int ) extends
ConcretePubSuperClass {
}
// In this case, a factory method using this subclass definition
// does override 'a'; it uses the new value.
val instancePrivSubClassExtendsConcretePubSuperClassHasParamet
|
Page 192 (PDF page 233):
Oops, regarding my previous submission, I found a coding error which
explains the issue. I forgot to include the "val " in my subclass
definition: "private class PrivSubClass1(a: Int) extends
ConcretePubSuperClass { }". So the class just takes a parameter that it
never uses. Adding "val " to correctly define the parametric field
causes the compiler to require the override modifier so that the correct
definition is "private class PrivSubClass1(override val a: Int) extends
ConcretePubSuperClass { }". As an aside, I note that it would be nice if
the compiler would warn when a parameter is defined that is never used
and suggest that the "val " might have been left off. Thanks.
|
Page 200 (PDF page 241):
Readability glitch. The following two sentences seem to be saying the
same thing to me, and break the otherwise perfect flow in the text.
"Here, the two arrays this.contents and that.contents are transformed
into an array of pairs (as Tuple2s are called) using the zip operator.
The zip method picks corresponding elements in its two arguments and
forms an array of pairs."
I'd remove the later sentence.
[I improved it by saying operator and operands instead of method and
arguments. Method and arguments was wrong.]
|
Page 203 (PDF page 244):
On the bottom of the pages 244 (and also on the page 245) the book uses:
new ArrayElement
although we already refactored the code to use only factory methods for
Element creation, thus ArrayElement is private class of the Element
singleton.
The code should say:
'Element.elem' instead of 'new ArrayElement'
|
Page 206 (PDF page 247):
var right = elem(' ', w - width - left.width, height)
should be
val right
and also
var bot = elem(' ', width, h - height - top.height)
on same page
|
Page 206 (PDF page 247):
Not quite an errata, but perhaps it would be worth calling this out.
Back on page 183, there is a discussion which ends with the comment "This
means you cannot define an element with a height of zero and a non-zero
width". By the time we get to page 206, this is true for ArrayElement's,
but not for UniformElement's. Indeed, the correctness of the code
depends upon the ability of UniformElement to have a non-zero width but a
zero height, because in heighten(), it is possible for "top" to be of
zero height, but the subsequent use of the "above()" operator will only
work if "top" can return an appropriate width (without an
index-out-of-bounds exception).
Of course, this works because the parameters in UniformElement's
constructor override the width() and height() function in the base class,
which is easy to overlook.
Thanks! Great book!
|
Page 207 (PDF page 248):
The book's version of Spiral outputs this for 14 edges:
+-------------
|
| +---------+
| | |
| | +-----+ |
| | | | |
| | | +-+ | |
| | | + | | |
| | | | | |
| | +---+ | |
| | | |
| +-------+ |
| |
+-----------+
I would suggest this version of `spiral`, as the shapelier solution,
that, IMHO, better fits the book's philosophy (simple over easy):
+-----------
| +-------+
| | +---+ |
| | | + | |
| | +-+ | |
| +-----+ |
+---------+
It's "more square", if nothing :)
def spiral(nEdges: Int, direction: Int): Element = {
if(nEdges == 1)
corner // we already have `corner`, so why not use it
else {
val sp = spiral(nEdges - 1, (direction + 3) % 4)
def verticalBar = elem('|', 1, sp.height - 1)
def horizontalBar = elem('-', sp.width, 1)
if(direction == 0)
(corner beside horizontalBar) above (sp beside space)
else if(direction == 1)
(sp) beside (corner above verticalBar)
else if(direction == 2)
(space beside sp) above (horizontalBar beside corner)
else
(verticalBar above corner) beside (sp)
}
}
|
|
|
|