You are previewing Programming Scala.

Programming Scala

Cover of Programming Scala by Dean Wampler... Published by O'Reilly Media, Inc.
  1. Programming Scala
    1. SPECIAL OFFER: Upgrade this ebook with O’Reilly
    2. A Note Regarding Supplemental Files
    3. Foreword
    4. Preface
      1. Welcome to Programming Scala
      2. Conventions Used in This Book
      3. Using Code Examples
      4. Safari® Books Online
      5. How to Contact Us
      6. Acknowledgments
    5. 1. Zero to Sixty: Introducing Scala
      1. Why Scala?
      2. Installing Scala
      3. For More Information
      4. A Taste of Scala
      5. A Taste of Concurrency
      6. Recap and What’s Next
    6. 2. Type Less, Do More
      1. In This Chapter
      2. Semicolons
      3. Variable Declarations
      4. Method Declarations
      5. Inferring Type Information
      6. Literals
      7. Tuples
      8. Option, Some, and None: Avoiding nulls
      9. Organizing Code in Files and Namespaces
      10. Importing Types and Their Members
      11. Abstract Types And Parameterized Types
      12. Reserved Words
      13. Recap and What’s Next
    7. 3. Rounding Out the Essentials
      1. Operator? Operator?
      2. Methods Without Parentheses and Dots
      3. Domain-Specific Languages
      4. Scala if Statements
      5. Scala for Comprehensions
      6. Other Looping Constructs
      7. Conditional Operators
      8. Pattern Matching
      9. Enumerations
      10. Recap and What’s Next
    8. 4. Traits
      1. Introducing Traits
      2. Stackable Traits
      3. Constructing Traits
      4. Recap and What’s Next
    9. 5. Basic Object-Oriented Programming in Scala
      1. Class and Object Basics
      2. Parent Classes
      3. Constructors in Scala
      4. Nested Classes
      5. Visibility Rules
      6. Recap and What’s Next
    10. 6. Advanced Object-Oriented Programming In Scala
      1. Overriding Members of Classes and Traits
      2. Companion Objects
      3. Case Classes
      4. Equality of Objects
      5. Recap and What’s Next
    11. 7. The Scala Object System
      1. The Predef Object
      2. Classes and Objects: Where Are the Statics?
      3. Sealed Class Hierarchies
      4. The Scala Type Hierarchy
      5. Linearization of an Object’s Hierarchy
      6. Recap and What’s Next
    12. 8. Functional Programming in Scala
      1. What Is Functional Programming?
      2. Functional Programming in Scala
      3. Recursion
      4. Tail Calls and Tail-Call Optimization
      5. Functional Data Structures
      6. Traversing, Mapping, Filtering, Folding, and Reducing
      7. Pattern Matching
      8. Partial Functions
      9. Currying
      10. Implicits
      11. Implicit Function Parameters
      12. Call by Name, Call by Value
      13. Lazy Vals
      14. Recap: Functional Component Abstractions
    13. 9. Robust, Scalable Concurrency with Actors
      1. The Problems of Shared, Synchronized State
      2. Actors
      3. Actors in Scala
      4. Traditional Concurrency in Scala: Threading and Events
      5. Recap and What’s Next
    14. 10. Herding XML in Scala
      1. Reading XML
      2. Writing XML
      3. Recap and What’s Next
    15. 11. Domain-Specific Languages in Scala
      1. Internal DSLs
      2. External DSLs with Parser Combinators
      3. Recap and What’s Next
    16. 12. The Scala Type System
      1. Reflecting on Types
      2. Understanding Parameterized Types
      3. Variance Under Inheritance
      4. Type Bounds
      5. Nothing and Null
      6. Understanding Abstract Types
      7. Path-Dependent Types
      8. Value Types
      9. Self-Type Annotations
      10. Structural Types
      11. Existential Types
      12. Infinite Data Structures and Laziness
      13. Recap and What’s Next
    17. 13. Application Design
      1. Annotations
      2. Enumerations Versus Pattern Matching
      3. Thoughts On Annotations and Enumerations
      4. Using Nulls Versus Options
      5. Exceptions and the Alternatives
      6. Scalable Abstractions
      7. Effective Design of Traits
      8. Design Patterns
      9. Better Design with Design By Contract
      10. Recap and What’s Next
    18. 14. Scala Tools, Libraries, and IDE Support
      1. Command-Line Tools
      2. Build Tools
      3. Integration with IDEs
      4. Test-Driven Development in Scala
      5. Other Notable Scala Libraries and Tools
      6. Java Interoperability
      7. Java Library Interoperability
      8. Recap and What’s Next
    19. A. References
    20. Glossary
    21. Index
    22. About the Authors
    23. Colophon
    24. SPECIAL OFFER: Upgrade this ebook with O’Reilly
O'Reilly logo

A Taste of Concurrency

There are many reasons to be seduced by Scala. One reason is the Actors API included in the Scala library, which is based on the robust Actors concurrency model built into Erlang (see [Haller2007]). Here is an example to whet your appetite.

In the Actor model of concurrency ([Agha1987]), independent software entities called Actors share no state information with each other. Instead, they communicate by exchanging messages. By eliminating the need to synchronize access to shared, mutable state, it is far easier to write robust, concurrent applications.

In this example, instances in a geometric Shape hierarchy are sent to an Actor for drawing on a display. Imagine a scenario where a rendering “farm” generates scenes in an animation. As the rendering of a scene is completed, the shape “primitives” that are part of the scene are sent to an Actor for a display subsystem.

To begin, we define a Shape class hierarchy:

// code-examples/IntroducingScala/shapes.scala

package shapes {
  class Point(val x: Double, val y: Double) {
    override def toString() = "Point(" + x + "," + y + ")"
  }

  abstract class Shape() {
    def draw(): Unit
  }

  class Circle(val center: Point, val radius: Double) extends Shape {
    def draw() = println("Circle.draw: " + this)
    override def toString() = "Circle(" + center + "," + radius + ")"
  }

  class Rectangle(val lowerLeft: Point, val height: Double, val width: Double)
        extends Shape {
    def draw() = println("Rectangle.draw: " + this)
    override def toString() =
      "Rectangle(" + lowerLeft + "," + height + "," + width + ")"
  }

  class Triangle(val point1: Point, val point2: Point, val point3: Point)
        extends Shape {
    def draw() = println("Triangle.draw: " + this)
    override def toString() =
      "Triangle(" + point1 + "," + point2 + "," + point3 + ")"
  }
}

The Shape class hierarchy is defined in a shapes package. You can declare the package using Java syntax, but Scala also supports a syntax similar to C#’s “namespace” syntax, where the entire declaration is scoped using curly braces, as used here. The Java-style package declaration syntax is far more commonly used, however, being both compact and readable.

The Point class represents a two-dimensional point on a plane. Note the argument list after the class name. Those are constructor parameters. In Scala, the whole class body is the constructor, so you list the arguments for the primary constructor after the class name and before the class body. (We’ll see how to define auxiliary constructors in Constructors in Scala.) Because we put the val keyword before each parameter declaration, they are automatically converted to read-only fields with the same names with public reader methods of the same name. That is, when you instantiate a Point instance, e.g., point, you can read the fields using point.x and point.y. If you want mutable fields, then use the keyword var. We’ll explore variable declarations and the val and var keywords in Variable Declarations.

The body of Point defines one method, an override of the familiar toString method in Java (like ToString in C#). Note that Scala, like C#, requires the override keyword whenever you override a concrete method. Unlike C#, you don’t have to use a virtual keyword on the original concrete method. In fact, there is no virtual keyword in Scala. As before, we omit the curly braces ({...}) around the body of toString, since it has only one expression.

Shape is an abstract class. Abstract classes in Scala are similar to those in Java and C#. We can’t instantiate instances of abstract classes, even when all their field and method members are concrete.

In this case, Shape declares an abstract draw method. We know it is abstract because it has no body. No abstract keyword is required on the method. Abstract methods in Scala are just like abstract methods in Java and C#. (See Overriding Members of Classes and Traits for more details.)

The draw method returns Unit, which is a type that is roughly equivalent to void in C-derived languages like Java, etc. (See The Scala Type Hierarchy for more details.)

Circle is declared as a concrete subclass of Shape. It defines the draw method to simply print a message to the console. Circle also overrides toString.

Rectangle is also a concrete subclass of Shape that defines draw and overrides toString. For simplicity, we assume it is not rotated relative to the x and y axes. Hence, all we need is one point, the lower lefthand point will do, and the height and width of the rectangle.

Triangle follows the same pattern. It takes three Points as its constructor arguments.

Both draw methods in Circle, Rectangle, and Triangle use this. As in Java and C#, this is how an instance refers to itself. In this context, where this is the righthand side of a String concatenation expression (using the plus sign), this.toString is invoked implicitly.

Note

Of course, in a real application, you would not implement drawing in “domain model” classes like this, since the implementations would depend on details like the operating system platform, graphics API, etc. We will see a better design approach when we discuss traits in Chapter 4.

Now that we have defined our shapes types, let’s return to Actors. We define an Actor that receives “messages” that are shapes to draw:

// code-examples/IntroducingScala/shapes-actor.scala

package shapes {
  import scala.actors._
  import scala.actors.Actor._

  object ShapeDrawingActor extends Actor {
    def act() {
      loop {
        receive {
          case s: Shape => s.draw()
          case "exit"   => println("exiting..."); exit
          case x: Any   => println("Error: Unknown message! " + x)
        }
      }
    }
  }
}

The Actor is declared to be part of the shapes package. Next, we have two import statements.

The first import statement imports all the types in the scala.actors package. In Scala, the underscore _ is used the way the star * is used in Java.

Note

Because * is a valid character for a function name, it can’t be used as the import wildcard. Instead, _ is reserved for this purpose.

All the methods and public fields from Actor are imported by the second import. These are not static imports from the Actor type, as they would be in Java. Rather, they are imported from an object that is also named Actor. The class and object can have the same name, as we will see in Companion Objects.

Our Actor class definition, ShapeDrawingActor, is an object that extends Actor (the type, not the object). The act method is overridden to do the unique work of the Actor. Because act is an abstract method, we don’t need to explicitly override it with the override keyword. Our Actor loops indefinitely, waiting for incoming messages.

During each pass in the loop, the receive method is called. It blocks until a new message arrives. Why is the code after receive enclosed in curly braces {...} and not parentheses (...)? We will learn later that there are cases where this substitution is allowed and is quite useful (see Chapter 3). For now, what you need to know is that the expressions inside the braces constitute a single function literal that is passed to receive. This function literal does a pattern match on the message instance to decide how to handle the message. Because of the case clauses, it looks like a typical switch statement in Java, for example, and the behavior is very similar.

The first case does a type comparison with the message. (There is no explicit variable for the message instance in the code; it is inferred.) If the message is of type Shape, the first case matches. The message instance is cast to a Shape and assigned to the variable s, and then the draw method is called on it.

If the message is not a Shape, the second case is tried. If the message is the string "exit", the Actor prints a message and terminates execution. Actors should usually have a way to exit gracefully!

The last case clause handles any other message instance, thereby functioning as the default case. The Actor reports an error and then drops the message. Any is the parent of all types in the Scala type hierarchy, like Object is the root type in Java and other languages. Hence, this case clause will match any message of any type. Pattern matching is eager; we have to put this case clause at the end, so it doesn’t consume the messages we are expecting!

Recall that we declared draw as an abstract method in Shape and we implemented draw in the concrete subclasses. Hence, the code in the first case statement invokes a polymorphic operation.

Finally, here is a script that uses the ShapeDrawingActor Actor:

// code-examples/IntroducingScala/shapes-actor-script.scala

import shapes._

ShapeDrawingActor.start()

ShapeDrawingActor ! new Circle(new Point(0.0,0.0), 1.0)
ShapeDrawingActor ! new Rectangle(new Point(0.0,0.0), 2, 5)
ShapeDrawingActor ! new Triangle(new Point(0.0,0.0),
                                 new Point(1.0,0.0),
                                 new Point(0.0,1.0))
ShapeDrawingActor ! 3.14159

ShapeDrawingActor ! "exit"

The shapes in the shapes package are imported.

The ShapeDrawingActor Actor is started. By default, it runs in its own thread (there are alternatives we will discuss in Chapter 9), waiting for messages.

Five messages are sent to the Actor, using the syntax actor ! message. The first message sends a Circle instance. The Actor “draws” the circle. The second message sends a Rectangle message. The Actor “draws” the rectangle. The third message does the same thing for a Triangle. The fourth message sends a Double that is approximately equal to Pi. This is an unknown message for the Actor, so it just prints an error message. The final message sends an “exit” string, which causes the Actor to terminate.

To try out the Actor example, start by compiling the first two files. You can get the sources from the O’Reilly download site (see Getting the Code Examples for details), or you can create them yourself.

Use the following command to compile the files:

 scalac shapes.scala shapes-actor.scala

While the source file names and locations don’t have to match the file contents, you will notice that the generated class files are written to a shapes directory and there is one class file for each class we defined. The class file names and locations must conform to the JVM requirements.

Now you can run the script to see the Actor in action:

 scala -cp . shapes-actor-script.scala

You should see the following output:

Circle.draw: Circle(Point(0.0,0.0),1.0)
Rectangle.draw: Rectangle(Point(0.0,0.0),2.0,5.0)
Triangle.draw: Triangle(Point(0.0,0.0),Point(1.0,0.0),Point(0.0,1.0))
Error: Unknown message! 3.14159
exiting...

For more on Actors, see Chapter 9.

The best content for your career. Discover unlimited learning on demand for around $1/day.