Skip to content
Snippets Groups Projects
Commit 0ac3ccc8 authored by Matt Bovel's avatar Matt Bovel
Browse files

Add to CI, reformat

parent 11bdc759
No related branches found
No related tags found
No related merge requests found
......@@ -21,4 +21,4 @@ test:
tags:
- cs320
script:
- sbt "runMain lecture1.javaThreads; runMain lecture1.scalaThreadWrapper; runMain lecture1.ExampleThread; runMain lecture3.intersectionWrong; runMain lecture3.intersectionCorrect; runMain lecture3.intersectionNoSideEffect; runMain lecture3.parallelGraphContraction; runMain lecture3.parallelGraphContractionCorrect; runMain midterm22.mock1; runMain midterm22.part3; test; scalafmtCheck; Test / scalafmtCheck"
- sbt "runMain lecture1.javaThreads; runMain lecture1.scalaThreadWrapper; runMain lecture1.ExampleThread; runMain lecture3.intersectionWrong; runMain lecture3.intersectionCorrect; runMain lecture3.intersectionNoSideEffect; runMain lecture3.parallelGraphContraction; runMain lecture3.parallelGraphContractionCorrect; runMain midterm22.mock1; runMain midterm22.part3; runMain ed.patternMatching; runMain lecture13.askPatternDemo; test; scalafmtCheck; Test / scalafmtCheck"
......@@ -5,20 +5,20 @@ val ada = Person("Ada", 36)
// Run using `sbt "runMain ed.patternMatching"`.
@main def patternMatching =
// There are several ways to pattern match on the `ada` instance:
// 1. Pattern matching on the case class constructor using `Person(name, age)`.
// If the pattern matches, the value of `n` is bound `ada.name` field, and
// `a` is bound to the `ada.age` field.
ada match
case Person(n, a) => println(f"$n is $a years old")
// There are several ways to pattern match on the `ada` instance:
// 1. Pattern matching on the case class constructor using `Person(name, age)`.
// If the pattern matches, the value of `n` is bound `ada.name` field, and
// `a` is bound to the `ada.age` field.
ada match
case Person(n, a) => println(f"$n is $a years old")
// 2. We can also check only that `ada` is of type `Person` without binding its
// fields by using a `:` pattern. The `:` pattern is used to check if a value is
// of a certain type.
ada match
case p: Person => println(f"${p.name} is ${p.age} years old")
// 2. We can also check only that `ada` is of type `Person` without binding its
// fields by using a `:` pattern. The `:` pattern is used to check if a value is
// of a certain type.
ada match
case p: Person => println(f"${p.name} is ${p.age} years old")
// 3. If we want to both bind the fields and bind a value to the whole instance,
// we can use an `@` pattern.
ada match
case p @ Person(n, a) => println(f"${p.name} is ${a} years old")
// 3. If we want to both bind the fields and bind a value to the whole instance,
// we can use an `@` pattern.
ada match
case p @ Person(n, a) => println(f"${p.name} is ${a} years old")
......@@ -9,10 +9,10 @@ import akka.pattern.pipe
import akka.testkit.{ImplicitSender, TestKit}
import akka.util.Timeout
/**
* This demonstrates a simplified implementation of the ask pattern.
/** This demonstrates a simplified implementation of the ask pattern.
*
* @param promise the promise to be completed when a message is received
* @param promise
* the promise to be completed when a message is received
*/
class AskMiniActor(promise: Promise[Any]) extends Actor:
def receive = LoggingReceive {
......@@ -21,16 +21,18 @@ class AskMiniActor(promise: Promise[Any]) extends Actor:
extension (receiver: ActorRef)
def ?(msg: Any)(using
// In this simplified implementation, we don't use the timeout.
timeout: Timeout,
// This only used for logging purposes (and to get the actor system in the
// real implementation), but is not used otherwise in the implementation.
sender: ActorRef,
// In the real implementation, the actor system is retrieved differently,
// but here we pass it as an additional implicit parameter for simplicity.
context: ActorContext
// In this simplified implementation, we don't use the timeout.
timeout: Timeout,
// This only used for logging purposes (and to get the actor system in the
// real implementation), but is not used otherwise in the implementation.
sender: ActorRef,
// In the real implementation, the actor system is retrieved differently,
// but here we pass it as an additional implicit parameter for simplicity.
context: ActorContext
): Future[Any] =
context.system.log.debug(s"Create mini actor to ask $msg from $sender to $receiver")
context.system.log.debug(
s"Create mini actor to ask $msg from $sender to $receiver"
)
// Create a `Promise` that will be completed when a message is received.
val promise = Promise[Any]()
......@@ -49,91 +51,94 @@ extension (receiver: ActorRef)
promise.future
object Person:
enum Protocol:
case GetName
case GetAge
enum Response:
case Name(name: String)
case Age(age: Int)
case UnknownMessage
enum Protocol:
case GetName
case GetAge
enum Response:
case Name(name: String)
case Age(age: Int)
case UnknownMessage
class Person(name: String, age: Int) extends Actor:
import Person.Protocol._
import Person.Response._
import Person.Protocol.*
import Person.Response.*
def receive = LoggingReceive {
case GetName => sender() ! Name(name)
case GetAge => sender() ! Age(age)
case _ => sender() ! UnknownMessage
case GetAge => sender() ! Age(age)
case _ => sender() ! UnknownMessage
}
object PersonsDatabase:
enum Protocol:
case CreatePerson(name: String, age: Int)
case GetPersonNames(ids: List[Int])
enum Response:
case PersonCreated(id: Int)
case PersonNames(names: List[String])
enum Protocol:
case CreatePerson(name: String, age: Int)
case GetPersonNames(ids: List[Int])
enum Response:
case PersonCreated(id: Int)
case PersonNames(names: List[String])
class PersonsDatabase extends Actor:
import Person.Protocol._
import Person.Response._
import PersonsDatabase.Protocol._
import PersonsDatabase.Response._
var persons: Map[Int, ActorRef] = Map.empty
var maxId = 0
given ExecutionContext = context.system.dispatcher
given Timeout = Timeout(200.millis)
def receive = LoggingReceive {
case CreatePerson(name, age) =>
val personRef = context.actorOf(Props(Person(name, age)))
persons = persons + (maxId -> personRef)
sender() ! PersonCreated(maxId)
maxId += 1
case GetPersonNames(ids) =>
// We ask every person for their name using the ask pattern. This
// gives us a list of `Future`s that will each be completed with a
// `Name` message.
val rawResponsesFutures: List[Future[Any]] = ids.map(id => (persons(id) ? GetName))
// We first map each `Future[Any]` to a `Future[Name]` using the
// `mapTo` method. Then, we map each `Future[Name]` to a
// `Future[String]` using the `map` method.
val namesFutures: List[Future[String]] = rawResponsesFutures.map(_.mapTo[Name].map(_.name))
// We use the `Future.sequence` method to convert a
// `List[Future[String]]` to a `Future[List[String]]`. The resulting
// future will be completed once all the futures in the input list
// are completed.
val futureOfNames: Future[List[String]] = Future.sequence(namesFutures)
// Finally, map the `Future[List[String]]` to a
// `Future[PersonNames]` and pipe it to the sender of the
// `GetPersonNames` message.
futureOfNames.map(PersonNames.apply).pipeTo(sender())
}
@main def askPatternDemo() = new TestKit(ActorSystem("DebugSystem")) with ImplicitSender:
import Person.Protocol._
import Person.Response._
import PersonsDatabase.Protocol._
import PersonsDatabase.Response._
try
val personsDb = system.actorOf(Props(PersonsDatabase()))
personsDb ! CreatePerson("Anita", 20)
expectMsg(PersonCreated(0))
personsDb ! CreatePerson("Berta", 30)
expectMsg(PersonCreated(1))
personsDb ! CreatePerson("Cecilia", 40)
expectMsg(PersonCreated(2))
personsDb ! GetPersonNames(List(0, 1, 2))
expectMsg(PersonNames(List("Anita", "Berta", "Cecilia")))
finally shutdown(system)
import Person.Protocol.*
import Person.Response.*
import PersonsDatabase.Protocol.*
import PersonsDatabase.Response.*
var persons: Map[Int, ActorRef] = Map.empty
var maxId = 0
given ExecutionContext = context.system.dispatcher
given Timeout = Timeout(200.millis)
def receive = LoggingReceive {
case CreatePerson(name, age) =>
val personRef = context.actorOf(Props(Person(name, age)))
persons = persons + (maxId -> personRef)
sender() ! PersonCreated(maxId)
maxId += 1
case GetPersonNames(ids) =>
// We ask every person for their name using the ask pattern. This
// gives us a list of `Future`s that will each be completed with a
// `Name` message.
val rawResponsesFutures: List[Future[Any]] =
ids.map(id => (persons(id) ? GetName))
// We first map each `Future[Any]` to a `Future[Name]` using the
// `mapTo` method. Then, we map each `Future[Name]` to a
// `Future[String]` using the `map` method.
val namesFutures: List[Future[String]] =
rawResponsesFutures.map(_.mapTo[Name].map(_.name))
// We use the `Future.sequence` method to convert a
// `List[Future[String]]` to a `Future[List[String]]`. The resulting
// future will be completed once all the futures in the input list
// are completed.
val futureOfNames: Future[List[String]] = Future.sequence(namesFutures)
// Finally, map the `Future[List[String]]` to a
// `Future[PersonNames]` and pipe it to the sender of the
// `GetPersonNames` message.
futureOfNames.map(PersonNames.apply).pipeTo(sender())
}
@main def askPatternDemo() =
new TestKit(ActorSystem("DebugSystem")) with ImplicitSender:
import Person.Protocol.*
import Person.Response.*
import PersonsDatabase.Protocol.*
import PersonsDatabase.Response.*
try
val personsDb = system.actorOf(Props(PersonsDatabase()))
personsDb ! CreatePerson("Anita", 20)
expectMsg(PersonCreated(0))
personsDb ! CreatePerson("Berta", 30)
expectMsg(PersonCreated(1))
personsDb ! CreatePerson("Cecilia", 40)
expectMsg(PersonCreated(2))
personsDb ! GetPersonNames(List(0, 1, 2))
expectMsg(PersonNames(List("Anita", "Berta", "Cecilia")))
finally shutdown(system)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment