Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save odersky/56323c309a186cffe9af to your computer and use it in GitHub Desktop.
Save odersky/56323c309a186cffe9af to your computer and use it in GitHub Desktop.
A simpler way to returning the "current" type in Scala.
/** This is in reference to @tploecat's blog http://tpolecat.github.io/2015/04/29/f-bounds.html
* where he compares F-bounded polymorphism and type classes for implementing "MyType".
*
* Curiously, the in my mind obvious solution is missing: Use abstract types.
*
* A lot of this material, including an argument against F-bounded for the use-case
* is discussed in:
*
* Kim B. Bruce, Martin Odersky, Philip Wadler:
* A Statically Safe Alternative to Virtual Types. ECOOP 1998: 523-549
*/
trait Pet {
type This <: Pet
def name: String
def renamed(newName: String): This
}
case class Fish(name: String, age: Int) extends Pet {
type This = Fish
def renamed(newName: String): Fish = copy(name = newName)
}
case class Kitty(name: String, age: Int) extends Pet {
type This = Kitty
def renamed(newName: String): Kitty = copy(name = newName)
}
object Test {
def esquire[A <: Pet](a: A): a.This = a.renamed(a.name + ", Esq.")
val f: Fish = esquire(new Fish("bob", 22))
}
@immediatus
Copy link

What about have more than one level of inheritance?

Something like:

class Kitty(val name: String, val age: Int) extends Pet {
  type This = Kitty
  def renamed(newName: String): Kitty = new Kitty(newName, age)
}

class Cat(name: String) extends Kitty(name, 2) {
  override type This = Cat
  override def renamed(newName: String): Cat = new Cat(newName)
}

error: overriding type This in class Kitty, which equals Kitty;

@accmltr
Copy link

accmltr commented Apr 3, 2024

What about have more than one level of inheritance?

Something like:

class Kitty(val name: String, val age: Int) extends Pet {
  type This = Kitty
  def renamed(newName: String): Kitty = new Kitty(newName, age)
}

class Cat(name: String) extends Kitty(name, 2) {
  override type This = Cat
  override def renamed(newName: String): Cat = new Cat(newName)
}

error: overriding type This in class Kitty, which equals Kitty;

I also want to know!

@accmltr
Copy link

accmltr commented Apr 5, 2024

Not the best, but you can override variables and methods with more specific types. Works for my situation:

trait Container {
  type T = Any
  val contents: Any
}

class Animal(val name: String)
class Fish(name: String) extends Animal(name)

class A extends Container {

  override val contents: Animal = new Animal("Animal")

}

class AA extends A {
  override val contents: Fish = new Fish("Fish")
}

class B extends Container {

  override val contents: Int = 3874

}

val a = new A
println(a.contents.name) // Animal

val b = new B
println(b.contents) // 3874

val aa = new AA
println(aa.contents.name) // Fish

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment