- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Parametrized vs Abstract type
Wed, 2011-12-14, 01:44
I've got 2 class groups, which implement similar functionality:
object CurrencyWithAbstractType{
trait AbstractCurrency{
type Currency <: AbstractCurrency
def value : Double
def make(d:Double) : Currency
def +(x: AbstractCurrency/*doesnt compile if I change it to Currency*/) = make(x.value + value)
}
class USD(val value: Double) extends AbstractCurrency {
type Currency = USD
def make(d: Double) = new USD(d)
}
class EUR(val value: Double) extends AbstractCurrency {
type Currency = EUR
def make(d: Double) = new EUR(d)
}
def plus[T <: AbstractCurrency](c1: T, c2:T) : T#Currency = c1 + c2
val x : USD = plus(new USD(100),new USD(200))
new EUR(100) + new USD(50) //compiles which is wrong
}
object CurrencyWithParametrizedType{
trait AbstractCurrency[Currency <: AbstractCurrency[Currency]]{
val value : Double
def make(d:Double) : Currency
def +(x: Currency) = make(x.value + value)
}
class USD(val value: Double) extends AbstractCurrency[USD] {
def make(d: Double) = new USD(d)
}
class EUR(val value: Double) extends AbstractCurrency[EUR] {
def make(d: Double) = new EUR(d)
}
def plus[T <: AbstractCurrency[T]](c1: T, c2:T) : T = c1 + c2
val x : USD = plus(new USD(100),new USD(200))
new EUR(100) + new USD(50) // doesnt compile whis is expected
}
First question is how do I make Abstract Type version to detect that:
new EUR(100) + new USD(50)
shouldn't compile?
Second: how do I get rid of this funny T#Currency type in line:
def plus[T <: AbstractCurrency](c1: T, c2:T) : T#Currency = c1 + c2
I would guess that T is equivalent to T#Currency so this should be enough:
def plus[T <: AbstractCurrency](c1: T, c2:T) : T = c1 + c2
Piotr Gabryanczyk
Thu, 2011-12-15, 00:51
#2
Re: Re: Parametrized vs Abstract type
On Thu, Dec 15, 2011 at 9:38 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
You can get there with dependent method types.
https://gist.github.com/1479149
-jason
Is my question so silly, or nobody really understand the
difference? :)
You can get there with dependent method types.
https://gist.github.com/1479149
-jason
Thu, 2011-12-15, 01:01
#3
Re: Re: Parametrized vs Abstract type
You have to drill all the way down and specify the type: T <: AbstractCurrency { type Currency = T }
object CurrencyWithAbstractType{
trait AbstractCurrency{
type Currency <: AbstractCurrency
def value : Double
def make(d:Double) : Currency
def +(x: Currency/*must be Currency*/) = make(x.value + value)
}
class USD(val value: Double) extends AbstractCurrency {
type Currency = USD
def make(d: Double) = new USD(d)
}
class EUR(val value: Double) extends AbstractCurrency {
type Currency = EUR
def make(d: Double) = new EUR(d)
}
def plus[T <: AbstractCurrency { type Currency = T } ](c1: T, c2:T) : T#Currency = c1 + c2
val x : USD = plus(new USD(100),new USD(200))
new EUR(100) + new USD(50) //compiles which is wrong
}
On Wed, Dec 14, 2011 at 5:47 PM, Jason Zaugg <jzaugg@gmail.com> wrote:
object CurrencyWithAbstractType{
trait AbstractCurrency{
type Currency <: AbstractCurrency
def value : Double
def make(d:Double) : Currency
def +(x: Currency/*must be Currency*/) = make(x.value + value)
}
class USD(val value: Double) extends AbstractCurrency {
type Currency = USD
def make(d: Double) = new USD(d)
}
class EUR(val value: Double) extends AbstractCurrency {
type Currency = EUR
def make(d: Double) = new EUR(d)
}
def plus[T <: AbstractCurrency { type Currency = T } ](c1: T, c2:T) : T#Currency = c1 + c2
val x : USD = plus(new USD(100),new USD(200))
new EUR(100) + new USD(50) //compiles which is wrong
}
On Wed, Dec 14, 2011 at 5:47 PM, Jason Zaugg <jzaugg@gmail.com> wrote:
On Thu, Dec 15, 2011 at 9:38 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
Is my question so silly, or nobody really understand the
difference? :)
You can get there with dependent method types.
https://gist.github.com/1479149
-jason
Thu, 2011-12-15, 01:11
#4
Re: Parametrized vs Abstract type
1. I noticed -Ydependent-method-types flag, but I was puzzled that it doesn't work by default...
2. def plus[T <: AbstractCurrency](c1: T)(c2: c1.Currency) : c1.Currency = c1 + c2 I forgot about compiler deficiency which requires currying, so it understands the types better. I tried c1.Currency but without currying... (silly me... or the compiler...). I honestly think this is one of the reasons why people tend to think that scala is complicated...
Thanks for a quick answer! :)
Piotr Gabryanczyk
On 14 Dec 2011, at 23:47, Jason Zaugg wrote:
2. def plus[T <: AbstractCurrency](c1: T)(c2: c1.Currency) : c1.Currency = c1 + c2 I forgot about compiler deficiency which requires currying, so it understands the types better. I tried c1.Currency but without currying... (silly me... or the compiler...). I honestly think this is one of the reasons why people tend to think that scala is complicated...
Thanks for a quick answer! :)
Piotr Gabryanczyk
On 14 Dec 2011, at 23:47, Jason Zaugg wrote:
On Thu, Dec 15, 2011 at 9:38 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:Is my question so silly, or nobody really understand the
difference? :)
You can get there with dependent method types.
https://gist.github.com/1479149
-jason
Thu, 2011-12-15, 09:51
#5
Re: Parametrized vs Abstract type
dependent method types will be on by default in the upcoming 2.10 (already the case in the nightly build)
cheersadriaan
cheersadriaan
Is my question so silly, or nobody really understand the
difference? :)
On Dec 14, 12:44 am, Piotr Gabryanczyk wrote:
> I've got 2 class groups, which implement similar functionality:
> object CurrencyWithAbstractType{
>
> trait AbstractCurrency{
> type Currency <: AbstractCurrency
> def value : Double
>
> def make(d:Double) : Currency
> def +(x: AbstractCurrency/*doesnt compile if I change it to Currency*/) = make(x.value + value)
> }
>
> class USD(val value: Double) extends AbstractCurrency {
> type Currency = USD
> def make(d: Double) = new USD(d)
> }
> class EUR(val value: Double) extends AbstractCurrency {
> type Currency = EUR
> def make(d: Double) = new EUR(d)
> }
>
> def plus[T <: AbstractCurrency](c1: T, c2:T) : T#Currency = c1 + c2
> val x : USD = plus(new USD(100),new USD(200))
>
> new EUR(100) + new USD(50) //compiles which is wrong
>
> }
>
> object CurrencyWithParametrizedType{
>
> trait AbstractCurrency[Currency <: AbstractCurrency[Currency]]{
> val value : Double
>
> def make(d:Double) : Currency
> def +(x: Currency) = make(x.value + value)
> }
>
> class USD(val value: Double) extends AbstractCurrency[USD] {
> def make(d: Double) = new USD(d)
> }
>
> class EUR(val value: Double) extends AbstractCurrency[EUR] {
> def make(d: Double) = new EUR(d)
> }
>
> def plus[T <: AbstractCurrency[T]](c1: T, c2:T) : T = c1 + c2
> val x : USD = plus(new USD(100),new USD(200))
> new EUR(100) + new USD(50) // doesnt compile whis is expected
>
> }
>
> First question is how do I make Abstract Type version to detect that:
> new EUR(100) + new USD(50)
> shouldn't compile?
>
> Second: how do I get rid of this funny T#Currency type in line:
> def plus[T <: AbstractCurrency](c1: T, c2:T) : T#Currency = c1 + c2
>
> I would guess that T is equivalent to T#Currency so this should be enough:
> def plus[T <: AbstractCurrency](c1: T, c2:T) : T = c1 + c2
>
> Piotr Gabryanczyk