|
Hi all,
I would like to define a union types that would be like type Handler = Handler0 | Handler1 | Handler2 | Handler3
where type Handler0 = Request => Response type Handler1 = Request => Object => Response
type Handler2 = Request => Object => Object => Response type Handler3 = Request => Object => Object => Object => Response
is this possible in Scala ? -- Sébastien |
|
trait Handler
class Handler0 extends Handler class Handler1 extends Handler etc ... providing an apply with the correct argument number 2010/8/20 Sébastien Pierre <[hidden email]>: > Hi all, > I would like to define a union types that would be like > type Handler = Handler0 | Handler1 | Handler2 | Handler3 > where > type Handler0 = Request => Response > type Handler1 = Request => Object => Response > type Handler2 = Request => Object => Object => Response > type Handler3 = Request => Object => Object => Object => Response > is this possible in Scala ? > -- Sébastien > > |
|
Given the name "Handler" daisy-chaining PartialFunctions might be a more appropriate design for you
2010/8/20 Stefan Langer <[hidden email]> trait Handler -- Kevin Wright mail/google talk: [hidden email] wave: [hidden email] skype: kev.lee.wright twitter: @thecoda |
|
Hi Kevin,
Could you elaborate on that ? What would it look like ? Thanks ! -- Sébastien
Le 20 août 2010 10:32, Kevin Wright <[hidden email]> a écrit : Given the name "Handler" daisy-chaining PartialFunctions might be a more appropriate design for you |
|
2010/8/20 Sébastien Pierre <[hidden email]>
Hi Kevin,
Let's assume that we're writing an event handler for a GUI, and, instead of "Object" in your example, we use a more type-safe "Event" for this purpose. Like so: trait Event case class Click(x: Int, y: Int) extends Event //other events e.g. KeyPress etc... Then we need handlers for events. We can use PartialFunctions for this, because they're very well suited for the purpose: they can choose whether to handle an argument, which makes them "chainable", meaning that if one handler doesn't accept the argument, it can be redirected into another partial function and so on until one of them handles the argument.
Our handler type (we assume that the handler returns Unit; it could be something else of course): object Event { type Handler[A <: Event] = PartialFunction[A, Unit] } This type takes an argument A that extends Event, and creates a PartialFunction with A as the first type parameter. So "Event.Handler[Click]" will mean the same thing as "PartialFunction[Click, Unit]".
Then some handlers that use this construct: object Application { val handleTopLeftClick: Event.Handler[Click] = { case Click(x, y) if y < 20 && x < 20 => println("Clicked the top left corner!") } val handleDiagonalClick: Event.Handler[Click] = { case Click(x, y) if x == y => println("Clicked on the diagonal") } val default: Event.Handler[Event] = { case event => println("There were no handlers for the event " + event) } ...and then a demo "main" method that uses these handlers. "orElse" chains multiple PartialFunctions together. def main(foo: Array[String]) = { val handler = handleTopLeftClick orElse handleDiagonalClick orElse default handler(Click(10, 15)) //prints: Clicked the top left corner! handler(Click(100, 100)) //prints: Clicked on the diagonal handler(Click(1829, 1298)) //prints: There were no handlers for the event Click(1829,1298) } } Hope that helps. I have no idea what your program looks like, so I had to make up my own event-handling situation; feel free to supply more details if you want more input.
|
|
Hi David,
Thanks a lot for the detailed example, it's a very practical use for PartialFunction (which I haven't used so far) -- however for my application the HandlerN approach fits my needs better.
-- Sébastien 2010/8/20 David Flemström <[hidden email]>
|
|
Either is something like Type1 | Type2.
You can extend that idea: abstract class OneOfThree[A,B,C] { def as1 = Option[A] def as2 = Option[B] def as3 = Option[C] } class FirstOfThree[A,B,C](a: A) extends OneOfThree[A,B,C] { def as1 = Some(a) def as2 = None def as3 = None } class SecondOfThree[A,B,C](b: B) extends OneOfThree[A,B,C] { def as1 = None def as2 = Some(a) def as3 = None } class ThirdOfThree // Same idea // Perhaps want some method so you can pattern match on these? // (Creating a library of these is a perfect task for code-generation tools.) Or you could use structural types: // Would have to have some method in common, even if you couldn't inherit a trait def handler(h: { def method_found_only_in_handlers }) { /* . . . */ } Or you could use implicit conversions: case class Wrapper[+A](a: A) { } implicit def direct2wrap[B,C](f: B => C) = Wrapper(f) implicit def onestop2wrap[B,C](f: B => AnyRef => C) = Wrapper(f) implicit def twostops2wrap[B,C](f: B => AnyRef => AnyRef => C) = Wrapper(f) and then accept Wrapper[AnyRef] or Wrapper[_] and pattern match. --Rex |
|
In reply to this post by Sébastien Pierre
I asked a similar question on StackOverflow:
http://stackoverflow.com/questions/3508077/does-scala-have-type-disjunction. In addition to Rex's suggestions, you may want to look at MetaScala which has a OneOf type constructor: type Handler = OneOf[Handler1 :: Handler2 :: Handler3 :: Nil] Hope this helps, ~Aaron On 08/20/2010 09:02 AM, Sébastien Pierre wrote: > Hi David, > > Thanks a lot for the detailed example, it's a very practical use for > PartialFunction (which I haven't used so far) -- however for my application > the HandlerN approach fits my needs better. > > -- Sébastien > > 2010/8/20 David Flemström <[hidden email]> > >> 2010/8/20 Sébastien Pierre <[hidden email]> >> >>> Hi Kevin, >>> >>> Could you elaborate on that ? What would it look like ? >>> >>> Thanks ! >>> >> >> My name is not Kevin, but because this is an open mailing list I'll answer >> anyways. >> Let's assume that we're writing an event handler for a GUI, and, instead of >> "Object" in your example, we use a more type-safe "Event" for this purpose. >> Like so: >> >> trait Event >> case class Click(x: Int, y: Int) extends Event//other events e.g. KeyPress etc... >> >> Then we need handlers for events. We can use PartialFunctions for this, >> because they're very well suited for the purpose: they can choose whether to >> handle an argument, which makes them "chainable", meaning that if one >> handler doesn't accept the argument, it can be redirected into another >> partial function and so on until one of them handles the argument. >> Our handler type (we assume that the handler returns Unit; it could be >> something else of course): >> >> object Event { >> type Handler[A <: Event] = PartialFunction[A, Unit]} >> >> This type takes an argument A that extends Event, and creates a >> PartialFunction with A as the first type parameter. So >> "Event.Handler[Click]" will mean the same thing as "PartialFunction[Click, >> Unit]". >> Then some handlers that use this construct: >> >> object Application { >> val handleTopLeftClick: Event.Handler[Click] = { >> case Click(x, y) if y < 20 && x < 20 => >> println("Clicked the top left corner!") >> } >> >> val handleDiagonalClick: Event.Handler[Click] = { >> case Click(x, y) if x == y => >> println("Clicked on the diagonal") >> } >> >> val default: Event.Handler[Event] = { >> case event => >> println("There were no handlers for the event " + event) >> } >> >> ...and then a demo "main" method that uses these handlers. "orElse" chains >> multiple PartialFunctions together. >> >> >> def main(foo: Array[String]) = { >> val handler = handleTopLeftClick orElse handleDiagonalClick orElse default >> handler(Click(10, 15)) //prints: Clicked the top left corner! >> handler(Click(100, 100)) //prints: Clicked on the diagonal >> handler(Click(1829, 1298)) //prints: There were no handlers for the event Click(1829,1298) >> }} >> >> Hope that helps. I have no idea what your program looks like, so I had to >> make up my own event-handling situation; feel free to supply more details if >> you want more input. >> > |
|
In reply to this post by Rex Kerr-2
Or you could use implicit conversions: How would you pattern match in this case? Wouldn't you need a Manifest? --Rex |
|
2010/8/22 Naftoli Gugenheim <[hidden email]>
Good point--yes, probably, depending on how you wanted to use it, so that might not be the best way to go depending on whether it was convenient to store the manifest. --Rex |
| Powered by Nabble | Edit this page |
