Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
CS-206 Demos
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Sankalp Gambhir
CS-206 Demos
Commits
0ac3ccc8
Commit
0ac3ccc8
authored
1 year ago
by
Matt Bovel
Browse files
Options
Downloads
Patches
Plain Diff
Add to CI, reformat
parent
11bdc759
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
.gitlab-ci.yml
+1
-1
1 addition, 1 deletion
.gitlab-ci.yml
src/main/scala/ed/39368.scala
+15
-15
15 additions, 15 deletions
src/main/scala/ed/39368.scala
src/main/scala/lecture13/AskPattern.scala
+95
-90
95 additions, 90 deletions
src/main/scala/lecture13/AskPattern.scala
with
111 additions
and
106 deletions
.gitlab-ci.yml
+
1
−
1
View file @
0ac3ccc8
...
...
@@ -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"
This diff is collapsed.
Click to expand it.
src/main/scala/ed/39368.scala
+
15
−
15
View file @
0ac3ccc8
...
...
@@ -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"
)
This diff is collapsed.
Click to expand it.
src/main/scala/lecture13/AskPattern.scala
+
95
−
90
View file @
0ac3ccc8
...
...
@@ -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
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment