SIP suggestion: Add a This type to allow superclass method to return subclass type

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

SIP suggestion: Add a This type to allow superclass method to return subclass type

Jxtps
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Daniel Armak

I also feel it would be very useful to provide a more convenient syntax for F-bounds. Most importantly, traits with F-bounds wouldn't be needlessly generic anymore, spreading existential types everywhere. But to accomplish this, we really need to allow This everywhere the F-bound argument can be used today: in method argument types, field types, type arguments, etc. And why restrict it?

To maintain backward compatibility, it could be named something like this.subtype.

The spec seems simple:

  • In a type that uses this.subtype, it behaves as some unknown subtype of the current type.
  • In a type A that extends B, an expression defined in B which type this.subtype when viewed from A has some unknown subtype of A.

But the implementation would require new info in the compiled class.

-- 
Daniel Armak

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Justin du coeur
In reply to this post by Jxtps
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <[hidden email]> wrote:
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Alex Cruise-2
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:


-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <[hidden email]> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <[hidden email]> wrote:
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Daniel Armak

They discuss various alternatives, but in the end the OP settles for F-bounds. And we know from experience that F-bounds are useful and are often used, and that the introduced genericity (and verbosity) are harmful. A syntax deliberately equivalent to F-bounds would be simple to specify and to understand.

The problem is how to represent this in the Scala type system. F-bounds can’t be implemented with abstract type members instead of type arguments:

trait Tr { self =>
    type Self <: Tr { type Self <: self.Self }
}

We cannot say here self: Self as we would in the equivalent type-argument situation. So even if we enforce this at compile time, other users of the type wouldn’t know about it.

We could have the new syntax be equivalent to this:

trait Tr[F <: Tr[F]] { self: F =>
    def copy(): F
}
object Tr {
    type Trx = Tr[F] forSome{ type F <: Tr[F] }
}
import Tr.Trx

class C extends Tr[C] {
    override def copy(): C = new C
}

// Use site
val tr: Trx = new C
val copy: Trx = tr.copy()

This much can be generated with a macro annotation today, and may even be worth writing by hand when we use F-bounds. If Tr has extra generic arguments, then so will Trx.

C still has to extend Tr[C], but that’s not a big a problem IMO. Everyone else needs to use Tr.Trx and not Tr, which is annoying but less annoying than using Tr[_] (which would have made the code above not compile).

What am I missing? There must be something, or this would already by accepted practice for F-bounds.


Daniel Armak

On Tue, Apr 26, 2016 at 1:22 AM, Alex Cruise <[hidden email]> wrote:
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:


-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <[hidden email]> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <[hidden email]> wrote:
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Ahmad Salim Al-Sibahi
There was recently a paper in ACM Transactions on Programming Languages (TOPLAS) discussing a nice and correct way to add This types to a language if people are interested:


Ryu, S. (2016). ThisType for Object-Oriented Languages. ACM Transactions on Programming Languages and Systems, 38(3), 1–66. http://doi.org/10.1145/2888392


Den tirsdag den 26. april 2016 kl. 11.25.21 UTC+2 skrev Daniel Armak:

They discuss various alternatives, but in the end the OP settles for F-bounds. And we know from experience that F-bounds are useful and are often used, and that the introduced genericity (and verbosity) are harmful. A syntax deliberately equivalent to F-bounds would be simple to specify and to understand.

The problem is how to represent this in the Scala type system. F-bounds can’t be implemented with abstract type members instead of type arguments:

trait Tr { self =>
    type Self <: Tr { type Self <: self.Self }
}

We cannot say here self: Self as we would in the equivalent type-argument situation. So even if we enforce this at compile time, other users of the type wouldn’t know about it.

We could have the new syntax be equivalent to this:

trait Tr[F <: Tr[F]] { self: F =>
    def copy(): F
}
object Tr {
    type Trx = Tr[F] forSome{ type F <: Tr[F] }
}
import Tr.Trx

class C extends Tr[C] {
    override def copy(): C = new C
}

// Use site
val tr: Trx = new C
val copy: Trx = tr.copy()

This much can be generated with a macro annotation today, and may even be worth writing by hand when we use F-bounds. If Tr has extra generic arguments, then so will Trx.

C still has to extend Tr[C], but that’s not a big a problem IMO. Everyone else needs to use Tr.Trx and not Tr, which is annoying but less annoying than using Tr[_] (which would have made the code above not compile).

What am I missing? There must be something, or this would already by accepted practice for F-bounds.


Daniel Armak

On Tue, Apr 26, 2016 at 1:22 AM, Alex Cruise <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="cjXKZDo_BwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">al...@...> wrote:
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:

<a href="http://comments.gmane.org/gmane.comp.lang.scala.debate/4871" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcomments.gmane.org%2Fgmane.comp.lang.scala.debate%2F4871\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHpgMFl_1I7l4H5ixUCSoNm9-JbPQ&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcomments.gmane.org%2Fgmane.comp.lang.scala.debate%2F4871\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHpgMFl_1I7l4H5ixUCSoNm9-JbPQ&#39;;return true;">http://comments.gmane.org/gmane.comp.lang.scala.debate/4871

-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="cjXKZDo_BwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">jduc...@...> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="cjXKZDo_BwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">jxtp...@...> wrote:
<a href="https://tpolecat.github.io/2015/04/29/f-bounds.html" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Ftpolecat.github.io%2F2015%2F04%2F29%2Ff-bounds.html\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHoq2YJi_DUFzgZkLnn-WJuGMnc1Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Ftpolecat.github.io%2F2015%2F04%2F29%2Ff-bounds.html\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHoq2YJi_DUFzgZkLnn-WJuGMnc1Q&#39;;return true;">https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="cjXKZDo_BwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-debate...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="cjXKZDo_BwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-debate...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="cjXKZDo_BwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-debate...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Kevin Wright-3
I’ll wait for it to appear on arxiv.  Paywalls and broad discourse of new ideas don’t make for happy bedfellows.


On 26 April 2016 at 16:09, Ahmad Salim Al-Sibahi <[hidden email]> wrote:
There was recently a paper in ACM Transactions on Programming Languages (TOPLAS) discussing a nice and correct way to add This types to a language if people are interested:


Ryu, S. (2016). ThisType for Object-Oriented Languages. ACM Transactions on Programming Languages and Systems, 38(3), 1–66. http://doi.org/10.1145/2888392


Den tirsdag den 26. april 2016 kl. 11.25.21 UTC+2 skrev Daniel Armak:

They discuss various alternatives, but in the end the OP settles for F-bounds. And we know from experience that F-bounds are useful and are often used, and that the introduced genericity (and verbosity) are harmful. A syntax deliberately equivalent to F-bounds would be simple to specify and to understand.

The problem is how to represent this in the Scala type system. F-bounds can’t be implemented with abstract type members instead of type arguments:

trait Tr { self =>
    type Self <: Tr { type Self <: self.Self }
}

We cannot say here self: Self as we would in the equivalent type-argument situation. So even if we enforce this at compile time, other users of the type wouldn’t know about it.

We could have the new syntax be equivalent to this:

trait Tr[F <: Tr[F]] { self: F =>
    def copy(): F
}
object Tr {
    type Trx = Tr[F] forSome{ type F <: Tr[F] }
}
import Tr.Trx

class C extends Tr[C] {
    override def copy(): C = new C
}

// Use site
val tr: Trx = new C
val copy: Trx = tr.copy()

This much can be generated with a macro annotation today, and may even be worth writing by hand when we use F-bounds. If Tr has extra generic arguments, then so will Trx.

C still has to extend Tr[C], but that’s not a big a problem IMO. Everyone else needs to use Tr.Trx and not Tr, which is annoying but less annoying than using Tr[_] (which would have made the code above not compile).

What am I missing? There must be something, or this would already by accepted practice for F-bounds.


Daniel Armak

On Tue, Apr 26, 2016 at 1:22 AM, Alex Cruise <[hidden email]> wrote:
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:


-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <[hidden email]> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <[hidden email]> wrote:
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?




--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Adriaan Moors-7
In reply to this post by Daniel Armak
If we're talking about syntactic sugar for "the abstract type upper bounded by the current class as seen from the given prefix", that would indeed not be too hard but it would only be sound in covariant positions. Not convinced the utility outweighs the cost. 

Something more ambitious quickly becomes intractable (needing exact types, some way of disconnecting MyType from the hierarchy when you get into implementation subclasses etc)

On Tuesday, April 26, 2016, Daniel Armak <[hidden email]> wrote:

They discuss various alternatives, but in the end the OP settles for F-bounds. And we know from experience that F-bounds are useful and are often used, and that the introduced genericity (and verbosity) are harmful. A syntax deliberately equivalent to F-bounds would be simple to specify and to understand.

The problem is how to represent this in the Scala type system. F-bounds can’t be implemented with abstract type members instead of type arguments:

trait Tr { self =>
    type Self <: Tr { type Self <: self.Self }
}

We cannot say here self: Self as we would in the equivalent type-argument situation. So even if we enforce this at compile time, other users of the type wouldn’t know about it.

We could have the new syntax be equivalent to this:

trait Tr[F <: Tr[F]] { self: F =>
    def copy(): F
}
object Tr {
    type Trx = Tr[F] forSome{ type F <: Tr[F] }
}
import Tr.Trx

class C extends Tr[C] {
    override def copy(): C = new C
}

// Use site
val tr: Trx = new C
val copy: Trx = tr.copy()

This much can be generated with a macro annotation today, and may even be worth writing by hand when we use F-bounds. If Tr has extra generic arguments, then so will Trx.

C still has to extend Tr[C], but that’s not a big a problem IMO. Everyone else needs to use Tr.Trx and not Tr, which is annoying but less annoying than using Tr[_] (which would have made the code above not compile).

What am I missing? There must be something, or this would already by accepted practice for F-bounds.


Daniel Armak

On Tue, Apr 26, 2016 at 1:22 AM, Alex Cruise <<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;alex@cluonflux.com&#39;);" target="_blank">alex@...> wrote:
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:


-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;jducoeur@gmail.com&#39;);" target="_blank">jducoeur@...> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;jxtps435@gmail.com&#39;);" target="_blank">jxtps435@...> wrote:
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;scala-debate%2Bunsubscribe@googlegroups.com&#39;);" target="_blank">scala-debate+unsubscribe@....
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;scala-debate%2Bunsubscribe@googlegroups.com&#39;);" target="_blank">scala-debate+unsubscribe@....
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;scala-debate%2Bunsubscribe@googlegroups.com&#39;);" target="_blank">scala-debate+unsubscribe@....
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;scala-debate%2Bunsubscribe@googlegroups.com&#39;);" target="_blank">scala-debate+unsubscribe@....
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Viktor Klang

Ergonomically (read syntactically), I'd probably prefer:
this.type & this#type

--
Cheers,

On Apr 26, 2016 7:10 PM, "Adriaan Moors" <[hidden email]> wrote:
If we're talking about syntactic sugar for "the abstract type upper bounded by the current class as seen from the given prefix", that would indeed not be too hard but it would only be sound in covariant positions. Not convinced the utility outweighs the cost. 

Something more ambitious quickly becomes intractable (needing exact types, some way of disconnecting MyType from the hierarchy when you get into implementation subclasses etc)

On Tuesday, April 26, 2016, Daniel Armak <[hidden email]> wrote:

They discuss various alternatives, but in the end the OP settles for F-bounds. And we know from experience that F-bounds are useful and are often used, and that the introduced genericity (and verbosity) are harmful. A syntax deliberately equivalent to F-bounds would be simple to specify and to understand.

The problem is how to represent this in the Scala type system. F-bounds can’t be implemented with abstract type members instead of type arguments:

trait Tr { self =>
    type Self <: Tr { type Self <: self.Self }
}

We cannot say here self: Self as we would in the equivalent type-argument situation. So even if we enforce this at compile time, other users of the type wouldn’t know about it.

We could have the new syntax be equivalent to this:

trait Tr[F <: Tr[F]] { self: F =>
    def copy(): F
}
object Tr {
    type Trx = Tr[F] forSome{ type F <: Tr[F] }
}
import Tr.Trx

class C extends Tr[C] {
    override def copy(): C = new C
}

// Use site
val tr: Trx = new C
val copy: Trx = tr.copy()

This much can be generated with a macro annotation today, and may even be worth writing by hand when we use F-bounds. If Tr has extra generic arguments, then so will Trx.

C still has to extend Tr[C], but that’s not a big a problem IMO. Everyone else needs to use Tr.Trx and not Tr, which is annoying but less annoying than using Tr[_] (which would have made the code above not compile).

What am I missing? There must be something, or this would already by accepted practice for F-bounds.


Daniel Armak

On Tue, Apr 26, 2016 at 1:22 AM, Alex Cruise <[hidden email]> wrote:
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:


-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <[hidden email]> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <[hidden email]> wrote:
https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?






--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: SIP suggestion: Add a This type to allow superclass method to return subclass type

Ahmad Salim Al-Sibahi
In reply to this post by Kevin Wright-3
I didn't notice since I have access to ACM Digital Library.
Here is a link to earlier related work (from the author's website http://plrg.kaist.ac.kr/doku.php?id=research:publications):
http://plrg.kaist.ac.kr/lib/exe/fetch.php?media=research:publications:thisjava-aplas-final.pdf

Den tirsdag den 26. april 2016 kl. 17.22.31 UTC+2 skrev Kevin Wright:
I’ll wait for it to appear on arxiv.  Paywalls and broad discourse of new ideas don’t make for happy bedfellows.


On 26 April 2016 at 16:09, Ahmad Salim Al-Sibahi <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="RG6fELhSBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">asal.t...@...> wrote:
There was recently a paper in ACM Transactions on Programming Languages (TOPLAS) discussing a nice and correct way to add This types to a language if people are interested:


Ryu, S. (2016). ThisType for Object-Oriented Languages. ACM Transactions on Programming Languages and Systems, 38(3), 1–66. <a href="http://doi.org/10.1145/2888392" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fdoi.org%2F10.1145%2F2888392\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEfFO7g0SeSuDIAI0psgTsqBaN2gg&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fdoi.org%2F10.1145%2F2888392\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEfFO7g0SeSuDIAI0psgTsqBaN2gg&#39;;return true;">http://doi.org/10.1145/2888392


Den tirsdag den 26. april 2016 kl. 11.25.21 UTC+2 skrev Daniel Armak:

They discuss various alternatives, but in the end the OP settles for F-bounds. And we know from experience that F-bounds are useful and are often used, and that the introduced genericity (and verbosity) are harmful. A syntax deliberately equivalent to F-bounds would be simple to specify and to understand.

The problem is how to represent this in the Scala type system. F-bounds can’t be implemented with abstract type members instead of type arguments:

trait Tr { self =>
    type Self <: Tr { type Self <: self.Self }
}

We cannot say here self: Self as we would in the equivalent type-argument situation. So even if we enforce this at compile time, other users of the type wouldn’t know about it.

We could have the new syntax be equivalent to this:

trait Tr[F <: Tr[F]] { self: F =>
    def copy(): F
}
object Tr {
    type Trx = Tr[F] forSome{ type F <: Tr[F] }
}
import Tr.Trx

class C extends Tr[C] {
    override def copy(): C = new C
}

// Use site
val tr: Trx = new C
val copy: Trx = tr.copy()

This much can be generated with a macro annotation today, and may even be worth writing by hand when we use F-bounds. If Tr has extra generic arguments, then so will Trx.

C still has to extend Tr[C], but that’s not a big a problem IMO. Everyone else needs to use Tr.Trx and not Tr, which is annoying but less annoying than using Tr[_] (which would have made the code above not compile).

What am I missing? There must be something, or this would already by accepted practice for F-bounds.


Daniel Armak

On Tue, Apr 26, 2016 at 1:22 AM, Alex Cruise <[hidden email]> wrote:
A discussion from the past that should provide some context to this MyType vs. F-bounded polymorphism debate:

<a href="http://comments.gmane.org/gmane.comp.lang.scala.debate/4871" rel="nofollow" target="_blank" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcomments.gmane.org%2Fgmane.comp.lang.scala.debate%2F4871\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHpgMFl_1I7l4H5ixUCSoNm9-JbPQ&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcomments.gmane.org%2Fgmane.comp.lang.scala.debate%2F4871\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHpgMFl_1I7l4H5ixUCSoNm9-JbPQ&#39;;return true;">http://comments.gmane.org/gmane.comp.lang.scala.debate/4871

-0xe1a

On Mon, Apr 25, 2016 at 12:07 PM, Justin du coeur <[hidden email]> wrote:
+1 from the just-a-user viewpoint: I wind up needing F-bounds moderately often, and I *hate* the side-effects they wind up imposing on my code.  Having a solution that didn't introduce pointless genericity would be a big win for my codebase...

On Mon, Apr 25, 2016 at 2:17 PM, Jxtps <[hidden email]> wrote:
<a href="https://tpolecat.github.io/2015/04/29/f-bounds.html" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Ftpolecat.github.io%2F2015%2F04%2F29%2Ff-bounds.html\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHoq2YJi_DUFzgZkLnn-WJuGMnc1Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Ftpolecat.github.io%2F2015%2F04%2F29%2Ff-bounds.html\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHoq2YJi_DUFzgZkLnn-WJuGMnc1Q&#39;;return true;">https://tpolecat.github.io/2015/04/29/f-bounds.html has a great discussion about:

A common question on the #scala IRC channel is

I have a type hierarchy … how do I declare a supertype method that returns the “current” type?

The aesthetics are however a bit challenging - either you use an F-bounded type, Pet[A <: Pet[A]], which can "leak", or you use a TypeClass, which leads to a lot of boilerplate for each specific class.

Suggestion: add the concept of a "This" type, which denotes the type of the runtime instance, as known at compile time.

Example:

class StringBuilder {
  def append(s:String):This = {
    //...
    this
  }
}

trait Fancy {
  self: StringBuilder =>
  def fancy(s:String):This = {
    //...
    append(s)
  }
}

class FancyStringBuilder extends StringBuilder with Fancy {
}

val f = new FancyStringBuilder()
f.append("hello").fancy("world!")

where returning This allows the last chained call to happen - normally f.append() would return StringBuilder, which knows nothing about fancy(), and we'd get an error.


The compiler would only use & enforce the type as known at compile time, so this doesn't work:

val f:StringBuilder = new FancyStringBuilder()
f.append("hello").fancy("world!") // => compilation error, StringBuilder doesn't have fancy()


Conceptually, the calls would be very similar to:

val f = new FancyStringBuilder()
f.append("hello").asInstanceOf[FancyStringBuilder].fancy("world!")

Where the cast is guaranteed to succeed thanks to appen() returning This.


A method returning This has to either return this, return the result of another method that returns This, or be in a final class and return an instance of that class.


So in tpolecat's first example, you'd be allowed to do (changes highlighted):
trait Pet {
  def name: String
  def renamed(newName: String): This
}

final case class Fish(name: String, age: Int) extends Pet {
  def renamed(newName: String): This = copy(name = newName)
}

While I'm only really envisioning the This type being used as a method return type, and being very strict in terms of what can be returned from such methods (i.e. pretty much only this), it might be both possible & desirable to expand the scope to include method parameters, and more lenient returns.

Allowing the This type to be used in e.g. collections, or getting passed along in type definitions (class Fish extends Pet[This]) sounds dangerous to me, but maybe that could be useful as well?

Thoughts?




--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.