- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Why is it not allowed to override methods with contravariant parameter types?
Mon, 2010-08-30, 09:20
This compiles:
var f:String => Object = {a => a}
var g:Object => String = {a => a.toString}
f = g
but this doesn't:
class X {
def f(s:String):Object = s
}
class Y extends X {
override def f(s:Object):String = s.toString // Method f overrides nothing
}
Why have this limitation in Scala? Is that a JVM issue?
Thanks,
Sébastien
var f:String => Object = {a => a}
var g:Object => String = {a => a.toString}
f = g
but this doesn't:
class X {
def f(s:String):Object = s
}
class Y extends X {
override def f(s:Object):String = s.toString // Method f overrides nothing
}
Why have this limitation in Scala? Is that a JVM issue?
Thanks,
Sébastien
Mon, 2010-08-30, 10:57
#2
Re: Why is it not allowed to override methods with contravarian
I do feel your pain here, as an Object=>String obviously conforms to the String=>Object signature
(i.e. I want a function that accepts a string, and a function accepting any object clearly does *that*. I also want my function to return an object, and a string is-an object, so returning a String is perfectly acceptable)
It's a JVM restriction. In order to override, the function signature must match exactly.
The only exception to this is that you can be covariant in the return type (as with Java). But this requires some trickery behind the scenes... As return types are considered part of the signature, the compiler must generate a forwarder method whenever you override with a covariant return.
And that's your answer, duplicate the trickery by hand!
in Y you must define: override def f(s:String):Object and have it delegate the call to def f(s:Object):String
On 30 August 2010 09:21, Sébastien Bocq <sebastien.bocq@gmail.com> wrote:
--
Kevin Wright
mail/google talk: kev.lee.wright@gmail.com
wave: kev.lee.wright@googlewave.com
skype: kev.lee.wright
twitter: @thecoda
(i.e. I want a function that accepts a string, and a function accepting any object clearly does *that*. I also want my function to return an object, and a string is-an object, so returning a String is perfectly acceptable)
It's a JVM restriction. In order to override, the function signature must match exactly.
The only exception to this is that you can be covariant in the return type (as with Java). But this requires some trickery behind the scenes... As return types are considered part of the signature, the compiler must generate a forwarder method whenever you override with a covariant return.
And that's your answer, duplicate the trickery by hand!
in Y you must define: override def f(s:String):Object and have it delegate the call to def f(s:Object):String
On 30 August 2010 09:21, Sébastien Bocq <sebastien.bocq@gmail.com> wrote:
This compiles:
var f:String => Object = {a => a}
var g:Object => String = {a => a.toString}
f = g
but this doesn't:
class X {
def f(s:String):Object = s
}
class Y extends X {
override def f(s:Object):String = s.toString // Method f overrides nothing
}
Why have this limitation in Scala? Is that a JVM issue?
Thanks,
Sébastien
--
Kevin Wright
mail/google talk: kev.lee.wright@gmail.com
wave: kev.lee.wright@googlewave.com
skype: kev.lee.wright
twitter: @thecoda
Mon, 2010-08-30, 11:17
#3
Re: Why is it not allowed to override methods with contravaria
Kevin Wright wrote:
> The only exception to this is that you can be covariant in the return
> type (as with Java). But this requires some trickery behind the
> scenes... As return types are considered part of the signature, the
> compiler must generate a forwarder method whenever you override with a
> covariant return.
Is that a JVM thing? As far as I understand the Java language spec, the
return type is not part of the method signature.
Mon, 2010-08-30, 11:57
#4
Re: Why is it not allowed to override methods with contravaria
Sébastien Bocq wrote:
> class X {
> def f(s:String):Object = s
> }
>
> class Y extends X {
> override def f(s:Object):String = s.toString // Method f overrides
> nothing
> }
>
> Why have this limitation in Scala? Is that a JVM issue?
Suppose you would not have this limitation. In this situation:
class Parent {
def f(x: String) = "42"
def f(x: Int) = 42
}
class Child extends Parent {
override def f(x: Any) = 42
}
which superclass method would it override, the String or the Int one?
Mon, 2010-08-30, 12:17
#5
Re: Why is it not allowed to override methods with contravarian
Yes, it's a JVM thing.
One commonly used trick by obfuscators is to overload on just return type, it makes decompiling fun :)
On 30 August 2010 11:14, Andreas Flierl <andreas@flierl.eu> wrote:
--
Kevin Wright
mail/google talk: kev.lee.wright@gmail.com
wave: kev.lee.wright@googlewave.com
skype: kev.lee.wright
twitter: @thecoda
One commonly used trick by obfuscators is to overload on just return type, it makes decompiling fun :)
On 30 August 2010 11:14, Andreas Flierl <andreas@flierl.eu> wrote:
Kevin Wright <kev.lee.wright@gmail.com> wrote:
> The only exception to this is that you can be covariant in the return
> type (as with Java). But this requires some trickery behind the
> scenes... As return types are considered part of the signature, the
> compiler must generate a forwarder method whenever you override with a
> covariant return.
Is that a JVM thing? As far as I understand the Java language spec, the
return type is not part of the method signature.
--
Kevin Wright
mail/google talk: kev.lee.wright@gmail.com
wave: kev.lee.wright@googlewave.com
skype: kev.lee.wright
twitter: @thecoda
Mon, 2010-08-30, 12:47
#6
Re: Why is it not allowed to override methods with contravaria
both at the same time :D
Am 30.08.2010 12:51, schrieb Andreas Flierl:
> Sébastien Bocq wrote:
>> class X {
>> def f(s:String):Object = s
>> }
>>
>> class Y extends X {
>> override def f(s:Object):String = s.toString // Method f overrides
>> nothing
>> }
>>
>> Why have this limitation in Scala? Is that a JVM issue?
> Suppose you would not have this limitation. In this situation:
>
> class Parent {
> def f(x: String) = "42"
> def f(x: Int) = 42
> }
>
> class Child extends Parent {
> override def f(x: Any) = 42
> }
>
> which superclass method would it override, the String or the Int one?
>
>
>
Mon, 2010-08-30, 14:57
#7
Re: Why is it not allowed to override methods with contravarian
I noticed it when I tried to make an Option as an Iterable (c.f. below). I didn't understood why type inference
was not working properly and then wondered why the compiler did not
complained because map and flatMap where already defined in one of the
parent.
Now I know why.
Thanks you all for the answers.
sealed abstract class Opt[+A] extends Iterable[A]
case object Non extends Opt[Nothing] {
def iterator: Iterator[Nothing] = Iterator.empty
def map[B](f:Nothing => B):Opt[B] = Non
def flatMap[B](f:Nothing => Opt[B]):Opt[B] = Non
override def filter(p:Nothing => Boolean):Opt[Nothing] = Non
}
case class Som[+A](a:A) extends Opt[A] {
def iterator: Iterator[A] = Iterator.single(a)
def map[B](f:A => B):Opt[B] = Som(f(a))
def flatMap[B](f:A => Opt[B]):Opt[B] = f(a)
override def filter(p:A => Boolean):Opt[A] = if (p(a)) this else Non
}
object Opt {
def main(args : Array[String]) : Unit = {
println(Som(1) flatMap{_:Int => Som(1)}) // Som(1)
println(Som(1) flatMap{_:Int => Iterable(1, 2)}) // List(1, 2)
println(for {
y <- List(1, 2)
x:Int <- Som(y)
} yield (x, y)) // List((1,1), (2,2))
}
}
2010/8/30 HamsterofDeath <h-star@gmx.de>
Now I know why.
Thanks you all for the answers.
sealed abstract class Opt[+A] extends Iterable[A]
case object Non extends Opt[Nothing] {
def iterator: Iterator[Nothing] = Iterator.empty
def map[B](f:Nothing => B):Opt[B] = Non
def flatMap[B](f:Nothing => Opt[B]):Opt[B] = Non
override def filter(p:Nothing => Boolean):Opt[Nothing] = Non
}
case class Som[+A](a:A) extends Opt[A] {
def iterator: Iterator[A] = Iterator.single(a)
def map[B](f:A => B):Opt[B] = Som(f(a))
def flatMap[B](f:A => Opt[B]):Opt[B] = f(a)
override def filter(p:A => Boolean):Opt[A] = if (p(a)) this else Non
}
object Opt {
def main(args : Array[String]) : Unit = {
println(Som(1) flatMap{_:Int => Som(1)}) // Som(1)
println(Som(1) flatMap{_:Int => Iterable(1, 2)}) // List(1, 2)
println(for {
y <- List(1, 2)
x:Int <- Som(y)
} yield (x, y)) // List((1,1), (2,2))
}
}
2010/8/30 HamsterofDeath <h-star@gmx.de>
do you have an example where what you are trying to so makes sense?
do you have an example where what you are trying to so makes sense?
Am 30.08.2010 10:21, schrieb Sébastien Bocq: