Quantcast

Union types in Scala

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Union types in Scala

Sébastien Pierre
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


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Stefan Langer-4
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
>
>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Kevin Wright-3
Given the name "Handler" daisy-chaining PartialFunctions might be a more appropriate design for you

2010/8/20 Stefan Langer <[hidden email]>
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
>
>



--
Kevin Wright

mail/google talk: [hidden email]
wave: [hidden email]
skype: kev.lee.wright
twitter: @thecoda

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Sébastien Pierre
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 Stefan Langer <[hidden email]>

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
>
>



--
Kevin Wright

mail/google talk: [hidden email]
wave: [hidden email]
skype: kev.lee.wright
twitter: @thecoda


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

David Flemström
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Sébastien Pierre
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.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Rex Kerr-2
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

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Aaron Novstrup
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.
>>
>


anovstrup.vcf (300 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Naftoli Gugenheim
In reply to this post by Rex Kerr-2
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.


How would you pattern match in this case? Wouldn't you need a Manifest?
 
  --Rex


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Union types in Scala

Rex Kerr-2
2010/8/22 Naftoli Gugenheim <[hidden email]>
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.


How would you pattern match in this case? Wouldn't you need a Manifest?

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

Loading...