Get specific parameters for a partial function

Say I have a partial function (similar to Akka's receiving method for participants)

def receive: PartialFunction[Any, Unit] = { case SomeCaseClass(params) => println("whatever") } 

Is there a way to get all the specific parameters of this function?

I am implementing a service structure similar to JSON RPC. I basically want customers to be able to define a service through a partial function.

 def clientService = { case Connect(login, password) =>..... case SomeMessage => ... case SomeMethod(bla) => .. } 

eg. the first method will be transferred from

 {method: "connect", params:{login: "asdsad", password: "adsada"}} 

(this part is already working)

Now, if the client has defined the service, and the other client wants to know about the available methods of the service, now I need to know what classes of classes the service accepts, so I can tell the requesting client. I know that I could do this easily using the usual methods in the object, but due to the way I parse JSON and translate it into case classes, a partial function would simplify my API and I would like beautiful code;)

Plus, I'm sure there should be a way through reflection, although I don’t know how partial functions are represented after compilation / at run time.

+4
source share
2 answers

Depending on how many assumptions you can or want to make about your services, here is a completely unsophisticated approach, which, however, may be an option. It mainly relies on 1) all known known message types and b) partial functions are partial in only one dimension (more on this later).

We need a finite set of possible message types:

 sealed trait Message case class Hello(who: String) extends Message case class Lunch(withWhom: String) extends Message case class Dinner(withWhom: String) extends Message case class Goodbye(who: String) extends Message 

And a few examples of services:

 val service0: PartialFunction[Any, Unit] = { case Hello(who) => () case Goodbye(who) => () } val service1: PartialFunction[Any, Unit] = { case Hello(who) => () case Lunch(withWhom) => () case Goodbye(who) => () } var services = List(service0, service1) 

Further, we also define a list of message instances intended to be executed as drawings for received messages:

 val simpleInstances = List(Hello("*"), Lunch("*"), Dinner("*"), Goodbye("*")) 

Finally, we define a method that returns accepted arguments from a partial function and a list of possible arguments:

 def supportedArguments[F, T, A <: F] (pf: PartialFunction[F, T], args: Iterable[A]) = args filter pf.isDefinedAt 

Cute printer:

 def printSupportedArguments(services: Iterable[PartialFunction[Any, Unit]], messages: Iterable[Message]) { services.zipWithIndex.foreach {case (s, i) => val supported = supportedArguments(s, messages) println(s"Service $i supports $supported") } } 

Release:

 printSupportedArguments(services, simpleInstances) // Service 0 supports List(Hello(*), Goodbye(*)) // Service 1 supports List(Hello(*), Lunch(*), Goodbye(*)) // Service 2 supports List(Goodbye(*)) 

Everything becomes more complicated if the services are not only partial with respect to the type of message they receive, but also partially relate to the content of the message they receive, that is, if they are partial in more than one direction:

 val service2: PartialFunction[Any, Unit] = { case Hello("Thomas") => () case Hello("Laura") => () case Goodbye(who) => () } 

Such a service also requires adaptation of the list of schema instances:

 val moreInstances = simpleInstances ++ List(Hello("Thomas"), Hello("Laura")) 

Result:

 printSupportedArguments(services :+ service2, moreInstances) // Service 0 supports List(Hello(*), Goodbye(*), Hello(Thomas), Hello(Laura)) // Service 1 supports List(Hello(*), Lunch(*), Goodbye(*), Hello(Thomas), // Hello(Laura)) // Service 2 supports List(Goodbye(*), Hello(Thomas), Hello(Laura)) 

Many of the drawbacks of this approach obviously include the following:

  • Message types must be known.

  • If services are partial in several dimensions, all possible contents of the message should be known.

  • Using an instance of Hello("*") to indicate arbitrary instances of Hello makes it impossible to distinguish between services that accept Hello(_) and services that literally only accept Hello("*")

If you find a real solution using macros or reflection (or magic), post it here!

+3
source

You ask, is it possible to get a list of all the inputs for the Any argument, which will lead to a match? If this is your question, then I believe the answer is this. All you have is isDefinedAt to tell you if the arg argument will match if it is passed to this partial function, but that is probably not what you were looking for.

+1
source

Source: https://habr.com/ru/post/1480718/


All Articles