├── chapter11 ├── build.sbt └── src │ └── main │ └── scala │ └── scalax │ ├── functional │ ├── Implicits.scala │ ├── Monoid.scala │ ├── Functor.scala │ ├── Monad.scala │ └── Applicative.scala │ ├── resource │ ├── example.scala │ └── resource.scala │ └── config │ ├── Test.scala │ └── Config.scala ├── chapter7 ├── manifests │ └── dummy.scala ├── type-programming │ ├── hlist.scala │ ├── booleans.scala │ └── hlist2.scala └── type-class │ ├── typeclass.scala │ └── tyoeclass2.scala ├── chapter1 └── jvm-examples │ ├── ScalaUtils.scala │ ├── FunctionalUtil.scala │ ├── JavaTest.java │ └── JavaFunction.java ├── chapter3 ├── old-conventions │ ├── Foo.java │ ├── brackets.scala │ └── Average.scala ├── newlines │ └── Test.java ├── meaningful-names │ ├── AverageInt.scala │ └── Average.scala └── annotations │ ├── TailCall.scala │ └── Switch.scala ├── chapter5 ├── identifiers │ ├── Foo.scala │ └── Usage.scala ├── scope │ ├── package.scala │ └── transactional.scala ├── bindings │ ├── externalbindings.scala │ └── testbindings.scala ├── limitscope │ ├── predef-conflict.scala │ └── sample-package.scala ├── views │ └── privilege.scala ├── wrappers │ └── file-wrapper.scala └── implicitscope │ └── library.scala ├── README ├── chapter9 ├── build.sbt └── src │ └── main │ └── scala │ ├── messageapi.scala │ ├── main.scala │ ├── AdaptiveScatterGather.scala │ └── ScatterGather.scala ├── chapter4 └── trait-composition │ ├── inheritance.scala │ ├── compose.scala │ ├── mixin-inheritance.scala │ ├── component-inheritance.scala │ └── named-default-class.scala ├── chapter2 ├── option │ └── lifter.scala ├── equals │ └── PolymorphicEquals.scala └── immutability │ └── MapConcurrencyTest.scala ├── chapter6 ├── existential-types │ ├── Test.java │ └── existential.scala └── dependent-types │ └── callbacks.scala └── LICENSE.txt /chapter11/build.sbt: -------------------------------------------------------------------------------- 1 | scalaVersion := "2.9.1" 2 | 3 | 4 | -------------------------------------------------------------------------------- /chapter7/manifests/dummy.scala: -------------------------------------------------------------------------------- 1 | class Test { 2 | def first[A : ClassManifest](x : Array[A]) = Array(x(0)) 3 | } 4 | -------------------------------------------------------------------------------- /chapter1/jvm-examples/ScalaUtils.scala: -------------------------------------------------------------------------------- 1 | object ScalaUtils { 2 | def log(msg : String) : Unit = Console.println(msg) 3 | val MAX_LOG_SIZE = 1056 4 | } 5 | -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/functional/Implicits.scala: -------------------------------------------------------------------------------- 1 | package scalax.functional 2 | 3 | object Implicits extends FunctorImplicits with MonadImplicits {} -------------------------------------------------------------------------------- /chapter3/old-conventions/Foo.java: -------------------------------------------------------------------------------- 1 | public class Foo { 2 | public static void main(String[] args) 3 | 4 | { 5 | System.out.println("HAI"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter5/identifiers/Foo.scala: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | // Defines the class Foo in the root namespace. The name "Foo" is the binding of this class. 4 | class Foo { 5 | val x = 5 6 | } 7 | -------------------------------------------------------------------------------- /chapter5/scope/package.scala: -------------------------------------------------------------------------------- 1 | package object foo { 2 | implicit def foo = new Foo 3 | } 4 | 5 | package foo { 6 | class Foo { 7 | override def toString = "FOO!" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/functional/Monoid.scala: -------------------------------------------------------------------------------- 1 | package com.github.jsuereth.applicative 2 | 3 | trait Monoid[A] { 4 | def zero: A 5 | def combine(a: A, b: A): A 6 | } 7 | 8 | object Monoid {} -------------------------------------------------------------------------------- /chapter5/identifiers/Usage.scala: -------------------------------------------------------------------------------- 1 | import test.{Foo=>Bar} 2 | 3 | object Test { 4 | def main(args: Array[String]) : Unit = { 5 | val x = new Bar 6 | println( "Created new: " + x) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /chapter3/newlines/Test.java: -------------------------------------------------------------------------------- 1 | 2 | class Test { 3 | private int x = 5; 4 | public String foo() { 5 | return "HAI" 6 | + x 7 | + "ZOMG" 8 | + "\n"; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /chapter1/jvm-examples/FunctionalUtil.scala: -------------------------------------------------------------------------------- 1 | object FunctionUtil { 2 | def testFunction(f : Int => Int) : Int = f(5) 3 | } 4 | 5 | abstract class AbstractFunctionIntIntForJava extends (Int => Int) { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /chapter3/meaningful-names/AverageInt.scala: -------------------------------------------------------------------------------- 1 | object `Average$int` { 2 | def avg(values : List[Int]) = { 3 | val sum = values.foldLeft(0.0) { _ + _.toDouble } 4 | sum / values.size.toDouble 5 | } 6 | 7 | } 8 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This repository contains all the source code used in the Scala In Depth book (found at http://www.manning.com/suereth). This code is copyright 2011, Joshua Suereth, All rights reserved. 2 | 3 | The code is licensed under a BSD licenese (see LICENSE.txt). 4 | -------------------------------------------------------------------------------- /chapter9/build.sbt: -------------------------------------------------------------------------------- 1 | name := "scatter-gather" 2 | 3 | organization := "scalaindepth" 4 | 5 | resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases" 6 | 7 | libraryDependencies += "se.scalablesolutions.akka" % "akka-actor" % "1.1.2" 8 | 9 | 10 | -------------------------------------------------------------------------------- /chapter5/bindings/externalbindings.scala: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | // The x in this file is used to demenstrate an externally bound x within the testbindings.scala file. 4 | // These two files should be compiled together. 5 | object x { 6 | override def toString = "Externally bound x object in package test" 7 | } 8 | -------------------------------------------------------------------------------- /chapter1/jvm-examples/JavaTest.java: -------------------------------------------------------------------------------- 1 | 2 | class JavaTest { 3 | public static void main(String[] args) { 4 | ScalaUtils.log("Hello!"); 5 | ScalaUtils$.MODULE$.log("Hello!"); 6 | System.out.println(ScalaUtils.MAX_LOG_SIZE()); 7 | System.out.println(ScalaUtils$.MODULE$.MAX_LOG_SIZE()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter4/trait-composition/inheritance.scala: -------------------------------------------------------------------------------- 1 | 2 | 3 | trait Logger { 4 | def log(category : String, msg : String) : Unit = { 5 | println(msg) 6 | } 7 | } 8 | 9 | trait DataAccess with Logger { 10 | 11 | def query[A](in : String) : A = { 12 | log("QUERY", in) 13 | 5 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/trait-composition/compose.scala: -------------------------------------------------------------------------------- 1 | 2 | trait Logger { 3 | def log(category : String, msg : String) : Unit = { 4 | println(msg) 5 | } 6 | } 7 | 8 | 9 | 10 | trait DataAccess { 11 | val logger = new Logger 12 | 13 | def query[A](in : String) : A = { 14 | logger.log("QUERY", in) 15 | 5 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter1/jvm-examples/JavaFunction.java: -------------------------------------------------------------------------------- 1 | class JavaFunction { 2 | public static void main(String[] args) { 3 | System.out.println(FunctionUtil.testFunction((scala.Function1)new AbstractFunctionIntIntForJava() { 4 | public Integer apply(Integer argument) { 5 | return argument + 5; 6 | } 7 | })); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter2/option/lifter.scala: -------------------------------------------------------------------------------- 1 | 2 | 3 | object Lifter { 4 | 5 | def foo(a : String, b : String) = a + b 6 | 7 | def lift3[A,B,C,D](f : Function3[A,B,C,D]) : Function3[Option[A], Option[B], Option[C], Option[D]] = { 8 | (oa : Option[A], ob : Option[B], oc : Option[C]) => 9 | for(a <- oa; b <- ob; c <- oc) yield f(a,b,c) 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /chapter9/src/main/scala/messageapi.scala: -------------------------------------------------------------------------------- 1 | package scattergather 2 | 3 | import akka.actor.ActorRef 4 | 5 | /** 6 | * Represents a Search Query that is sent through the actors system. 7 | */ 8 | case class SearchQuery(query : String, maxDocs : Int, gatherer : ActorRef) 9 | 10 | /** 11 | * Represents a partial or full response of query results. 12 | */ 13 | case class QueryResponse(results : Seq[(Double, String)]) -------------------------------------------------------------------------------- /chapter6/existential-types/Test.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | // This class demonstrates how Java treats existential types. 4 | public class Test { 5 | public static void main(String[] args) { 6 | List foo = new ArrayList(); 7 | List bar = foo; // When compiled with -Xlint this gives a warning. 8 | } 9 | public static List makeList() { 10 | return new ArrayList(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter3/old-conventions/brackets.scala: -------------------------------------------------------------------------------- 1 | trait FooHolder 2 | { 3 | def foo() 4 | 5 | { 6 | println("foo was called") 7 | } 8 | } 9 | 10 | 11 | trait FooHolder2 12 | { 13 | def foo() : Unit = 14 | 15 | { 16 | println("foo2 was called") 17 | } 18 | } 19 | 20 | trait IfIssues { 21 | if(true) 22 | { 23 | println("true!") 24 | } 25 | else 26 | { 27 | println("false!") 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /chapter3/meaningful-names/Average.scala: -------------------------------------------------------------------------------- 1 | object Average { 2 | def avg(values : List[Double] = List(0.0,1.0,0.5)) = { 3 | val sum = values.foldLeft(0.0) { _ + _ } 4 | sum / values.size.toDouble 5 | } 6 | 7 | def `avg$default$1` = List(0.0,0.0,0.) 8 | 9 | /*class `$anonfun` { 10 | class `1` { 11 | println("O MY!") 12 | } 13 | }*/ 14 | } 15 | 16 | /*class `Average$$anonfun$1` { 17 | println("O MY!") 18 | }*/ 19 | 20 | -------------------------------------------------------------------------------- /chapter4/trait-composition/mixin-inheritance.scala: -------------------------------------------------------------------------------- 1 | 2 | trait Logger { 3 | def log(category : String, msg : String) : Unit = { 4 | println(msg) 5 | } 6 | } 7 | 8 | 9 | 10 | trait DataAccess { 11 | def query[A](in : String) : A = { 12 | 5 13 | } 14 | } 15 | 16 | 17 | trait LoggedDataAccess extends DataAccess with Logger { 18 | def query[A](in : String) : A = { 19 | log("QUERY", in) 20 | super.query(in) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter7/type-programming/hlist.scala: -------------------------------------------------------------------------------- 1 | sealed trait HList {} 2 | 3 | final case class HCons[H, T <: HList](head : H, tail : T) extends HList { 4 | def ::[T](v : T) = HCons(v,this) 5 | override def toString = head + " :: " + tail 6 | } 7 | class HNil extends HList { 8 | def ::[T](v : T) = HCons(v,this) 9 | override def toString = "Nil" 10 | } 11 | 12 | object HList { 13 | type ::[H, T <: HList] = HCons[H,T] 14 | val :: = HCons 15 | val HNil = new HNil 16 | } 17 | -------------------------------------------------------------------------------- /chapter3/old-conventions/Average.scala: -------------------------------------------------------------------------------- 1 | object Average { 2 | 3 | 4 | def avg(values : List[Double])(implicit adjustment : Double => Double) = { 5 | val sum = values.foldLeft(0.0) { 6 | (sum, cur) => sum + adjustment(cur) 7 | } 8 | sum / values.size.toDouble 9 | } 10 | 11 | def stdDev(values : List[Double]) = { 12 | val avgVal = avg(values) 13 | avg(values) 14 | { 15 | x : Double => Math.abs(x - avgVal) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter5/limitscope/predef-conflict.scala: -------------------------------------------------------------------------------- 1 | object Time { 2 | case class TimeRange(start : Long, end : Long) 3 | implicit def longWrapper(start : Long) = new { 4 | def to(end : Long) = TimeRange(start, end) 5 | } 6 | } 7 | 8 | object Test { 9 | println(1L to 10L) 10 | import Time._ 11 | println(1L to 10L) 12 | def x() = { 13 | import scala.Predef.longWrapper 14 | println(1L to 10L) 15 | def y() = { 16 | import Time.longWrapper 17 | println(1L to 10L) 18 | } 19 | y() 20 | } 21 | x() 22 | } -------------------------------------------------------------------------------- /chapter5/scope/transactional.scala: -------------------------------------------------------------------------------- 1 | 2 | trait Transaction 3 | 4 | 5 | 6 | object DefaultTransaction extends Transaction { 7 | override def toString = "DefaultTransaction" 8 | } 9 | 10 | 11 | trait DatabaseAction { 12 | 13 | def executeQuery(query : String)(implicit transaction : Transaction) : Unit = { 14 | println("Executing [" + query + "] on " + transaction) 15 | } 16 | 17 | def doAction(implicit transaction : Transaction) : Unit 18 | } 19 | 20 | object TestAction extends DatabaseAction { 21 | override def doAction(implicit transaction : Transaction) { 22 | executeQuery("INSERT MY DATA") 23 | } 24 | } -------------------------------------------------------------------------------- /chapter5/views/privilege.scala: -------------------------------------------------------------------------------- 1 | import java.security._ 2 | 3 | /** This object defines an implicit view that will convert Scala functions 4 | * into PrivilegedAction instances that can be sent to the java.security.AccessController. 5 | */ 6 | object ScalaSecurityImplicits { 7 | implicit def functionToPrivilegedAction[A](func : Function0[A]) = 8 | new PrivilegedAction[A] { 9 | override def run() = func() 10 | } 11 | } 12 | 13 | /* 14 | 15 | scala> import ScalaSecurityImplicits._ 16 | import ScalaSecurityImplicits._ 17 | 18 | scala> AccessController.doPrivileged( () => 19 | | println("This is priviliged")) 20 | This is priviliged 21 | 22 | */ -------------------------------------------------------------------------------- /chapter5/limitscope/sample-package.scala: -------------------------------------------------------------------------------- 1 | package object complexmath { 2 | implicit def realToComplex(r : Double) = new ComplexNumber(r, 0.0) 3 | val i = ComplexNumber(0.0, 1.0) 4 | } 5 | 6 | package complexmath { 7 | // Represents a number composed of a real and imaginary part. 8 | case class ComplexNumber(real : Double, imaginary : Double) { 9 | def *(other : ComplexNumber) = ComplexNumber( (real*other.real) + (imaginary * other.imaginary), 10 | (real*other.imaginary) + (imaginary * other.real) ) 11 | def +(other : ComplexNumber) = ComplexNumber( real + other.real, imaginary + other.imaginary ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter3/annotations/TailCall.scala: -------------------------------------------------------------------------------- 1 | import annotation.tailrec 2 | 3 | case class Node(name : String, edges : Seq[Node] = Nil) 4 | 5 | object BFS { 6 | def search(start : Node, p : Node => Boolean) = { 7 | @tailrec 8 | def loop(nodeQueue : List[Node], visited : Set[Node]) : Option[Node] = 9 | nodeQueue match { 10 | case head :: tail if p(head) => 11 | Some(head) 12 | case head :: tail if !visited.contains(head) => 13 | loop(tail ++ head.edges, visited + head) 14 | case head :: tail => 15 | loop(tail, visited) 16 | case Nil => 17 | None 18 | } 19 | loop(List(start), Set()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter7/type-programming/booleans.scala: -------------------------------------------------------------------------------- 1 | package booleans 2 | 3 | /** 4 | * Encoding of Boolean types into the type system. 5 | */ 6 | sealed trait TBool { 7 | /**The 'if' function as a type constructor. 8 | * TrueType: The type to return if the current boolean is true. 9 | * FalseType: The type to return if the current boolean is false. 10 | * Up: The upper bound type for all values to prevent too many compiler acrobatics. 11 | */ 12 | type If[TrueType <: Up, FalseType <: Up, Up] <: Up 13 | } 14 | 15 | /** 16 | * Encoding of the value 'true' into the type system. 17 | */ 18 | class TTrue extends TBool { 19 | type If[TrueType <: Up, FalseType <: Up, Up] = TrueType 20 | } 21 | 22 | /** 23 | * Encoding of the value 'false' into the type system. 24 | */ 25 | class TFalse extends TBool { 26 | type If[TrueType <: Up, FalseType <: Up, Up] = FalseType 27 | } -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/resource/example.scala: -------------------------------------------------------------------------------- 1 | package scalax.resource 2 | 3 | import scalax.functional.{Applicative, Functor, Monad, Implicits} 4 | import Implicits._ 5 | import java.io._ 6 | 7 | object Example { 8 | 9 | type LazyTraversable[T] = collection.TraversableView[T, Traversable[T]] 10 | 11 | def makeLineTraversable(input: BufferedReader) = new Traversable[String] { 12 | def foreach[U](f: String => U): Unit = { 13 | var line = input.readLine() 14 | while (line != null) { 15 | f(line) 16 | line = input.readLine() 17 | } 18 | } 19 | } view 20 | 21 | def getLines(file: File): ManagedResource[LazyTraversable[String]] = 22 | for { 23 | input <- ManagedResource.readFile(file) 24 | val reader = new InputStreamReader(input) 25 | val buffered = new BufferedReader(reader) 26 | } yield makeLineTraversable(buffered) 27 | 28 | 29 | 30 | def lineLengthCount(inFile: File, outFile: File) = 31 | for { 32 | lines <- getLines(inFile) 33 | val counts = lines.map(_.length).toSeq.zipWithIndex 34 | output <- ManagedResource.writeFile(outFile) 35 | val writer = new OutputStreamWriter(output) 36 | val buffered = new BufferedWriter(writer) 37 | } yield buffered.write(counts.mkString("\n")) 38 | 39 | def main(args: Array[String]): Unit = { 40 | workflow(new File("test.in"), new File("test.out")).loan(_ => ()) 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, JoshuaSuereth 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | Neither the name of the Scala In Depth book nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/config/Test.scala: -------------------------------------------------------------------------------- 1 | package scalax.config.test 2 | 3 | 4 | import scalax.functional.{Functor,Monad,Applicative,ApplicativeMagic} 5 | import scalax.config.Config 6 | import scalax.functional.Implicits._ 7 | 8 | class DataStore(connection: java.sql.Connection) { 9 | // 10 | } 11 | 12 | class WorkerPool() {} 13 | 14 | class Application(ds: DataStore, pool: WorkerPool) { 15 | def doStuff = "Go Go Main Application!" 16 | } 17 | 18 | // This test shows how to configure a software application using the Config monad. 19 | object Test { 20 | 21 | // Default properties 22 | def properties = Config.propertyfile(new java.io.File("jdbc.properties")) 23 | // JDBC properties 24 | def jdbcUrl = Config.environment("jdbc.url") orElse properties.map(_.getProperty("jdbc.url")) 25 | def jdbcUser = Config.environment("jdbc.user") orElse properties.map(_.getProperty("jdbc.user")) 26 | def jdbcPw = Config.environment("jdbc.pw") orElse properties.map(_.getProperty("jdbc.pw")) 27 | // For a better example, configure a connection pool 28 | def connection = Applicative build jdbcUrl and jdbcUser and jdbcPw apply java.sql.DriverManager.getConnection 29 | // Building subsystems using components. 30 | def dataStore = connection map (new DataStore(_)) 31 | def workerPool = Config(new WorkerPool) 32 | def system = Applicative build dataStore and workerPool apply (new Application(_,_)) 33 | def main(args: Array[String]): Unit = { 34 | system.get.getOrElse(error("Error reading configuration for main system")).doStuff 35 | } 36 | } -------------------------------------------------------------------------------- /chapter3/annotations/Switch.scala: -------------------------------------------------------------------------------- 1 | import annotation.switch 2 | 3 | object WeekDay extends Enumeration { 4 | type WeekDay = Value 5 | val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value 6 | val Mon_ID = Mon.id; 7 | val Tue_ID = Tue.id; 8 | val Wed_ID = Wed.id; 9 | val Thu_ID = Thu.id; 10 | val Fri_ID = Fri.id; 11 | val Sat_ID = Sat.id; 12 | val Sun_ID = Sun.id; 13 | } 14 | 15 | import WeekDay._ 16 | 17 | class Test { 18 | 19 | 20 | 21 | def unannotated(x : Int) = x match { 22 | case 1 => "One" 23 | case 2 => "Two!" 24 | case z => z + "?" 25 | } 26 | def annotated(x : Int) = (x : @switch) match { 27 | case 1 => "One" 28 | case 2 => "Two!" 29 | case z => z + "?" 30 | } 31 | def notOptimized(x : Any) = x match { 32 | case 1 => "One" 33 | case 2 => "Two!" 34 | case _ => x + "?" 35 | } 36 | def notOptimised2(x : Int) = x match { 37 | case 1 => "One" 38 | case 2 => "Two!" 39 | case i if i % 2 == 0 => "Even" 40 | case _ => "Odd" 41 | } 42 | def notOptimised3(x : Int) = x match { 43 | case 1 => "One" 44 | case 2 => "Two!" 45 | case i : Int => "Other" 46 | } 47 | def notOptimisedEnum(x : WeekDay) = x.id match { 48 | case Mon_ID => "Case of the Mondays" 49 | case Tue_ID => "Ruby Tuesdays?" 50 | case Fri_ID => "Thank God!" 51 | case _ => "Not an interesting day" 52 | } 53 | 54 | def mightBeOptimised(x : WeekDay) = x match { 55 | case Mon => "Case of the Mondays" 56 | case Tue => "Ruby Tuesdays?" 57 | case Fri => "Thank God!" 58 | case _ => "Not an interesting day" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /chapter5/bindings/testbindings.scala: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | // This object contains the bindings/scope tests from Chapter 5. See 4 | // externalbindings.scala for other defintions used by this file. 5 | object Test { 6 | 7 | def main(arg : Array[String]) : Unit = { 8 | testSamePackage() 9 | testWildcardImport() 10 | testExplicitImport() 11 | testInlineDefinition() 12 | } 13 | 14 | // This looks for a binding 'x' within the same package (test) as this scope. 15 | def testSamePackage() { 16 | println(x) // prints: Externally bound x object in package test 17 | } 18 | 19 | // This defines a new scope with an 'x' binding that we can import with a wildcard. 20 | object Wildcard { 21 | def x = "Wildcard Import x" 22 | } 23 | 24 | // This function will print the value in the binding 'x' after importing from the Wildcard object 25 | // using a wildcard import. 26 | def testWildcardImport() { 27 | import Wildcard._ 28 | println(x) // prints: Wildcard Import x 29 | } 30 | 31 | // This defines another binding of 'x' that we can import explicitly. 32 | object Explicit { 33 | def x = "Explicit Import x" 34 | } 35 | 36 | def testExplicitImport() { 37 | import Explicit.x 38 | import Wildcard._ 39 | println(x) // prints: Explicit Import x 40 | } 41 | 42 | // This defines an inline binding for x. Note that with all the imports, there are no ambiguous naming conflicts. 43 | def testInlineDefinition() { 44 | val x = "Inline definition x" 45 | import Explicit.x 46 | import Wildcard._ 47 | println(x) // prints: Inline definition x 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/functional/Functor.scala: -------------------------------------------------------------------------------- 1 | package scalax.functional 2 | 3 | 4 | /** 5 | * This class represents a Functor from Category theory. It is able to convert elements in the category of all types into 6 | * the sub-category of types of T[_]. 7 | */ 8 | trait Functor[T[_]] { 9 | /** This method maps the given value into the functor category. It is akin to a constructor. 10 | */ 11 | def apply[A](x: A): T[A] 12 | /** This method takes a an unmapped morphism and translates it into the new domain. 13 | * @param x A mapped value. 14 | * @param f A morphism in the original domain 15 | * @return The new value in the final domain. 16 | */ 17 | def map[A,B](x: T[A])(f: A=>B): T[B] 18 | } 19 | 20 | 21 | object Functor { 22 | // Defaults for standard lib. 23 | implicit object TraversableFunctor extends Functor[Traversable] { 24 | override def apply[A](x: A) = Traversable(x) 25 | override def map[A,B](x:Traversable[A])(f: A=>B) = x map f 26 | } 27 | implicit object OptionFunctor extends Functor[Option] { 28 | override def apply[A](x: A) = Some(x) 29 | override def map[A,B](x: Option[A])(f: A=>B) = x map f 30 | } 31 | } 32 | 33 | /** 34 | * This class stores the 'pimped' functions used on values F[A] if F is a functor. 35 | */ 36 | final class FunctorOps[F[_], A](val value: F[A], val functor: Functor[F]) { 37 | @inline final def map[B](f: A=>B): F[B] = functor.map(value)(f) 38 | } 39 | 40 | /** 41 | * This trait stores all the implicit views to bring convenient syntax to functors. 42 | */ 43 | trait FunctorImplicits { 44 | implicit def funcOperations[F[_], A](value : F[A])(implicit functor: Functor[F]): FunctorOps[F,A] = 45 | new FunctorOps[F,A](value, functor) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /chapter7/type-class/typeclass.scala: -------------------------------------------------------------------------------- 1 | import java.io._ 2 | 3 | /** 4 | * Defines an interface for things that are like files for our synchronization code. 5 | */ 6 | trait FileLike { 7 | def name : String 8 | def exists : Boolean 9 | def isDirectory : Boolean 10 | def parent : FileLike 11 | def children : Seq[FileLike] 12 | // Creates new child of given name under this directory (throws if this is not a directory) 13 | def child(name : String) : FileLike 14 | def mkdirs() : Unit 15 | 16 | def content : InputStream 17 | // This will write a new file if it doesn't exist 18 | def writeContent(otherContent : InputStream) : Unit 19 | } 20 | 21 | object SynchUtil { 22 | 23 | def synchronize[F <: FileLike, 24 | T <: FileLike]( 25 | from : F, 26 | to : T) : Unit = { 27 | 28 | def synchronizeFile(file1 : F, 29 | file2 : T) : Unit = { 30 | file2.writeContent(file1.content) 31 | } 32 | 33 | def synchronizeDirectory(dir1 : F, 34 | dir2 : T) : Unit = { 35 | def findFile(file : FileLike, 36 | directory : FileLike) : Option[FileLike] = 37 | (for { file2 <- directory.children 38 | if file.name == file2.name 39 | } yield file2).headOption 40 | 41 | for(file1 <- dir1.children) { 42 | val file2 = findFile(file1, dir2). 43 | getOrElse(dir2.child(file1.name)) 44 | if(file1.isDirectory) { 45 | file2.mkdirs() 46 | } 47 | synchronize[F,T](file1, file2) 48 | } 49 | } 50 | 51 | if(from.isDirectory) { 52 | synchronizeDirectory(from,to) 53 | } else { 54 | synchronizeFile(from,to) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /chapter4/trait-composition/component-inheritance.scala: -------------------------------------------------------------------------------- 1 | /** Defines a base logging trait that classes can use to log status messages. */ 2 | trait Logger { 3 | def log(category : String, msg : String) : Unit = { 4 | println(msg) 5 | } 6 | } 7 | /** A Logger that will send log messages over a remote socket (not implemented) */ 8 | trait RemoteLogger extends Logger { 9 | //val socket = .. 10 | override def log(category : String, msg : String) : Unit = { 11 | //Send over socket 12 | } 13 | } 14 | 15 | /** A Logger that does nothing. */ 16 | trait NullLogger extends Logger { 17 | override def log(category : String, msg : String) : Unit = {} 18 | } 19 | 20 | /** This trait can be extended by class that use the Logger service. This allows 21 | * those classes to be 'configured' via trait mixins with an appropriate logger at instantiation. 22 | */ 23 | trait HasLogger { 24 | val logger : Logger = new Logger {} 25 | } 26 | 27 | /** 28 | * This is a service for accessing data using query strings. This service 29 | * extends the HasLogger class and can be configured when instantiated. 30 | */ 31 | trait DataAccess extends HasLogger { 32 | 33 | def query[A](in : String) : A = { 34 | logger.log("QUERY", in) 35 | null.asInstanceOf[A] 36 | } 37 | } 38 | 39 | /** This trait can be mixed into to any HasLogger class to give them a remote logger. */ 40 | trait HasRemoteLogger extends HasLogger { 41 | override val logger : Logger = new RemoteLogger {} 42 | } 43 | 44 | /** This trait can be mixed into any HasLogger class to turn off logging. */ 45 | trait HasNullLogger extends HasLogger { 46 | override val logger : Logger = new NullLogger {} 47 | } 48 | 49 | 50 | // Foo is an instance of DataAccess configured with the logger we'd like to use. 51 | object foo extends DataAccess with HasNullLogger {} 52 | 53 | // This is a mechanism of defining a nested service such that pieces are still configurable. 54 | trait HasDataAccess extends HasLogger { 55 | 56 | } 57 | -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/functional/Monad.scala: -------------------------------------------------------------------------------- 1 | package scalax.functional 2 | 3 | /** This class represents the ability to 'flatten' a Functor morphism. That is, 4 | * If we have a functor F[_] applied twice, e.g. List[List[Int]], then this typeclass can reduce it to a single functor application, 5 | * i.e. a List[Int]. 6 | */ 7 | trait Monad[M[_]] { 8 | /** 9 | * This method takes two functor applications and reduces them to a single application. 10 | * 11 | * Essentially this method can take containers nested into containers and remove the outter container. 12 | */ 13 | def flatten[A](m: M[M[A]]): M[A] 14 | /** 15 | * This method is provided because it is often more efficient to directly implement a flatMap method rather than use 16 | * map and flatten. 17 | */ 18 | def flatMap[A,B](m: M[A])(f: A=>M[B])(implicit functor : Functor[M]): M[B] = flatten(functor.map(m)(f)) 19 | } 20 | 21 | object Monad { 22 | implicit object TraversableFunctor extends Monad[Traversable] { 23 | override def flatten[A](m: Traversable[Traversable[A]]): Traversable[A] = m.flatten 24 | override def flatMap[A,B](m: Traversable[A])(f: A=>Traversable[B])(implicit functor : Functor[Traversable]): Traversable[B] = 25 | m flatMap f 26 | } 27 | implicit object OptionFunctor extends Monad[Option] { 28 | override def flatten[A](m: Option[Option[A]]): Option[A] = m flatMap identity 29 | override def flatMap[A,B](m: Option[A])(f: A=>Option[B])(implicit functor : Functor[Option]): Option[B] = 30 | m.flatMap(f) 31 | } 32 | } 33 | 34 | final class MonadOps[M[_], A](val m : M[A], val monad: Monad[M]) { 35 | @inline final def flatMap[B](f: A=>M[B])(implicit functor: Functor[M]): M[B] = monad.flatMap(m)(f) 36 | @inline final def flatten[B](implicit ev : M[A] <:< M[M[B]]): M[B] = monad.flatten(m) 37 | } 38 | 39 | trait MonadImplicits { 40 | implicit def monadOps[M[_], A](value: M[A])(implicit monad: Monad[M]) : MonadOps[M, A] = 41 | new MonadOps[M,A](value, monad) 42 | } -------------------------------------------------------------------------------- /chapter5/wrappers/file-wrapper.scala: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import scala.collection.Traversable 4 | 5 | /** This class wraps a java.io.File with a more powerful scala API. */ 6 | class FileWrapper(val file : java.io.File) { 7 | /** This method is used to compose File paths. Although called /, it will 8 | * do the right thing in windows. 9 | */ 10 | def /(next : String) = new FileWrapper(new java.io.File(file, next)) 11 | 12 | /** 13 | * This method will return a traversable collection that will iterate over the lines in the file. 14 | */ 15 | def lines : Traversable[String] = new Traversable[String] { 16 | override def foreach[U](f : String => U) : Unit = { 17 | import java.io._ 18 | val reader = new BufferedReader(new FileReader(file)) 19 | try { 20 | var line = reader.readLine() 21 | while(line != null) { 22 | f(line) 23 | line = reader.readLine() 24 | } 25 | } finally { 26 | reader.close(); 27 | } 28 | } 29 | } 30 | override def toString = file.getCanonicalPath 31 | } 32 | 33 | /** 34 | * The companion object to FileWrapper that can convert to and from java.io.File and FileWrapper. 35 | */ 36 | object FileWrapper { 37 | implicit def unwrap(w : FileWrapper) = w.file 38 | implicit def wrap(f : java.io.File) = new FileWrapper(f) 39 | } 40 | 41 | /** This object tests the FileWrapper implicit views. */ 42 | object Test { 43 | // This is the only implicit that needs to be improted for two-way conversions between wrapped and 44 | // straight java.io.File. 45 | import FileWrapper.wrap 46 | /** This method takes a java.io.File and prints its lines. We use it to demonstrate implicit views. */ 47 | def withFile(f : java.io.File) : Unit = { 48 | for(line <- f.lines) println(line) 49 | } 50 | 51 | def test() { 52 | val currentDirectory = new java.io.File(".") 53 | // wrapping and unwrapping is happening implicitly here. 54 | withFile( currentDirectory / "tmp.txt" ) 55 | } 56 | } -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/resource/resource.scala: -------------------------------------------------------------------------------- 1 | package scalax.resource 2 | 3 | import scalax.functional.{Applicative,Functor,Monad} 4 | 5 | 6 | trait ManagedResource[T] { 7 | // Note: This operation could fail. 8 | def loan[U](f: T => U): U 9 | } 10 | 11 | object ManagedResource { 12 | def readFile(file: java.io.File) = new ManagedResource[java.io.InputStream] { 13 | def loan[U](f: java.io.InputStream => U): U = { 14 | val stream = new java.io.BufferedInputStream(new java.io.FileInputStream(file)) 15 | try { 16 | f(stream) 17 | } finally { 18 | stream.close() 19 | } 20 | } 21 | } 22 | 23 | def writeFile(file: java.io.File) = new ManagedResource[java.io.OutputStream] { 24 | def loan[U](f: java.io.OutputStream => U): U = { 25 | val stream = new java.io.BufferedOutputStream(new java.io.FileOutputStream(file)) 26 | try { 27 | f(stream) 28 | } finally { 29 | stream.close() 30 | } 31 | } 32 | } 33 | 34 | def make[T <: { def close(): Unit }](t: => T): ManagedResource[T] = 35 | new ManagedResource[T] { 36 | def loan[U](f: T => U): U = { 37 | val resource = t 38 | try { 39 | f(resource) 40 | } finally { 41 | resource.close() 42 | } 43 | } 44 | override def toString = "ManagedResource(...)" 45 | } 46 | 47 | implicit object MRFunctor extends Functor[ManagedResource] { 48 | override def apply[A](a: A) = new ManagedResource[A] { 49 | override def loan[U](f: A => U) = f(a) 50 | override def toString = "ManagedResource("+a+")" 51 | } 52 | override def map[A,B](ma: ManagedResource[A])(mapping: A => B) = new ManagedResource[B] { 53 | override def loan[U](f: B => U) = ma.loan(mapping andThen f) 54 | override def toString = "ManagedResource.map("+ma+")("+mapping+")" 55 | } 56 | } 57 | implicit object MRMonad extends Monad[ManagedResource] { 58 | override def flatten[A](mma: ManagedResource[ManagedResource[A]]): ManagedResource[A] = 59 | new ManagedResource[A] { 60 | override def loan[U](f: A => U): U = mma.loan(ma => ma.loan(f)) 61 | override def toString = "ManagedResource.flatten("+mma+")" 62 | } 63 | } 64 | implicit object MRApplicative extends Applicative[ManagedResource] { 65 | override def lift2[A,B](func: ManagedResource[A=>B])(ma: ManagedResource[A]): ManagedResource[B] = 66 | new ManagedResource[B] { 67 | override def loan[U](f: B => U): U = func.loan(n => ma.loan(n andThen f)) 68 | override def toString = "ManagedResource.lift2("+func+")("+ma+")" 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /chapter6/dependent-types/callbacks.scala: -------------------------------------------------------------------------------- 1 | 2 | trait Observable { 3 | type Handle 4 | 5 | protected var callbacks = Map[Handle, this.type => Unit]() 6 | 7 | def observe(callback : this.type => Unit) : Handle = { 8 | val handle = createHandle(callback) 9 | callbacks += (handle -> callback) 10 | handle 11 | } 12 | 13 | def unobserve(handle : Handle) : Unit = { 14 | callbacks -= handle 15 | } 16 | 17 | protected def notifyListeners() : Unit = 18 | for(callback <- callbacks.values) callback(this) 19 | 20 | /** 21 | * Subclasses override this to provide their own callback disambiguation scheme. 22 | */ 23 | protected def createHandle(callback : this.type => Unit) : Handle 24 | } 25 | 26 | trait DefaultHandles extends Observable { 27 | type Handle = (this.type => Unit) 28 | protected def createHandle(callback : this.type => Unit) : Handle = callback 29 | } 30 | 31 | 32 | 33 | class VariableStore[X](private var value : X) extends Observable with DefaultHandles { 34 | def get : X = value 35 | def set(newValue : X) : Unit = { 36 | value = newValue 37 | notifyListeners() 38 | } 39 | 40 | override def toString : String = "VariableStore(" + value + ")" 41 | } 42 | 43 | /** 44 | Welcome to Scala version 2.8.0.RC3 (OpenJDK 64-Bit Server VM, Java 1.6.0_18). 45 | Type in expressions to have them evaluated. 46 | Type :help for more information. 47 | 48 | scala> val x = new VariableStore(5) 49 | x: VariableStore[Int] = VariableStore(5) 50 | 51 | scala> val handle = x.observe(println) 52 | handle: (x.type) => Unit = 53 | 54 | scala> x.set(2) 55 | VariableStore(2) 56 | 57 | scala> x.unobserve(handle) 58 | 59 | scala> x.set(4) 60 | 61 | */ 62 | 63 | 64 | /** 65 | * Type difference != runtime difference. 66 | 67 | scala> val x = new VariableStore(5) 68 | x: VariableStore[Int] = VariableStore(5) 69 | 70 | scala> val y = new VariableStore(2) 71 | y: VariableStore[Int] = VariableStore(2) ^ 72 | 73 | scala> val callback = println(_ : Any) 74 | callback: (Any) => Unit = 75 | 76 | scala> val handle1 = x.observe(callback) 77 | handle1: (x.type) => Unit = 78 | 79 | scala> val handle2 = y.observe(callback) 80 | handle2: (y.type) => Unit = 81 | 82 | scala> y.set(3) 83 | VariableStore(3) 84 | 85 | scala> x.set(5) 86 | VariableStore(5) 87 | 88 | scala> y.unobserve(handle1) 89 | :10: error: type mismatch; 90 | found : (x.type) => Unit 91 | required: (y.type) => Unit 92 | y.unobserve(handle1) 93 | ^ 94 | 95 | scala> handle 96 | 97 | handle1 handle2 98 | 99 | scala> handle1 == handle2 100 | res3: Boolean = true 101 | 102 | */ 103 | -------------------------------------------------------------------------------- /chapter9/src/main/scala/main.scala: -------------------------------------------------------------------------------- 1 | package scattergather 2 | 3 | import akka.actor.{Supervisor, Actor, ActorRef} 4 | import akka.config.Supervision._ 5 | import akka.dispatch.Dispatchers 6 | import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy 7 | 8 | object AdaptiveSearchTreeMain { 9 | def submitInitialDocuments(searchNode: ActorRef) = 10 | Seq("Some example data for you", 11 | "Some more example data for you to use", 12 | "To be or not to be, that is the question", 13 | "OMG it's a cat", 14 | "This is an example. It's a great one", 15 | "HAI there", 16 | "HAI IZ HUNGRY", 17 | "Hello, World", 18 | "Hello, and welcome to the search node 8", 19 | "The lazy brown fox jumped over the", 20 | "Winning is the best because it's winning." 21 | ) foreach (doc => searchNode ! SearchableDocument(doc)) 22 | def makeTree = { 23 | val supervisor = Supervisor(SupervisorConfig(AllForOneStrategy(List(classOf[Exception]), 3, 1000), Nil)) 24 | val searchnodedispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("adaptive search tree") 25 | .withNewThreadPoolWithLinkedBlockingQueueWithCapacity(100) 26 | .setCorePoolSize(10) 27 | .setMaxPoolSize(128) 28 | .setKeepAliveTimeInMillis(60000) 29 | .setRejectionPolicy(new CallerRunsPolicy) 30 | .build 31 | val searchTree = Actor.actorOf(new AdaptiveSearchNode { 32 | self.dispatcher = searchnodedispatcher 33 | }) 34 | supervisor link searchTree 35 | searchTree.start() 36 | submitInitialDocuments(searchTree) 37 | searchTree 38 | } 39 | } 40 | 41 | object SearchTreeMain { 42 | def create(name: String) = { 43 | val supervisor = Supervisor(SupervisorConfig(AllForOneStrategy(List(classOf[Exception]), 3, 1000), Nil)) 44 | val searchnodedispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("search tree [" + name + "]") 45 | .withNewThreadPoolWithLinkedBlockingQueueWithCapacity(100) 46 | .setCorePoolSize(10) 47 | .setMaxPoolSize(128) 48 | .setKeepAliveTimeInMillis(60000) 49 | .setRejectionPolicy(new CallerRunsPolicy) 50 | .build 51 | val leafNodes = (1 to 10).map(i => Actor.actorOf(new SearchNode(i) { 52 | self.dispatcher = searchnodedispatcher 53 | })) 54 | leafNodes foreach supervisor.link 55 | leafNodes foreach (_.start()) 56 | val headNode = Actor.actorOf(new HeadNode { 57 | override val nodes = leafNodes 58 | self.dispatcher = searchnodedispatcher 59 | }) 60 | supervisor link headNode 61 | headNode.start() 62 | headNode 63 | } 64 | 65 | def makeResponder = { 66 | val tmp = Actor.actorOf(new Actor { 67 | def receive = { 68 | case x => println(x) 69 | } 70 | }) 71 | tmp.start() 72 | tmp 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /chapter4/trait-composition/named-default-class.scala: -------------------------------------------------------------------------------- 1 | trait Logger { 2 | def log(category : String, msg : String) : Unit = { 3 | println(msg) 4 | } 5 | } 6 | 7 | class DataAccess(val logger : Logger = new Logger {}) { 8 | 9 | def query[A](in : String) : A = { 10 | logger.log("QUERY", in) 11 | null.asInstanceOf[A] 12 | } 13 | } 14 | 15 | 16 | class DoubleDataAccess(logger : Logger = DataAccess.`init$default$1`) extends DataAccess(logger) {} 17 | 18 | /** 19 | scala> val x = new DataAccess 20 | x: DataAccess = DataAccess@15837e8 21 | 22 | scala> x.query("HAI") 23 | HAI 24 | java.lang.NullPointerException 25 | at RequestResult$.(:9) 26 | at RequestResult$.() 27 | at RequestResult$scala_repl_result() 28 | at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 29 | at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 30 | at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 31 | at java.lang.reflect.Method.invoke(Method.java:616) 32 | at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$13.apply(Interpreter.scala:827) 33 | at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$13.apply(Interpreter.scala:827) 34 | at scala.util.control.Exception$Catch.apply(Exception.scala:79) 35 | at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1.apply(Interpreter.scala:826) 36 | at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1.apply(Interpreter.scala:826) 37 | at scala.util.control.Exception$Catch.apply(Exception.scala:79) 38 | at scala.tools.nsc.Interpreter$Request.loadAndRun(Interpreter.scala:825) 39 | at scala.tools.nsc.Interpreter.interpret(Interpreter.scala:467) 40 | at scala.tools.nsc.Interpreter.interpret(Interpreter.scala:457) 41 | at scala.tools.nsc.InterpreterLoop.interpretStartingWith(InterpreterLoop.scala:391) 42 | at scala.tools.nsc.InterpreterLoop.command(InterpreterLoop.scala:367) 43 | at scala.tools.nsc.InterpreterLoop.processLine$1(InterpreterLoop.scala:249) 44 | at scala.tools.nsc.InterpreterLoop.repl(InterpreterLoop.scala:267) 45 | at scala.tools.nsc.InterpreterLoop.main(InterpreterLoop.scala:439) 46 | at scala.tools.nsc.MainGenericRunner$.createLoop$1(MainGenericRunner.scala:118) 47 | at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:143) 48 | at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala) 49 | 50 | scala> val x = new DataAccess(logger = new Logger { def log(c : String, q : String) = println(c) }) 51 | :6: error: overriding method log in trait Logger of type (category: String,msg: String)Unit; 52 | method log needs `override' modifier 53 | val x = new DataAccess(logger = new Logger { def log(c : String, q : String) = println(c) }) 54 | ^ 55 | 56 | scala> val x = new DataAccess(logger = new Logger { override def log(c : String, q : String) = println(c) }) 57 | x: DataAccess = DataAccess@1fc6eed 58 | 59 | scala> x.query[AnyRef]("HAI") 60 | QUERY 61 | res1: AnyRef = null 62 | **/ 63 | 64 | -------------------------------------------------------------------------------- /chapter9/src/main/scala/AdaptiveScatterGather.scala: -------------------------------------------------------------------------------- 1 | package scattergather 2 | 3 | import collection.immutable.HashMap 4 | import akka.actor.{ReceiveTimeout, ActorRef, Actor} 5 | 6 | /** 7 | * A message representing a document to add to the search tree. 8 | */ 9 | case class SearchableDocument(content: String) 10 | 11 | trait BaseHeadNode { self: AdaptiveSearchNode => 12 | var children = IndexedSeq[ActorRef]() 13 | var currentIdx = 0 14 | def parentNode: PartialFunction[Any, Unit] = { 15 | case SearchQuery(q, max, responder) => 16 | // TODO - use gatherer scheudler 17 | val gatherer = Actor.actorOf(new GathererNode { 18 | val maxDocs = max 19 | val maxResponses = children.size 20 | val query = q 21 | val client = responder 22 | }) 23 | gatherer.start 24 | for (node <- children) { 25 | node ! SearchQuery(q, max, gatherer) 26 | } 27 | case s @ SearchableDocument(_) => getNextChild ! s 28 | } 29 | 30 | // Round Robin 31 | private def getNextChild = { 32 | currentIdx = (1 + currentIdx) % children.size 33 | children(currentIdx) 34 | } 35 | 36 | } 37 | 38 | trait BaseChildNode { self: AdaptiveSearchNode => 39 | final val maxNoOfDocuments = 10 40 | var documents: Vector[String] = Vector() 41 | var index: HashMap[String, Seq[(Double, String)]] = HashMap() 42 | 43 | def leafNode: PartialFunction[Any, Unit] = { 44 | case SearchQuery(query, maxDocs, handler) => executeLocalQuery(query, maxDocs, handler) 45 | case SearchableDocument(content) => addDocumentToLocalIndex(content) 46 | } 47 | private def executeLocalQuery(query: String, maxDocs: Int, handler: ActorRef) = { 48 | val result = for { 49 | results <- index.get(query).toList 50 | resultList <- results 51 | } yield resultList 52 | handler ! QueryResponse(result take maxDocs) 53 | } 54 | 55 | private def addDocumentToLocalIndex(content: String) = { 56 | for( (key,value) <- content.split("\\s+").groupBy(identity)) { 57 | val list = index.get(key) getOrElse Seq() 58 | index += ((key, ((value.length.toDouble, content)) +: list)) 59 | } 60 | documents = documents :+ content 61 | // Split on size.... 62 | if (documents.size > maxNoOfDocuments) split() 63 | } 64 | 65 | /** Abstract method to split this actor. */ 66 | protected def split(): Unit 67 | 68 | protected def clearIndex(): Unit = { 69 | documents = Vector() 70 | index = HashMap() 71 | } 72 | } 73 | 74 | 75 | class AdaptiveSearchNode extends Actor with BaseHeadNode with BaseChildNode { 76 | def receive = leafNode 77 | 78 | /** Splits this search node into a tree of search nodes if there are too many documents. */ 79 | protected def split(): Unit = { 80 | children = (for(docs <- documents grouped 5) yield { 81 | // TODO - use search scheduler + hook up to supervisor... 82 | val child = Actor.actorOf[AdaptiveSearchNode] 83 | child.start() 84 | docs foreach (child ! SearchableDocument(_)) 85 | child 86 | }).toIndexedSeq 87 | clearIndex() 88 | this become parentNode 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /chapter2/equals/PolymorphicEquals.scala: -------------------------------------------------------------------------------- 1 | 2 | trait InstantaneousTime { 3 | val repr : Int 4 | override def equals(other : Any) : Boolean = other match { 5 | case that : InstantaneousTime => 6 | if(this eq that) { 7 | true 8 | } else { 9 | (that.## == this.##) && 10 | (repr == that.repr) 11 | } 12 | case _ => false 13 | } 14 | override def hashCode() : Int = repr.hashCode 15 | } 16 | 17 | trait Event extends InstantaneousTime { 18 | val name : String 19 | override def equals(other : Any) : Boolean = other match { 20 | case that : Event => 21 | if(this eq that) { 22 | true 23 | } else { 24 | (repr == that.repr) && 25 | (name == that.name) 26 | } 27 | case _ => false 28 | } 29 | } 30 | 31 | 32 | trait InstantaneousTime extends Equals { 33 | val repr : Int 34 | override def canEqual(other : Any) = other.isInstanceOf[InstantaneousTime] 35 | override def equals(other : Any) : Boolean = other match { 36 | case that : InstantaneousTime => 37 | if(this eq that) true else { 38 | (that.## == this.##) && 39 | (that canEqual this) && 40 | (repr == that.repr) 41 | } 42 | case _ => false 43 | } 44 | override def hashCode() : Int = repr.hashCode 45 | } 46 | 47 | trait Event extends InstantaneousTime { 48 | val name : String 49 | override def canEqual(other : Any) = other.isInstanceOf[Event] 50 | override def equals(other : Any) : Boolean = other match { 51 | case that : Event => 52 | if(this eq that) { 53 | true 54 | } else { 55 | (that canEqual this) && 56 | (repr == that.repr) && 57 | (name == that.name) 58 | } 59 | case _ => false 60 | } 61 | } 62 | 63 | 64 | object InstantaneousTime { 65 | def apply(secondsGMT : Int) = new InstantaneousTime { 66 | override val repr = secondsGMT 67 | } 68 | } 69 | 70 | /* 71 | class TimeSeriesRange(start : Time, end : Time) extends Equals { 72 | def hashCode() : Int = start.## + ((27+end.##) * 13) 73 | def equals(other : Any) : Boolean = other match { 74 | case that : TimeSeriesRange => 75 | // Check simple equals first 76 | if(that eq this) { 77 | true 78 | } else if ( (that.## != this.##) && // If hashCode is quicker than deep check 79 | // , we can check differences for quick failure 80 | (that canEqual this) ){ // Make sure equivalence holds true! -> Allows subclasses to "opt-out" of equality! 81 | // Our implementation 82 | (start == that.start) && (stop == that.stop) 83 | } else false 84 | case _ => false 85 | } 86 | 87 | def canEqual(other : Any) : Boolean = other.isInstanceOf[TimeSeriesRange] 88 | } 89 | 90 | object Day { 91 | def startOfDay(day : Time) : Time = day 92 | def endOfDay(day : Time) : Time = day 93 | } 94 | 95 | class DayRange(day : Time) extends TimeSeriesRange(Day.startOfDay(day),Day.endOfDay(day)) { 96 | override def canEqual(other : Any) : Boolean = other.isInstanceof[DayRange] 97 | // We don't have to override equals, although 98 | } 99 | 100 | */ 101 | 102 | 103 | -------------------------------------------------------------------------------- /chapter9/src/main/scala/ScatterGather.scala: -------------------------------------------------------------------------------- 1 | package scattergather 2 | 3 | import collection.immutable.HashMap 4 | import akka.actor.{ReceiveTimeout, ActorRef, Actor} 5 | 6 | /** Defines a SearchNode that contains a fragment of the search index */ 7 | class SearchNode(id : Int) extends Actor { 8 | // TODO - index init 9 | lazy val index : HashMap[String, Seq[(Double, String)]] = { 10 | def makeIndex(docs : String*) = { 11 | var tmp = HashMap[String, Seq[(Double, String)]]() 12 | for( doc <- docs; (key,value) <- doc.split("\\s+").groupBy(identity)) { 13 | val list = tmp.get(key) getOrElse Seq() 14 | tmp += ((key, ((value.length.toDouble, doc)) +: list)) 15 | } 16 | tmp 17 | } 18 | id match { 19 | case 1 => makeIndex("Some example data for you") 20 | case 2 => makeIndex("Some more example data for you to use") 21 | case 3 => makeIndex("To be or not to be, that is the question") 22 | case 4 => makeIndex("OMG it's a cat") 23 | case 5 => makeIndex("This is an example. It's a great one") 24 | case 6 => makeIndex("HAI there", "HAI IZ HUNGRY") 25 | case 7 => makeIndex("Hello, World") 26 | case 8 => makeIndex("Hello, and welcome to the search node 8") 27 | case 9 => makeIndex("The lazy brown fox jumped over the") 28 | case 10 => makeIndex("Winning is the best because it's winning.") 29 | } 30 | } 31 | def receive = { 32 | case SearchQuery(query, maxDocs, handler) => 33 | val result = for { 34 | results <- index.get(query).toList 35 | resultList <- results 36 | } yield resultList 37 | handler ! QueryResponse(result.take(maxDocs)) 38 | } 39 | } 40 | 41 | /** The head node for the search tree. Note: The tree can be multiple levels deep, with head nodes 42 | * pointing to other head nodes. 43 | */ 44 | class HeadNode extends Actor { 45 | // TODO - Init search nodes 46 | def nodes : Seq[ActorRef] = Seq() 47 | def receive = { 48 | case SearchQuery(q, max, responder) => 49 | val gatherer = Actor.actorOf(new GathererNode { 50 | val maxDocs = max 51 | val maxResponses = nodes.size 52 | val query = q 53 | val client = responder 54 | }) 55 | gatherer.start 56 | for (node <- nodes) { 57 | node ! SearchQuery(q, max, gatherer) 58 | } 59 | } 60 | } 61 | /** An actor which receives distributed results and aggregates/responds to the original query. */ 62 | trait GathererNode extends Actor { 63 | val maxDocs : Int 64 | val query : String 65 | val maxResponses : Int 66 | val client : ActorRef 67 | self.receiveTimeout = Some(1000L) 68 | /** Stores the current set of results */ 69 | var results = Seq[(Double, String)]() 70 | var responseCount = 0 71 | /** Combines the current reuslts with the next set of search results. */ 72 | private def combineResults(current : Seq[(Double, String)], next : Seq[(Double, String)]) = 73 | (current ++ next).view.sortBy(_._1).take(maxDocs).force 74 | 75 | def receive = { 76 | case QueryResponse(next) => 77 | results = combineResults(results, next) 78 | responseCount += 1 79 | if(responseCount == maxResponses) { 80 | client ! QueryResponse(results) 81 | self.stop() 82 | } 83 | () 84 | case ReceiveTimeout => 85 | client ! QueryResponse(Seq()) 86 | self.stop() 87 | } 88 | } -------------------------------------------------------------------------------- /chapter7/type-class/tyoeclass2.scala: -------------------------------------------------------------------------------- 1 | import java.io.{File, FileInputStream,FileOutputStream,BufferedInputStream,BufferedOutputStream,InputStream} 2 | 3 | /** 4 | * Defines an interface for things that are like files for our synchronization code. 5 | */ 6 | trait FileLike[T] { 7 | def name(file : T) : String 8 | def isDirectory(file : T) : Boolean 9 | def children(directory : T) : Seq[T] 10 | // Creates new child of given name under this directory (throws if this is not a directory) 11 | def child(parent : T, name : String) : T 12 | def mkdirs(file : T) : Unit 13 | 14 | def content(file : T) : InputStream 15 | // This will write a new file if it doesn't exist 16 | def writeContent(file : T, otherContent : InputStream) : Unit 17 | } 18 | 19 | object FileLike { 20 | 21 | implicit val ioFileLike = new FileLike[File] { 22 | override def name(file : File) = file.getName() 23 | override def isDirectory(file : File) = file.isDirectory() 24 | override def parent(file : File) = file.getParentFile() 25 | override def children(directory : File) = directory.listFiles() //TODO - Lift null 26 | override def child(parent : File, name : String) = new java.io.File(parent, name) 27 | override def mkdirs(file : File) : Unit = file.mkdirs() 28 | override def content(file : File) = new FileInputStream(file) 29 | override def writeContent(file : File, otherContent : InputStream) = { 30 | // TODO - Auto close input stream? yes... 31 | val bufferedOutput = new java.io.BufferedOutputStream(new java.io.FileOutputStream(file)) 32 | try { 33 | val bufferedInput = new java.io.BufferedInputStream(otherContent) 34 | val buffer = new Array[Byte](512) 35 | var ready : Int = 0 36 | ready = bufferedInput.read(buffer) 37 | while(ready != -1) { 38 | if(ready > 0) { 39 | bufferedOutput.write(buffer, 0, ready) 40 | } 41 | ready = bufferedInput.read(buffer) 42 | } 43 | } finally { 44 | otherContent.close() 45 | bufferedOutput.close() 46 | } 47 | } 48 | } 49 | } 50 | 51 | // Utility to synchronize files 52 | object SynchUtil { 53 | 54 | def synchronize[F : FileLike, T : FileLike](from : F, to : T) : Unit = { 55 | val fromHelper = implicitly[FileLike[F]] 56 | val toHelper = implicitly[FileLike[T]] 57 | 58 | 59 | /** Synchronizes two files */ 60 | def synchronizeFile(file1 : F, file2 : T) : Unit = { 61 | Console.println("Writing [" + fromHelper.name(file1) + "] to [" + toHelper.name(file2) + "]") 62 | toHelper.writeContent(file2, fromHelper.content(file1)) 63 | } 64 | 65 | def synchronizeDirectory(dir1 : F, dir2 : T) : Unit = { 66 | def findFile(file : F, directory : T) : Option[T] = 67 | (for { file2 <- toHelper.children(directory) 68 | if fromHelper.name(file) == toHelper.name(file2) 69 | } yield file2).headOption 70 | // Iterate over all files in this directory and sync 71 | for(file1 <- fromHelper.children(dir1)) { 72 | val file2 = findFile(file1, dir2). 73 | getOrElse(toHelper.child(dir2, fromHelper.name(file1))) 74 | if(fromHelper.isDirectory(file1)) { 75 | toHelper.mkdirs(file2) // Ensure Directory for sync 76 | Console.println("Syncing [" + fromHelper.name(file1) + "] to [" + toHelper.name(file2) + "]") 77 | } 78 | synchronize(file1, file2) 79 | } 80 | } 81 | 82 | if(fromHelper.isDirectory(from)) { 83 | synchronizeDirectory(from,to) 84 | } else { 85 | synchronizeFile(from,to) 86 | } 87 | } 88 | 89 | 90 | } -------------------------------------------------------------------------------- /chapter2/immutability/MapConcurrencyTest.scala: -------------------------------------------------------------------------------- 1 | package sperformance 2 | 3 | import collection.immutable.{HashMap=>ImmutableHashMap} 4 | import collection.mutable.{HashMap=>MutableHashMap} 5 | import java.util.concurrent.{ExecutorService,Executors} 6 | import annotation.tailrec 7 | 8 | // Abstract type for memoizing function values. 9 | trait Service[Key,Value] { 10 | def lookUp(k : Key) : Option[Value] 11 | def insert(k : Key, v : Value) : Unit 12 | } 13 | 14 | 15 | class ImmutableService[Key, Value] extends Service[Key, Value] { 16 | var currentIndex = new ImmutableHashMap[Key,Value] 17 | def lookUp(k : Key) : Option[Value] = currentIndex.get(k) 18 | def insert(k : Key, v: Value) : Unit = synchronized { 19 | currentIndex = currentIndex + ((k, v)) 20 | } 21 | } 22 | 23 | 24 | class MutableService[Key, Value] extends Service[Key, Value] { 25 | val currentIndex = new MutableHashMap[Key, Value] 26 | def lookUp(k : Key) : Option[Value] = synchronized(currentIndex.get(k)) 27 | def insert(k : Key, v : Value) : Unit = synchronized { 28 | currentIndex.put(k,v) 29 | } 30 | } 31 | 32 | 33 | object TestLibs { 34 | var executor = Executors.newFixedThreadPool(2) 35 | 36 | implicit def functionToCallable[A](f : () => A) = new Runnable { 37 | override def run() { 38 | f() 39 | } 40 | } 41 | 42 | def runTest(r : Stream[Runnable]) { 43 | 44 | } 45 | 46 | class ListHolder { 47 | var list = List[Boolean]() 48 | 49 | def addValue(x : Boolean) : Unit = synchronized { 50 | list = x :: list 51 | } 52 | } 53 | 54 | def makeTest(n : Int, service : Service[Int, Int]) : (List[Runnable], ListHolder) = { 55 | var results = new ListHolder() 56 | def makeInsertRunnable(idx : Int) : Runnable = new Runnable { 57 | override def run() { 58 | service.insert(idx,idx) 59 | } 60 | } 61 | def makeReadRunnable(idx : Int) : Runnable = new Runnable { 62 | override def run() { 63 | val result = service.lookUp(idx) 64 | //Thread.sleep(10L) 65 | results.addValue(result.isDefined) 66 | } 67 | } 68 | def makeStream(generateIdx : Int, readIdx : Int, max : Int) : Stream[Runnable] = { 69 | (generateIdx, readIdx, math.random) match { 70 | case (i, j, k) if j > max => 71 | Stream() 72 | case (i, j, k) if i > max => 73 | Stream.cons(makeReadRunnable(j), makeStream(i, j+1, max)) 74 | case (i, j, k) if i == j => 75 | Stream.cons(makeInsertRunnable(i), makeStream(i+1, j, max)) 76 | case (i, j, k) if k > 0.5 => 77 | Stream.cons(makeInsertRunnable(i), makeStream(i+1, j, max)) 78 | case (i, j, k) => 79 | Stream.cons(makeReadRunnable(j), makeStream(i, j+1, max)) 80 | } 81 | } 82 | (makeStream(1,1,n).toList, results) 83 | } 84 | 85 | 86 | } 87 | 88 | import _root_.java.util.concurrent._ 89 | 90 | object MapConcurrencyTest extends sperformance.dsl.PerformanceDSLTest { 91 | 92 | performance of "ImmutableService" in { 93 | measure method "index-lookup" in { 94 | val x = Executors.newFixedThreadPool(2) 95 | withSize upTo 50 withSetup { 96 | size => 97 | TestLibs.makeTest(size, new ImmutableService) 98 | } run { 99 | case (runnables, results) => 100 | // Ensure we wait until all runnables are done 101 | runnables.map(x.submit(_, true)).foreach(_.get) 102 | } 103 | } 104 | } 105 | performance of "MutableService" in { 106 | measure method "index-lookup" in { 107 | val x = Executors.newFixedThreadPool(2) 108 | withSize upTo 50 withSetup { 109 | size => 110 | TestLibs.makeTest(size, new MutableService) 111 | } run { 112 | case (runnables, results) => 113 | // Ensure we wait until all runnables are done 114 | runnables.map(x.submit(_, true)).foreach(_.get) 115 | } 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /chapter5/implicitscope/library.scala: -------------------------------------------------------------------------------- 1 | package library 2 | 3 | import java.util.concurrent.{Callable, Executors} 4 | import collection.mutable.ArrayBuffer 5 | 6 | /** This class defines an interface for how to execute functions. */ 7 | trait ThreadStrategy { 8 | // pass in a function that returns a value and receive a function 9 | // that returns the value. The actual function may be executed on another thread. 10 | def execute[A](func : Function0[A]) : Function0[A] 11 | } 12 | 13 | /** This class stores a dense two-dimensional matrix of finite size. */ 14 | class Matrix(private val repr : Array[Array[Double]]) { 15 | /** Access the row at idx (0-based). Returns a column-ordered Seq of the values in the row. */ 16 | def row(idx : Int) : Seq[Double] = { 17 | repr(idx) 18 | } 19 | /** Access the column at idx (0-based). Returns a row-ordered Seq of the values in the column. */ 20 | def col(idx : Int) : Seq[Double] = { 21 | repr.foldLeft(ArrayBuffer[Double]()) { 22 | (buffer, currentRow) => 23 | buffer.append(currentRow(idx)) 24 | buffer 25 | } toArray 26 | } 27 | /** The number of rows in the matrix. */ 28 | lazy val rowRank = repr.size 29 | /** The number of columns in the matrix. */ 30 | lazy val colRank = if(rowRank > 0) repr(0).size else 0 31 | /** Pretty-prints the matrix */ 32 | override def toString = "Matrix" + repr.foldLeft("") { (msg, row) => msg + row.mkString("\n|", " | ", "|")} 33 | } 34 | 35 | /** This defines a service to multiply two matrices together while swapping out a threading strategy. */ 36 | object MatrixService { 37 | /** This method will multiple two matrices. It takes an implicit parameter that allows you to change the 38 | * threading strategy. 39 | */ 40 | def multiply(a : Matrix, b : Matrix)(implicit threading : ThreadStrategy = ThreadStrategy.SameThreadStrategy) : Matrix = { 41 | // Ensure the columns-rows line up for proper multipication. 42 | assert(a.colRank == b.rowRank) 43 | // Create a buffer we can use to store the results. The size is determined by the row rank in a and 44 | // column rank in b. 45 | val buffer = new Array[Array[Double]](a.rowRank) 46 | for ( i <- 0 until a.rowRank ) { 47 | buffer(i) = new Array[Double](b.colRank) 48 | } 49 | // This helper function will compute the value stored at index (row,col) in the resulting matrix and place 50 | // that value in the buffer. 51 | def computeValue(row : Int, col : Int) : Unit = { 52 | // Constructs a List of pairs of elements from the two matricies. 53 | val pairwiseElements = 54 | a.row(row).zip(b.col(col)) 55 | // multiplies every row value by every column value. The sum of products is the resulting value on the matrix. 56 | val products = 57 | for((x,y) <- pairwiseElements) 58 | yield x*y 59 | val result = products.sum 60 | buffer(row)(col) = result 61 | } 62 | // Create a list of computations for every (row,col) result of the matrix. 63 | val computations = for { 64 | i <- 0 until a.rowRank 65 | j <- 0 until b.colRank 66 | } yield threading.execute { () => computeValue(i,j) } 67 | // Execute all computations *or* wait for threading to finish. 68 | computations.foreach(_()) 69 | new Matrix(buffer) 70 | } 71 | } 72 | 73 | /** This is the companion object of the ThreadStrategy trait. 74 | * This defines various thread pool strategies that one can uses. */ 75 | object ThreadStrategy { 76 | /** This is a ThreadStrategy that will execute all functions on the local thread. */ 77 | object SameThreadStrategy extends ThreadStrategy { 78 | def execute[A](func : Function0[A]) = func 79 | } 80 | 81 | /** This is a strategy that will execute all functions within a thread pool. */ 82 | object ThreadPoolStrategy extends ThreadStrategy { 83 | val pool = Executors.newFixedThreadPool(java.lang.Runtime.getRuntime.availableProcessors) 84 | def execute[A](func : Function0[A] ) = { 85 | // Submit a callable class to the thread bool. 86 | val future = pool.submit(new Callable[A] { 87 | def call() : A = { 88 | Console.println("Executing function on thread: " + Thread.currentThread.getName) 89 | func() 90 | } 91 | }) 92 | // Create a function that will block when called and wait for the defered thread to finish execution. 93 | () => future.get() 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /chapter6/existential-types/existential.scala: -------------------------------------------------------------------------------- 1 | /** Defines a trait that marks a class as allowing external 2 | * viewers to be notified of changes. 3 | */ 4 | trait Observable { 5 | // Defines a type returned when registering a callback. 6 | type Handle <: { 7 | def remove() : Unit 8 | } 9 | /** registered callbacks for this observable */ 10 | protected var callbacks = Map[Handle, this.type => Unit]() 11 | 12 | /** Registers a new observer on this class. 13 | * Observers are simple functions that take the class and 14 | * return nothing. A handle is returned that allows 15 | * the observer to deregister from this observable. 16 | */ 17 | def observe(callback : this.type => Unit) : Handle = { 18 | val handle = createHandle(callback) 19 | callbacks += (handle -> callback) 20 | handle 21 | } 22 | /** Removes an observer from this class. */ 23 | def unobserve(handle : Handle) : Unit = { 24 | callbacks -= handle 25 | } 26 | /** This method is called by subclasses upon state change to 27 | * notify listeners of the change. 28 | */ 29 | protected def notifyListeners() : Unit = 30 | for(callback <- callbacks.values) callback(this) 31 | 32 | /** 33 | * Subclasses override this to provide their own callback disambiguation scheme. 34 | */ 35 | protected def createHandle(callback : this.type => Unit) : Handle 36 | } 37 | 38 | /** This trait provides a default implementation 39 | * for the handlers type. */ 40 | trait DefaultHandles extends Observable { 41 | /** A simple handle implementation */ 42 | class HandleClass { 43 | def remove() { 44 | DefaultHandles.this.unobserve(this) 45 | } 46 | } 47 | type Handle = HandleClass 48 | /** Every callback is assigned a new handle. */ 49 | protected def createHandle(callback : this.type => Unit) : Handle = new HandleClass 50 | } 51 | 52 | 53 | /** This defines a basic store or cache of a single value type. 54 | * This store is observable and will notify listeners when the stored 55 | * value is changed. 56 | */ 57 | class VariableStore[X](private var value : X) extends Observable with DefaultHandles { 58 | /** Retreive the stored value */ 59 | def get : X = value 60 | /** Sets the stored value. Will notify observers */ 61 | def set(newValue : X) : Unit = { 62 | value = newValue 63 | notifyListeners() 64 | } 65 | // Overridden for pretty REPL usage. 66 | override def toString : String = "VariableStore(" + value + ")" 67 | } 68 | 69 | /** This trait defines a mechanism for managing handles from 70 | * observerables such that they can all be unregistered when 71 | * the current class is 'finished' 72 | */ 73 | trait Dependencies { 74 | // This type allows us to refer to any handle from any 75 | // observable. Because handle is defined inside the Observable 76 | // we use an existential for the actual Observable. 77 | type Ref = x.Handle forSome { val x: Observable } 78 | /** The current registered observers. */ 79 | private var handles = List[Ref]() 80 | /** Adds a new handle to manage */ 81 | protected def addHandle(handle : Ref) : Unit = { 82 | handles :+= handle 83 | } 84 | /** Removes all observers using the registrered handles */ 85 | protected def removeDependencies() { 86 | for(h <- handles) h.remove() 87 | handles = List() 88 | } 89 | /** This method mimics Observable.observe except that it registers 90 | * an observer *and* adds it to the dependency list. 91 | */ 92 | protected def observe[T <: Observable](obj : T)(handler : T => Unit) : Ref = { 93 | val ref = obj.observe(handler) 94 | addHandle(ref) 95 | ref 96 | } 97 | } 98 | 99 | 100 | /* 101 | 102 | scala> val x = new VariableStore(12) 103 | x: VariableStore[Int] = VariableStore(12) 104 | 105 | scala> val d = new Dependencies {} 106 | d: java.lang.Object with Dependencies = $anon$1@153e6f83 107 | 108 | 109 | Note: Scala 2.8.x has a bug that causes the below to fail. 110 | 111 | scala> d.addHandle(x.observe(println)) 112 | :8: error: type mismatch; 113 | found : x.Handle 114 | required: d.Ref 115 | d.addHandle(x.observe(println)) 116 | ^ 117 | // The following does work. 118 | 119 | scala> val t = x.observe(println) 120 | t: x.Handle = DefaultHandles$HandleClass@662fe032 121 | 122 | scala> d.addHandle(t) 123 | 124 | scala> val t2 = x.observe(println) 125 | t2: x.Handle = DefaultHandles$HandleClass@57530551 126 | 127 | scala> d.addHandle(t2) 128 | 129 | scala> x.set(1) 130 | VariableStore(1) 131 | VariableStore(1) 132 | 133 | scala> d.removeDependencies() 134 | 135 | scala> x.set(2) 136 | 137 | */ 138 | -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/config/Config.scala: -------------------------------------------------------------------------------- 1 | package scalax.config 2 | 3 | import java.sql.DriverManager 4 | import util.control.Exception.catching 5 | import com.github.jsuereth.applicative 6 | 7 | import scalax.functional.{Functor,Monad,Applicative} 8 | import scalax.functional.Implicits._ 9 | 10 | /**Represents something that is read from the 'environment' before usage. 11 | * The 'environment' in question could be one of several locations. 12 | * 13 | */ 14 | trait Config[+A] { self => 15 | def get : Option[A] 16 | def flattenOpt[B](implicit ev: Option[A] <:< Option[Option[B]]): Config[B] = new OptionFlattenConfig(this) 17 | def orElse[B >: A](b : Config[B]) : Config[B] = new Combiner(this, b) 18 | } 19 | 20 | // a 'file' environment monad that attempts to minimize reads to the file based 21 | // on the file timestamp. 22 | final class FileReaderConfig[A](file : java.io.File, reader : java.io.File => A) extends Config[A] { 23 | // TODO - Thread safety... 24 | private var cache = Option.empty[A] 25 | private var timestamp = Option.empty[Long] 26 | def get : Option[A] = 27 | (for { 28 | time <- timestamp 29 | if time == file.lastModified 30 | value <- cache 31 | } yield value) orElse { 32 | cache = (catching[A](classOf[java.io.IOException]) opt reader(file)) 33 | timestamp = Some(file.lastModified) 34 | cache 35 | } 36 | } 37 | 38 | object Config { 39 | /* Functor implementation. */ 40 | implicit object ConfigFunctor extends Functor[Config] { 41 | override def apply[A](x: A) = Config(x) 42 | override def map[A,B](x: Config[A])(f: A=>B) = new MappedConfig(x, f) 43 | } 44 | implicit object ConfigApplicative extends Applicative[Config] { 45 | override def lift2[A,B](f: Config[A => B])(ma: Config[A]): Config[B] = 46 | new FlatMappedConfig(ma, (z: A) => f.map(_(z))) 47 | } 48 | /* Monad implementation */ 49 | implicit object ConfigMonad extends Monad[Config] { 50 | override def flatten[A](m: Config[Config[A]]): Config[A] = 51 | new FlatMappedConfig(m, identity[Config[A]]) 52 | override def flatMap[A,B](m: Config[A])(f: A=>Config[B])(implicit functor : Functor[Config]): Config[B] = 53 | new FlatMappedConfig(m, f) 54 | } 55 | def environment(name : String) : Config[String] = 56 | Config(if (System.getenv.containsKey(name)) 57 | Some(System.getenv.get(name)) 58 | else None).flattenOpt 59 | def systemproperty(name : String) : Config[String] = 60 | Config(Option(System.getProperty(name, null))).flattenOpt 61 | def propertyfile(file : java.io.File) : Config[java.util.Properties] = 62 | new FileReaderConfig(file, { file => 63 | val tmp = new java.util.Properties() 64 | Console.println("Loading file: " + file) 65 | tmp.load(new java.io.FileReader(file)) 66 | tmp 67 | }) 68 | def apply[A](a : => A): Config[A] = new Config[A] { def get : Option[A] = Some(a) } 69 | } 70 | // Implementation detail of the Config monad when it's mapped. We need 71 | // to collect and defer the operation. 72 | final class MappedConfig[O,A](val orig : Config[O], f : O => A) extends Config[A] { 73 | override def get = orig.get map f 74 | } 75 | // Implementation detail for flatmapped configuration. 76 | final class FlatMappedConfig[O,A](val orig : Config[O], f : O => Config[A]) extends Config[A] { 77 | override def get = orig.get flatMap (a => f(a).get) 78 | } 79 | 80 | // This combines two config objects 81 | final class Combiner[A](config : Config[A], config2 : Config[A]) extends Config[A] { 82 | def get: Option[A] = config.get orElse config2.get 83 | } 84 | 85 | final class OptionFlattenConfig[A,B](config: Config[A])(implicit ev: Option[A]<: 99 | if (value.containsKey(name)) 100 | Some(value.getProperty(name)) 101 | else None 102 | } flattenOpt 103 | val url = 104 | propertyOnFile("url", configFile) orElse 105 | Config.environment("jdbc_url") 106 | } -------------------------------------------------------------------------------- /chapter11/src/main/scala/scalax/functional/Applicative.scala: -------------------------------------------------------------------------------- 1 | package scalax.functional 2 | 3 | /** 4 | * This trait represents... 5 | */ 6 | trait Applicative[F[_]] { 7 | /** 8 | * This function is responsible for taking a mapped morphism (i.e. F[A=>B] where A=>B is the 'morphism' or function) and 9 | * converting into a function against the mapped domain, i.e. F[A] => F[B]. 10 | * 11 | * Note: This is similar to Haskell's <*> function. 12 | */ 13 | def lift2[A,B](f: F[A=>B])(ma: F[A]): F[B] 14 | } 15 | 16 | object Applicative { 17 | implicit def makeBuilder[F[_] : Functor : Applicative,A](ma: F[A]) = new ApplicativeBuilder[F,A](ma) 18 | def apply[F[_]: Functor: Applicative, A](m: F[A]) = makeBuilder(m) 19 | def build[F[_]: Functor: Applicative, A](m: F[A]) = makeBuilder(m) 20 | def foo(x: String*) = null 21 | def lift[F[_]: Functor: Applicative] = new { 22 | val func = implicitly[Functor[F]] 23 | val app = implicitly[Applicative[F]] 24 | def apply3[A,B,C,D](f: (A,B,C) => D): (F[A], F[B], F[C]) => F[D] = { 25 | (fa, fb, fc) => 26 | val tmp: F[B => C => D] = func.map(fa)(f.curried) 27 | val tmp2: F[C => D] = app.lift2(tmp)(fb) 28 | app.lift2(tmp2)(fc) 29 | } 30 | } 31 | 32 | implicit object OptionApplicative extends Applicative[Option] { 33 | def lift2[A,B](f: Option[A=>B])(ma: Option[A]): Option[B] = for { 34 | func <- f 35 | a <- ma 36 | } yield func(a) 37 | } 38 | implicit object TraversableApplicative extends Applicative[Traversable] { 39 | def lift2[A,B](f: Traversable[A=>B])(ma: Traversable[A]): Traversable[B] = for { 40 | func <- f 41 | a <- ma 42 | } yield func(a) 43 | } 44 | } 45 | 46 | class ApplicativeBuilder[F[_],A](ma: F[A])(implicit functor: Functor[F], ap: Applicative[F]) { 47 | import Implicits._ 48 | def and[B](mb: F[B]) = new ApplicativeBuilder2(mb) 49 | def apply[B](f: A => B): F[B] = ma.map(f) 50 | class ApplicativeBuilder2[B](mb: F[B]) { 51 | def apply[C](f: (A, B) => C): F[C] = ap.lift2((ma.map(f.curried)))(mb) 52 | def and[C](mc: F[C]) = new AppplicativeBuilder3[C](mc) 53 | class AppplicativeBuilder3[C](mc: F[C]) { 54 | def apply[D](f: (A,B,C) => D): F[D] = ap.lift2(ap.lift2((ma.map(f.curried)))(mb))(mc) 55 | def and[D](md: F[D]) = new ApplicativeBuilder4[D](md) 56 | class ApplicativeBuilder4[D](md: F[D]) { 57 | def apply[E](f: (A,B,C,D) => E): F[E] = ap.lift2(ap.lift2(ap.lift2((ma.map(f.curried)))(mb))(mc))(md) 58 | def and[E](me: F[E]) = new ApplicativeBuilder5[E](me) 59 | class ApplicativeBuilder5[E](me: F[E]) { 60 | def apply[R](f: (A,B,C,D,E) => R): F[R] = ap.lift2(ap.lift2(ap.lift2(ap.lift2((ma.map(f.curried)))(mb))(mc))(md))(me) 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | 68 | trait ApplicativeMagic[F[_]] { 69 | def apply[C](f: ApplicativeMagicFunctionHolder[FunctionArg => C]): F[C] 70 | type FunctionArg 71 | } 72 | class ApplicativeMagicFunctionHolder[F](val f: F) 73 | object ApplicativeMagicFunctionHolder { 74 | implicit def fix2[A,B,C](f: (A,B) => C): ApplicativeMagicFunctionHolder[Tuple2[A,B] => C] = 75 | new ApplicativeMagicFunctionHolder(f.tupled) 76 | implicit def fix3[A,B,C,D](f: (A,B,C) => D): ApplicativeMagicFunctionHolder[Tuple2[Tuple2[A,B],C] => D] = 77 | new ApplicativeMagicFunctionHolder({ case ((a,b),c) => f(a,b,c) }) 78 | implicit def fix4[A,B,C,D,E](f: (A,B,C,D) => E): ApplicativeMagicFunctionHolder[Tuple2[Tuple2[Tuple2[A,B],C],D] => E] = 79 | new ApplicativeMagicFunctionHolder({ case (((a,b),c),d) => f(a,b,c,d) }) 80 | implicit def fix5[A,B,C,D,E,F](f: (A,B,C,D,E) => F): ApplicativeMagicFunctionHolder[Tuple2[Tuple2[Tuple2[Tuple2[A,B],C],D],E] => F] = 81 | new ApplicativeMagicFunctionHolder({ case ((((a,b),c),d),e) => f(a,b,c,d,e) }) 82 | def apply[A,C](f: A => C) = new ApplicativeMagicFunctionHolder(f) 83 | } 84 | object ApplicativeMagic { 85 | def apply[F[_], A](ma: F[A])(implicit functor: Functor[F], app: Applicative[F]) = new ApplicativeMagic1[F,A](ma)(functor, app) 86 | } 87 | class ApplicativeMagic1[F[_],A](ma: F[A])(implicit functor: Functor[F], app: Applicative[F]) extends ApplicativeMagic[F] { 88 | import Implicits._ 89 | type FunctionArg = A 90 | override def apply[C](f: ApplicativeMagicFunctionHolder[FunctionArg => C]): F[C] = ma map f.f 91 | def <*>[B](mb: F[B]) = new ApplicativeMagicN[F,B,this.type](mb, this) 92 | } 93 | class ApplicativeMagicN[F[_], B, Magic <: ApplicativeMagic[F]](mn: F[B], prev: Magic)(implicit functor: Functor[F], app: Applicative[F]) extends ApplicativeMagic[F] { 94 | import Implicits._ 95 | type FunctionArg = (Magic#FunctionArg, B) 96 | override def apply[C](f: ApplicativeMagicFunctionHolder[FunctionArg => C]): F[C] = { 97 | val f2: Magic#FunctionArg => B => C = args => b => f.f((args,b)) 98 | app.lift2(prev[B=>C](ApplicativeMagicFunctionHolder(f2)))(mn) 99 | } 100 | def <*>[C](mc: F[C]) = new ApplicativeMagicN[F,C,this.type](mc, this) 101 | } 102 | 103 | /* 104 | object AppMagic 105 | 106 | trait AppMagic[F[_]] { 107 | type ReturnType[B] 108 | type ArgType 109 | type CurriedFuncType[B] = ArgType => ReturnType[B] 110 | def apply[B](f: CurriedFuncType[B]): F[B] 111 | def fmap[B](f: F[CurriedFuncType[B]]): F[B] 112 | } 113 | 114 | class AppMagicN[A, F[_] : Functor : Applicative, T <: AppMagic[F]](prev: T, mb: F[A]) extends AppMagic[F] { 115 | type ReturnType[B] = T#CurriedFuncType[B] 116 | type ArgType = A 117 | def apply[B](f: CurriedFuncType[B]): F[B] = fmap(implicitly[Functor[F]].apply(f)) 118 | def fmap[B](f: F[CurriedFuncType[B]]): F[B] = prev.fmap(implicitly[Applicative[F]].lift2(f)(mb)) 119 | } 120 | 121 | class AppMagic1[A, F[_]: Functor : Applicative](val ma: F[A]) extends AppMagic[F] { 122 | type ReturnType[B] = B 123 | type ArgType = A 124 | import Implicits._ 125 | 126 | def <*>[B](mb: F[B]) = { 127 | val tmp = new AppMagic1[B,F](mb) 128 | new AppMagicN[A, F, tmp.type](tmp, ma) 129 | } 130 | def apply[B](f: CurriedFuncType[B]): F[B] = ma map f 131 | def fmap[B](f: F[CurriedFuncType[B]]): F[B] = implicitly[Applicative[F]].lift2(f)(ma) 132 | } 133 | 134 | */ -------------------------------------------------------------------------------- /chapter7/type-programming/hlist2.scala: -------------------------------------------------------------------------------- 1 | /** Encoding of natural numbers in the type system, similar to church numerals */ 2 | sealed trait Nat { 3 | // This type is a mechanism for expansion of types over natural numbers. 4 | // Up is used as an upper bound for the resulting types of Exapnd. 5 | // NonZero is the type constructor to call against the previous natural number and 6 | // IfZero is the type to use when at the 'base' natural number, _0 7 | type Expand[NonZero[N <: Nat] <: Up, IfZero <: Up, Up] <: Up 8 | } 9 | 10 | object Nat { 11 | // Encoding for our 'zero' in the type system. 12 | sealed trait _0 extends Nat { 13 | // Expand also take steh IfZero case. 14 | type Expand[NonZero[N <: Nat] <: Ret, IfZero <: Ret, Ret] = IfZero 15 | } 16 | // Encoding for non-zero numbers based on a successive number. 17 | // Prev is the previous number in the type system. 18 | sealed trait Succ[Prev <: Nat] extends Nat { 19 | type Expand[NonZero[N <: Nat] <: Ret, IfZero <: Ret, Ret] = NonZero[Prev] 20 | } 21 | // Encode numbers 1->22 into the type system. Note: This only lets us use numbers _1 through _22. 22 | type _1 = Succ[_0] 23 | type _2 = Succ[_1] 24 | type _3 = Succ[_2] 25 | type _4 = Succ[_3] 26 | type _5 = Succ[_4] 27 | type _6 = Succ[_5] 28 | type _7 = Succ[_6] 29 | type _8 = Succ[_7] 30 | type _9 = Succ[_8] 31 | type _10 = Succ[_9] 32 | type _11 = Succ[_10] 33 | type _12 = Succ[_11] 34 | type _13 = Succ[_12] 35 | type _14 = Succ[_13] 36 | type _15 = Succ[_14] 37 | type _16 = Succ[_15] 38 | type _17 = Succ[_16] 39 | type _18 = Succ[_17] 40 | type _19 = Succ[_18] 41 | type _20 = Succ[_19] 42 | type _21 = Succ[_20] 43 | type _22 = Succ[_21] 44 | } 45 | 46 | /** Defines a heterogenously typed list. FullType captures the full type of the HList */ 47 | trait HListLike[FullType <: HList] extends HList { 48 | def viewAt[Idx <: Nat](implicit in : FullType => FullType#ViewAt[Idx]) = in(this.asInstanceOf[FullType]) 49 | def ::[T](v : T) = HCons(v, this.asInstanceOf[FullType]) 50 | } 51 | 52 | /**The base type for HLists. We can capture any Hlist using FullType <: HList and using various recursive algorithms 53 | * to deconstruct the list in a strongly typed fashion. This can be very handy when passing heterogenously typed 54 | * lists that share a common type-class. 55 | */ 56 | sealed trait HList { 57 | /**This defines the type for a View of the list at a given index. These views are used to modify 58 | * the list and to access values based on index. 59 | */ 60 | type ViewAt[N <: Nat] <: IndexedView 61 | } 62 | 63 | /** 64 | * This class represents a link-node in the linked heterogenous list. The type H refers to the type at the head 65 | * of the list, and the tail list is captures in the type T. 66 | */ 67 | final case class HCons[H, T <: HList](head : H, tail : T) extends HListLike[HCons[H,T]] { 68 | /** 69 | * This defines the type view of the list at a given index N. This is done by recursively building up an HListViewX 70 | * classes using the natural numbers encoded in the type system. 71 | */ 72 | type ViewAt[N <: Nat] = N#Expand[ 73 | ({ type Z[P <: Nat] = HListViewN[H, T#ViewAt[P]] })#Z, 74 | HListView0[H,T], 75 | IndexedView] 76 | override def toString = head + " :: " + tail 77 | } 78 | 79 | /** 80 | * This represents an empty heterogenious list. 81 | */ 82 | class HNil extends HListLike[HNil] { 83 | type ViewAt[N <: Nat] = Nothing 84 | override def toString = "HNil" 85 | } 86 | 87 | /** 88 | * The companion object to HList contains convenience definitions. 89 | */ 90 | object HList { 91 | // This defines the type operator to construct HList types using ::. 92 | type ::[H, T <: HList] = HCons[H,T] 93 | // Alias for HCons so that HList's can be constructed using :: 94 | val :: = HCons 95 | // The singleton HNil object used to construct HLists. This technique is chosen such that HNil refers to both 96 | // the empty-list type and the empty-list value depending on context. 97 | val HNil = new HNil 98 | // This method recursively builds an indexed view for a list using implicit resolution. 99 | def indexedView[List <: HList, 100 | Idx <: Nat](list : List)(implicit in : List => List#ViewAt[Idx]) = in(list) 101 | } 102 | 103 | import HList._ 104 | 105 | /**The base trait for indexed views. This gives the type system a bottom type that we can call 106 | * methods against if needed. 107 | */ 108 | sealed trait IndexedView { 109 | type Before <: HList 110 | type After <: HList 111 | type At 112 | def fold[R](f : (Before, At, After) => R) : R 113 | def get = fold( (_, value, _) => value) 114 | } 115 | 116 | /** Companion object that stores the implicit factories for IndexedView classes */ 117 | object IndexedView { 118 | /** The base case: An indexedview of the head of the list */ 119 | implicit def index0[H, T <: HList](list : H :: T) : HListView0[H,T] = 120 | new HListView0[H,T](list) 121 | /** The recursive case: An indexedView that captures a new head and delegates to a view of the tail. */ 122 | implicit def indexN[H, T <: HList, Prev <: IndexedView]( 123 | list : (H :: T))(implicit indexTail : T => Prev) : HListViewN[H,Prev] = 124 | new HListViewN[H, Prev](list.head, indexTail(list.tail)) 125 | } 126 | 127 | 128 | /** 129 | * This represents the view of an HList from its head. As such, both the head and tail types of the list are 130 | * captured and fold is defined against the head of the list. 131 | */ 132 | final class HListView0[H, T <: HList](val list : H :: T) extends IndexedView { 133 | type Before = HNil 134 | type After = T 135 | type At = H 136 | def fold[R](f : (Before, At, After) => R): R = 137 | f(HNil, list.head, list.tail) 138 | } 139 | 140 | /** 141 | * This represents the view of an HList where the current index is *not* the desired index for the view. 142 | * This class builds from an IndexedView against a tail of list. It captures one element preceding the tail. 143 | * This mechanism can be used to indexed anywhere in a list, by creating a HListView0 at the desired index and 144 | * building out HListViewN's to capture the preceding values of the list. 145 | */ 146 | final class HListViewN[H, NextIdxView <: IndexedView](h : H, next : NextIdxView) extends IndexedView { 147 | type Before = H :: NextIdxView#Before 148 | type At = NextIdxView#At 149 | type After = NextIdxView#After 150 | def fold[R](f : (Before, At, After) => R) : R = 151 | next.fold( (before, at, after) => 152 | f(HCons(h, before), at, after) ) 153 | } 154 | 155 | 156 | --------------------------------------------------------------------------------