Type members vs. types of members

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

Re: Type members vs. types of members



On Mon, Feb 20, 2012 at 1:51 AM, Jan Vanek <j3vanek [at] googlemail [dot] 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.

Re: Type members vs. types of members


On Mon, Feb 20, 2012 at 4:20 PM, Paul Phillips <paulp [at] improving [dot] org> wrote:


On Mon, Feb 20, 2012 at 1:51 AM, Jan Vanek <j3vanek [at] googlemail [dot] 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

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 [at] improving [dot] org> wrote:


On Mon, Feb 20, 2012 at 1:51 AM, Jan Vanek <j3vanek [at] googlemail [dot] com" target="_blank" rel="nofollow">j3vanek [at] googlemail [dot] 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 © 2013 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland