Scala class with Publisher and Subscriber traits - scala

Using import scala.collection.mutable.{Publisher, Subscriber} I'm trying to implement a class that subscribes to events and publishes events. For example, this class may receive raw data, operate on it, then publish the result to other subscribers.
A basic class that extends Subscriber:
scala> class Sub[Evt, Pub]() extends Subscriber[Evt, Pub]{
def notify(pub: Pub, evt: Evt){
}
}
defined class Sub
A basic class that extends Publisher:
scala> class Pub[Evt]() extends Publisher[Evt]{}
defined class Pub
Now, I want to combine the two:
scala> class PubSub[Evt, Pub] extends Subscriber[Evt, Pub] with Publisher[Evt]{
def notify(pub: Pub, evt: Evt){
}
}
<console>:26: error: class PubSub needs to be abstract, since method notify in
trait Subscriber of type (pub: Pub,event: Evt)Unit is not defined class
PubSub[Evt,Pub] extends Subscriber[Evt, Pub] with Publisher[Evt]{
The notify method is defined so perhaps the error is misleading.
I'm not sure how to define the type parameters for the PubSub class which might be part of the problem.

The problem is that the class Publisher defines a type Pub which shadows the generic Pub argument.
Just rename it to something else:
class PubSub[Evt, Pub2] extends Subscriber[Evt, Pub2] with Publisher[Evt]{
def notify(pub: Pub2, evt: Evt){
}
}

You should take a look at the paper Deprecating the Observer Pattern I believe. scala.react package described there isn't released as a part of the standard distribution, but some snapshot is available on the author's homepage. If you are not planning to use it in production systems right now this project can give a sufficient playground.

Related

Akka Typed and having base class for MessageAdapters

I am trying something with Akka Typed and Scala, actually something very simple as concept but I could not make it work so may be you can help me.
All my Actors will have one common Signal, so I try to place it to a base class and let my all Actors share it but it the compiler refuse it in the MessageAdapter....
So my code looks like following....
object ContractActor {
sealed trait ContractEvent extends BaseEvent
final case class onApprove(payload: Payload) extends ContractEvent
}
class ContractActor(ctx: ActorContext[ContractEvent]) extends BaseActor {
val listingAdapter = : ActorRef[Receptionist.Listing] = ctx.
messageAdapter(
listing => onAddRelatedEvent(listing)
}
and base actor
object BaseActor {
trait BaseEvent;
final case class onAddRelatedEvent(listing: Receptionist.Listing) extends BaseEvent
}
The compiler complains about onAddRelatedEvent is not known on ContractEvent which surprise me because ContractEvent extends BaseEvent....
What am I missing here....
Class ContractActor extending BaseActor does not automatically bring BaseActor's companion object into scope. To bring it into scope, just import it inside class ContractActor:
import BaseActor._
Alternatively, you could move the inner trait/case class into BaseActor's companion class.

Purpose of pattern where object extends trait of the same name - object Live extends Live

I am trying ZIO.
I do not understand why Live is added as Trait, and then an object is provided, like:
object Live extends Live
This pattern is found in different places, for example zio.console.Console.
Is there a reason, or are there cases where this makes sense?
What you see in ZIO is the usage of a pattern called Selfless Trait.
To implement the selfless trait pattern you simply provide a companion object for a trait that itself mixes in the trait.
trait Greeting {
def greet() { println("hi there") }
}
object Greeting extends Greeting
Then the user of the library has the choice to either mix-in Greeting:
object MixinExample extends Application with Greeting {
greet()
}
or to import the members of the Greeting companion object, like this:
import Greeting._
object ImportExample extends Application {
greet()
}
Just as an addition to Krzysztof Atłasik answer.
As mentioned in jq170727 comment you find these two cases here:
introduce-a-database-module
Object:
In the worst case, if we are pressed for time and need to ship code
today, maybe we choose to provide the production database wherever we
call inviteFriends.
inviteFriends(userId).provide(DatabaseLive)
In this case, instead of using the DefaultRuntime that ships with ZIO,
we can define our own Runtime, which provides the production database
module):
val myRuntime = Runtime(DatabaseLive, PlatformLive)
Trait:
When you have multiple Runtimes.
val myRuntime =
Runtime(
new DatabaseLive
with SocialLive
with EmailLive, PlatformLive)

What kind the implementation it is?

On the akka website, you can the following definition:
sealed trait AccountCommand[Reply] extends ExpectingReply[Reply]
final case class Withdraw(amount: BigDecimal)(override val replyTo: ActorRef[OperationResult])
extends AccountCommand[OperationResult]
How to assign an ActorRef to replyTo?
I've taken the code as an example and try to implement on own type:
case object Channel (override val replyTo: ActorRef[SendMessage])
extends ExpectingReply[SendMessage]
and the compiler complains.
The way, that the compiler does not complain:
case object Channel extends ExpectingReply[SendMessage] {
override def replyTo: ActorRef[SendMessage] = ???
}
Is the example on akka website wrong?
If your message does not have fields, you can use a case class without parameters:
case class Channel()(override val replyTo: ActorRef[SendMessage])
extends ExpectingReply[SendMessage]
If you're asking about how to create an instance of such a class, then you should use the standard multi-parameter function call syntax:
val msg = Channel()(sendMessageActorRef)
That being said, it looks to me that specifically in that part of the Akka API that you linked to, you don't have to explicitly provide any ActorRefs, Effects seem to do it kind of automatically.

Can a class extend itself?

I am reading the source code of Spark. I see it seems a class extends itself.
My questions: does it extend itself? If so, what's it called? Why do we do that?
class OneHotEncoderModel private[ml] (
#Since("2.3.0") override val uid: String,
#Since("2.3.0") val categorySizes: Array[Int])
extends Model[OneHotEncoderModel] with OneHotEncoderBase with MLWritable
It's not extending itself. Actually, "extends itself" has no meaning, or one could say all classes extends them-selves.
OneHotEncoderModel(...) extends Model[OneHotEncoderModel] with ...
means that OneHotEncoderModel extends Model. And Model is type-parametrized with OneHotEncoderModel. This construct allows Model to have the actual implementing class as a type-parameter and use it.
This can be used, for example, in an abstract api:
trait Model[A]{
def join(other: A): A
}
Here, to be a Model sub-class, OneHotEncoderModel will have to implement def join(other: OneHotEncoderModel): OneHotEncoderModel

Scala: Using the App trait

I have an app that extends App and a trait that implements an option parser. All the trait needs is that some class or trait in the runtime mix provides:
val args: Array[String]
If I declare:
trait OptionParser extends App {...}
All is fine but that rules out any other use of the option parser than with an App object. Not sure if there are inefficiencies in having the app extend App as well as mixing in OptionParser as with:
object MyApp extends App with OptionParser {...}
I realize this could be shortened to:
object MyApp extends OptionParser {...}
But ideally I'd like to make OptionParser completely independent except for relying on args to be provided and this is only because that's where App puts them.
Is there some way to declare a dependency without providing the class or trait to take it from? An error could be detected at link time so as not to break type safety.
Not sure I understand exactly what you are trying to do. How about that:
trait OptionParser {
protected def args: Array[String]
}
This way, you can mixin OptionParser with anything that provides a args, not necessarily App.
Edit: since App defines args visibility as protected you need to do that in OptionParser as well. This is unfortunate. Here is another idea:
trait OptionParser {def options: Array[String] ... }
object MyApp extends App with OptionParser {def options = args ...}
You can do this with a self type declaration on OptionParser. This will require types that mix in OptionParser to be an App, without mixing in App itself.
trait OptionParser { this: App =>
def test(): Unit = {
println("test")
println(args)
}
}
object Test extends App with OptionParser {
test()
println("done")
}