This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Type members vs. types of members

3 replies
Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
If we have
class Aclass B extends A
class X {    def foo: A = new A}
The foo declaration says my return type RT is A, if you override me then the new return type must be subtype of A. In other words it says if you override me the new type must be <: A, but if you don't then it is = A. The declaration say something like RT <:= A.
Would it make sense to provide this for type members? The nice thing about it that both type members and types of members (at least "return" types) which both belong to one family (the class) could be made to behave equivalently.
abstract class Y1 {    type T <: A}
class Y2 extends Y1 {    type T = A}
Y1 doesn't really need to be abstract (since 2.9?) but once T is set in Y2 it can't be overriden anymore. If it were possible to provide the same behavior, I think also the encoding of virtual classes could be simplified:
Example taken from: https://wiki.scala-lang.org/display/SIW/VirtualClassesDesign
/*  class A {     class C(x: Int) <: { var y = x ; def f(z: Int) = z + 1 }    class D(z) extends C(f(z)) { override def f(z:Int) = z + 2 }  }*/
  abstract class A {     type C <: CT
    trait CT { self: C => val x: Int; val y = x; def f(z:Int) = z + 1 }
    type D <: C with DT
    trait DT extends { self: D => def f(z:Int) = z + 2 }
    trait preDT extends { self: D => val z: Int; val x = f(z) }
    def newC(x: Int): C    def newD(x: Int): D  }
  class Afinal extends A {     type C = CT    type D = C with DT
    class CC(_x:Int) extends { val x = _x } with CT
    def newC(x:Int): C = new CC(x)
    class DC(_z:Int) extends { val z = _z } with preDT with CT with DT {       override def f(z:Int) = super.f(z)    }
    def newD(z:Int):D = new DC(z)  }
would become just:
  class A {     type C <:= CT
    trait CT { self: C => val x: Int; val y = x; def f(z:Int) = z + 1 }
    class CC(_x:Int) extends { val x = _x } with CT
    def newC(x:Int): C = new CC(x)
    type D <:= C with DT
    trait DT extends { self: D => def f(z:Int) = z + 2 }
    trait preDT extends { self: D => val z: Int; val x = f(z) }
    class DC(_z:Int) extends { val z = _z } with preDT with CT with DT {      override def f(z:Int) = super.f(z)    }
    def newD(z:Int):D = new DC(z)   }
With regards,Jan
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Type members vs. types of members


On Mon, Feb 20, 2012 at 1:51 AM, Jan Vanek <j3vanek@googlemail.com> wrote:
abstract class Y1 {    type T <: A}
class Y2 extends Y1 {    type T = A}
Y1 doesn't really need to be abstract (since 2.9?) but once T is set in Y2 it can't be overriden anymore.

Not since 2.9, it has always been like that.
You couldn't do this without attaching the same variance restrictions which apply to type parameters.  Because if Y1 looks like this
  abstract class Y1 { type T <: A ; def f(x: T) = x }
Then T, once fixed, must stay fixed.
Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
Re: Type members vs. types of members

On Mon, Feb 20, 2012 at 4:20 PM, Paul Phillips <paulp@improving.org> wrote:


On Mon, Feb 20, 2012 at 1:51 AM, Jan Vanek <j3vanek@googlemail.com> wrote:
abstract class Y1 {    type T <: A}
class Y2 extends Y1 {    type T = A}
Y1 doesn't really need to be abstract (since 2.9?) but once T is set in Y2 it can't be overriden anymore.

Not since 2.9, it has always been like that.
You couldn't do this without attaching the same variance restrictions which apply to type parameters.  Because if Y1 looks like this
  abstract class Y1 { type T <: A ; def f(x: T) = x }
Then T, once fixed, must stay fixed.

abstract class Y1 { type T <:= A ; def f(x: T) = x }
Using such T in invariant or contra-variant position would effectively fix T to A. A warning should be issued.
Regards, Jan
Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
Re: Type members vs. types of members
On 20.02.2012 16:47, Jan Vanek wrote:
KdAONFkSer1bC6vAJ1uCPU4yWx4NhHZLWvP61Q [at] mail [dot] gmail [dot] com" type="cite">
On Mon, Feb 20, 2012 at 4:20 PM, Paul Phillips <paulp [at] improving [dot] org" rel="nofollow">paulp@improving.org> wrote:


On Mon, Feb 20, 2012 at 1:51 AM, Jan Vanek <j3vanek [at] googlemail [dot] com" target="_blank" rel="nofollow">j3vanek@googlemail.com> wrote:
abstract class Y1 {     type T <: A }
class Y2 extends Y1 {     type T = A }
Y1 doesn't really need to be abstract (since 2.9?) but once T is set in Y2 it can't be overriden anymore.

Not since 2.9, it has always been like that.
You couldn't do this without attaching the same variance restrictions which apply to type parameters.  Because if Y1 looks like this
  abstract class Y1 { type T <: A ; def f(x: T) = x }
Then T, once fixed, must stay fixed.

abstract class Y1 { type T <:= A ; def f(x: T) = x }
Using such T in invariant or contra-variant position would effectively fix T to A. A warning should be issued.

This was a bit too rash... Thought about it on the way home, and need some more, thanks.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland