- •Contents
- •List of Figures
- •List of Tables
- •List of Listings
- •Foreword
- •Foreword to the First Edition
- •Acknowledgments
- •Introduction
- •A Scalable Language
- •A language that grows on you
- •What makes Scala scalable?
- •Why Scala?
- •Conclusion
- •First Steps in Scala
- •Conclusion
- •Next Steps in Scala
- •Conclusion
- •Classes and Objects
- •Semicolon inference
- •Singleton objects
- •A Scala application
- •Conclusion
- •Basic Types and Operations
- •Some basic types
- •Literals
- •Operators are methods
- •Arithmetic operations
- •Relational and logical operations
- •Bitwise operations
- •Object equality
- •Operator precedence and associativity
- •Rich wrappers
- •Conclusion
- •Functional Objects
- •Checking preconditions
- •Self references
- •Auxiliary constructors
- •Method overloading
- •Implicit conversions
- •A word of caution
- •Conclusion
- •Built-in Control Structures
- •If expressions
- •While loops
- •For expressions
- •Match expressions
- •Variable scope
- •Conclusion
- •Functions and Closures
- •Methods
- •Local functions
- •Short forms of function literals
- •Placeholder syntax
- •Partially applied functions
- •Closures
- •Special function call forms
- •Tail recursion
- •Conclusion
- •Control Abstraction
- •Reducing code duplication
- •Simplifying client code
- •Currying
- •Writing new control structures
- •Conclusion
- •Composition and Inheritance
- •A two-dimensional layout library
- •Abstract classes
- •Extending classes
- •Invoking superclass constructors
- •Polymorphism and dynamic binding
- •Using composition and inheritance
- •Heighten and widen
- •Putting it all together
- •Conclusion
- •How primitives are implemented
- •Bottom types
- •Conclusion
- •Traits
- •How traits work
- •Thin versus rich interfaces
- •Example: Rectangular objects
- •The Ordered trait
- •Why not multiple inheritance?
- •To trait, or not to trait?
- •Conclusion
- •Packages and Imports
- •Putting code in packages
- •Concise access to related code
- •Imports
- •Implicit imports
- •Package objects
- •Conclusion
- •Assertions and Unit Testing
- •Assertions
- •Unit testing in Scala
- •Informative failure reports
- •Using JUnit and TestNG
- •Property-based testing
- •Organizing and running tests
- •Conclusion
- •Case Classes and Pattern Matching
- •A simple example
- •Kinds of patterns
- •Pattern guards
- •Pattern overlaps
- •Sealed classes
- •The Option type
- •Patterns everywhere
- •A larger example
- •Conclusion
- •Working with Lists
- •List literals
- •The List type
- •Constructing lists
- •Basic operations on lists
- •List patterns
- •First-order methods on class List
- •Methods of the List object
- •Processing multiple lists together
- •Conclusion
- •Collections
- •Sequences
- •Sets and maps
- •Selecting mutable versus immutable collections
- •Initializing collections
- •Tuples
- •Conclusion
- •Stateful Objects
- •What makes an object stateful?
- •Reassignable variables and properties
- •Case study: Discrete event simulation
- •A language for digital circuits
- •The Simulation API
- •Circuit Simulation
- •Conclusion
- •Type Parameterization
- •Functional queues
- •Information hiding
- •Variance annotations
- •Checking variance annotations
- •Lower bounds
- •Contravariance
- •Object private data
- •Upper bounds
- •Conclusion
- •Abstract Members
- •A quick tour of abstract members
- •Type members
- •Abstract vals
- •Abstract vars
- •Initializing abstract vals
- •Abstract types
- •Path-dependent types
- •Structural subtyping
- •Enumerations
- •Case study: Currencies
- •Conclusion
- •Implicit Conversions and Parameters
- •Implicit conversions
- •Rules for implicits
- •Implicit conversion to an expected type
- •Converting the receiver
- •Implicit parameters
- •View bounds
- •When multiple conversions apply
- •Debugging implicits
- •Conclusion
- •Implementing Lists
- •The List class in principle
- •The ListBuffer class
- •The List class in practice
- •Functional on the outside
- •Conclusion
- •For Expressions Revisited
- •For expressions
- •The n-queens problem
- •Querying with for expressions
- •Translation of for expressions
- •Going the other way
- •Conclusion
- •The Scala Collections API
- •Mutable and immutable collections
- •Collections consistency
- •Trait Traversable
- •Trait Iterable
- •Sets
- •Maps
- •Synchronized sets and maps
- •Concrete immutable collection classes
- •Concrete mutable collection classes
- •Arrays
- •Strings
- •Performance characteristics
- •Equality
- •Views
- •Iterators
- •Creating collections from scratch
- •Conversions between Java and Scala collections
- •Migrating from Scala 2.7
- •Conclusion
- •The Architecture of Scala Collections
- •Builders
- •Factoring out common operations
- •Integrating new collections
- •Conclusion
- •Extractors
- •An example: extracting email addresses
- •Extractors
- •Patterns with zero or one variables
- •Variable argument extractors
- •Extractors and sequence patterns
- •Extractors versus case classes
- •Regular expressions
- •Conclusion
- •Annotations
- •Why have annotations?
- •Syntax of annotations
- •Standard annotations
- •Conclusion
- •Working with XML
- •Semi-structured data
- •XML overview
- •XML literals
- •Serialization
- •Taking XML apart
- •Deserialization
- •Loading and saving
- •Pattern matching on XML
- •Conclusion
- •Modular Programming Using Objects
- •The problem
- •A recipe application
- •Abstraction
- •Splitting modules into traits
- •Runtime linking
- •Tracking module instances
- •Conclusion
- •Object Equality
- •Equality in Scala
- •Writing an equality method
- •Recipes for equals and hashCode
- •Conclusion
- •Combining Scala and Java
- •Using Scala from Java
- •Annotations
- •Existential types
- •Using synchronized
- •Compiling Scala and Java together
- •Conclusion
- •Actors and Concurrency
- •Trouble in paradise
- •Actors and message passing
- •Treating native threads as actors
- •Better performance through thread reuse
- •Good actors style
- •A longer example: Parallel discrete event simulation
- •Conclusion
- •Combinator Parsing
- •Example: Arithmetic expressions
- •Running your parser
- •Basic regular expression parsers
- •Another example: JSON
- •Parser output
- •Implementing combinator parsers
- •String literals and regular expressions
- •Lexing and parsing
- •Error reporting
- •Backtracking versus LL(1)
- •Conclusion
- •GUI Programming
- •Panels and layouts
- •Handling events
- •Example: Celsius/Fahrenheit converter
- •Conclusion
- •The SCells Spreadsheet
- •The visual framework
- •Disconnecting data entry and display
- •Formulas
- •Parsing formulas
- •Evaluation
- •Operation libraries
- •Change propagation
- •Conclusion
- •Scala Scripts on Unix and Windows
- •Glossary
- •Bibliography
- •About the Authors
- •Index
Section 24.12 |
Chapter 24 · The Scala Collections API |
583 |
What happened here is that the evenElems demands a class manifest for the type parameter U, but none was found. The solution in this case is, of course, to demand another implicit class manifest for U. So the following works:
scala> def wrap[U: ClassManifest](xs: Vector[U]) = evenElems(xs)
wrap: [U](xs: Vector[U])(implicit evidence$1: ClassManifest[U])Array[U]
This example also shows that the context bound in the definition of U is just a shorthand for an implicit parameter named here evidence$1 of type
ClassManifest[U].
In summary, generic array creation demands class manifests. Whenever you create an array of a type parameter T, you also need to provide an implicit class manifest for T. The easiest way to do this is to declare the type parameter with a ClassManifest context bound, as in [T: ClassManifest].
24.12 Strings
Like arrays, strings are not directly sequences, but they can be converted to them, and they also support all sequence operations. Here are some examples of operations you can invoke on strings:
scala> val str = "hello"
str: java.lang.String = hello
scala> str.reverse res6: String = olleh
scala> str.map(_.toUpper) res7: String = HELLO
scala> str drop 3 res8: String = lo
scala> str slice (1, 4) res9: String = ell
scala> val s: Seq[Char] = str
s: Seq[Char] = WrappedString(h, e, l, l, o)
These operations are supported by two implicit conversions, which were explained in Section 21.7. The first, low-priority conversion maps a String
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Section 24.13 |
Chapter 24 · The Scala Collections API |
584 |
to a WrappedString, which is a subclass of immutable.IndexedSeq. This conversion was applied in the last line of the previous example in which a string was converted into a Seq. The other, high-priority conversion maps a string to a StringOps object, which adds all methods on immutable sequences to strings. This conversion was implicitly inserted in the method calls of reverse, map, drop, and slice in the previous example.
24.13Performance characteristics
As the previous explanations have shown, different collection types have different performance characteristics. That’s often the primary reason for picking one collection type over another. You can see the performance characteristics of some common operations on collections summarized in two tables, Table 24.10 and Table 24.11.
The entries in these two tables are explained as follows:
CThe operation takes (fast) constant time.
eC |
The operation takes effectively constant time, but |
|
this might depend on some assumptions such as the |
|
maximum length of a vector or the distribution of |
|
hash keys. |
aC |
The operation takes amortized constant time. Some |
|
invocations of the operation might take longer, but |
|
if many operations are performed on average only |
|
constant time per operation is taken. |
Log |
The operation takes time proportional to the loga- |
|
rithm of the collection size. |
LThe operation is linear, that is it takes time proportional to the collection size.
-The operation is not supported.
Table 24.10 treats sequence types—both immutable and mutable—with the following operations:
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Section 24.14 |
Chapter 24 · The Scala Collections API |
585 |
head |
Selecting the first element of the sequence. |
tail |
Producing a new sequence that consists of all ele- |
|
ments except the first one. |
apply |
Indexing. |
update |
Functional update (with updated) for immutable |
|
sequences, side-effecting update (with update) for |
|
mutable sequences. |
prepend |
Adding an element to the front of the sequence. |
|
For immutable sequences, this produces a new se- |
|
quence. For mutable sequences it modifies the exist- |
|
ing sequence. |
append |
Adding an element at the end of the sequence. |
|
For immutable sequences, this produces a new se- |
|
quence. For mutable sequences it modifies the exist- |
|
ing sequence. |
insert |
Inserting an element at an arbitrary position in the |
|
sequence. This is only supported directly for muta- |
|
ble sequences. |
Table 24.11 treats mutable and immutable sets and maps with the following operations:
lookup |
Testing whether an element is contained in set, or |
|
selecting a value associated with a key. |
add |
Adding a new element to a set or a new key/value |
|
pair to a map. |
remove |
Removing an element from a set or a key from a |
|
map. |
min |
The smallest element of the set, or the smallest key |
|
of a map. |
24.14Equality
The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences. Collections in different categories are always unequal. For instance, Set(1, 2, 3) is unequal to List(1, 2, 3) even though they contain the same elements. On the other hand, within the same category, collections are equal if and
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Section 24.14 |
Chapter 24 · The Scala Collections API |
586 |
|
head |
|
tail |
|
apply |
|
update |
|
prepend |
|
append |
|
insert |
immutable |
C |
|
C |
|
L |
|
L |
|
C |
|
L |
|
- |
List |
|
|
|
|
|
|
|||||||
Stream |
C |
|
C |
|
L |
|
L |
|
C |
|
L |
|
- |
Vector |
eC |
|
eC |
|
eC |
|
eC |
|
eC |
|
eC |
|
- |
Stack |
C |
|
C |
|
L |
|
L |
|
C |
|
L |
|
- |
Queue |
aC |
|
aC |
|
L |
|
L |
|
L |
|
C |
|
- |
Range |
C |
|
C |
|
C |
|
- |
|
- |
|
- |
|
- |
String |
C |
|
L |
|
C |
|
L |
|
L |
|
L |
|
- |
mutable |
C |
|
L |
|
C |
|
C |
|
L |
|
aC |
|
L |
ArrayBuffer |
|
|
|
|
|
|
|||||||
ListBuffer |
C |
|
L |
|
L |
|
L |
|
C |
|
C |
|
L |
StringBuilder |
C |
|
L |
|
C |
|
C |
|
L |
|
aC |
|
L |
MutableList |
C |
|
L |
|
L |
|
L |
|
C |
|
C |
|
L |
Queue |
C |
|
L |
|
L |
|
L |
|
C |
|
C |
|
L |
ArraySeq |
C |
|
L |
|
C |
|
C |
|
- |
|
- |
|
- |
Stack |
C |
|
L |
|
L |
|
L |
|
C |
|
L |
|
L |
ArrayStack |
C |
|
L |
|
C |
|
C |
|
aC |
|
L |
|
L |
Array |
C |
|
L |
|
C |
|
C |
|
- |
|
- |
|
- |
Table 24.10 · Performance characteristics of sequence types
|
lookup |
|
add |
|
remove |
|
min |
immutable |
eC |
|
eC |
|
eC |
|
L |
HashSet/HashMap |
|
|
|
||||
TreeSet/TreeMap |
Log |
|
Log |
|
Log |
|
Log |
BitSet |
C |
|
L |
|
L |
|
eCa |
ListMap |
L |
|
L |
|
L |
|
L |
mutable |
eC |
|
eC |
|
eC |
|
L |
HashSet/HashMap |
|
|
|
||||
WeakHashMap |
eC |
|
eC |
|
eC |
|
L |
BitSet |
C |
|
aC |
|
C |
|
eCa |
Table 24.11 · Performance characteristics of set and map types
aAssuming bits are densely packed.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index