When you have a parent:
abstract class Parent {
def something(arg: ???): Parent = ???
}
and
class Child extends Parent {}
I would like
val updatedChild = new Child().something(...)
updatedChild to be of type Child and not of type Parent, is it possible ?
One way to do it, is to parametrize the parent:
abstract class Parent[T <: Parent[T]] {
def something(arg: Foo): T
}
class Child(val foo: String) extends Parent[Child] {
def something(arg: String) = return new Child(arg)
}
Sometimes, you can also get away with using this.type:
class Parent {
def something(arg: Foo): this.type = this
}
class Child {
override def something(arg: Foo) = this
}
But the latter method only works if all you ever want to return is this (this.type is not Parent or Child, but a specific type that only has one instance - this).
Here is a proposal that actually compiles:
abstract class Parent[Repr <: Parent[Repr]] {
def something(arg: Int): Repr
}
This is something you can do, at least it's not explicitly discouraged. Standard collection library uses it a lot, see e.g. IterableLike as a typical example of such F-bounded polymorphism.
It seems that you can do :
class Parent[THIS <: Parent[THIS]] {
def something: THIS
}
And that seems to work.
I am not sure if this is something you should do tho.
Both Andrey's and Dima's answers cover one way to solve the problem using only oo-patterns.
However I would like to point out another approach called typeclasses (which is more common in functional languages), that would be helpful if you are planning to write generic functions using your interface.
First, instead of having a parent class, you have an interface that describes the operations that can be performed on instances of the typeclass.
trait Typeclass[T] {
def something(t: T)(arg: Foo): T
}
Then, you would define your types, this time they don't extend any parent class, thus they don't have to override nothing.
class Child {
...
}
Now, you have to prove that your type is an instance of the type class.
(A common place to do that is in the companion object of the class).
object Child {
implicit final val ChildTypeclass: Typeclass[Child] = new Typeclass[Child] {
override def something(child: Child)(arg: Foo): Child = ???
}
}
Finally, you define a generic method that can operate on any type T as long as there is an instance of your typeclass for that type.
def generic[T](t: T, arg: Foo)(implicit tt: Typeclass[T]): T =
tt.something(t)(arg)
Bonus, if you want to recover the "dot notation" you can add an Ops pattern to your Typeclass.
object syntax {
object typeclass {
implicit final class TypeclassOps[T](val t: T) extends AnyVal {
final def something(arg: Foo)(implicit tt: Typelcass[T]) =
tt.something(t)(arg)
}
}
}
import syntax.typeclasss._
def generic[T: Typelcass](t: T, arg: Foo): T
t.something(arg)
val newChild = generic(new Child, new Foo)
// newChild: Child = ???
Also, a common approach is to define the something method in your class and the typeclass instance forwards the call to the one defined in the class, this way you can use your method in any instance of Child without having to put all the typeclass machinery.
I must say that this is useful for very high-level abstractions to which you plan to provide instances for many types (even types outside your control like any of the standard collection types) and write very generic functions that can operate on any of these.
If not, F-bounded types seems like the more rational solution.
Related
I have a generic class that looks like:
class GenericClass[T <: AnyRef] {
def getHash(obj: T): String = obj.toString
}
As you can see, type T needs to have implemented the toString function in order for getHash to work properly. My question: is that possible to apply type bound/constraints so that type T always have toString implemented?
One way that I can think of is to use type class and context bound:
class GenericClass[T : ClassWithToString] {...}
trait ClassWithToString[T] {
def toString(t: T): String
}
implicit object SomeTypeWithToString extends ClassWithToString[SomeType] {
override def toString(a: SomeType): String = a.toString()
}
However, this approach requires clients to define new implicit objects whenever they want to use GenericClass with a new type, which is not ideal in my case. Especially given toString is a very common function that's being implemented by many types. Wanted to get some advice from you on how to solve this issue elegantly!
My motivation is I want an abstract class for sorting functions. Right now that looks like:
abstract class Sorter[A <% Ordered[A]]{
def apply(xs: Seq[A]): Seq[A]
}
But I'm not sure how to make a concrete instance of it, i.e.:
val mySort = new Sorter {
def apply(xs: Seq[A]) = { ... }
}
I suppose my question is two-fold:
Is my abstract class thing even correct?
How do I parameterize mySort?
View bounds are deprecated so if you don't have to use them you could write something simple like:
trait Sorter[A] {
def sort(xs: Seq[A])(implicit ord: Ordering[A]): Seq[A]
}
new Sorter[Int] {
override def sort(xs: Seq[X])(implicit ord: Ordering[X]): Seq[X] = {
xs.sorted
}
}
Sorter is a trait but could well be an abstract class. Parameterizing instance is done right before the brackets as shown in the example.
On a side note, in Scala I don't see the need for an abstract class (or trait) for ordering things.
The collections already define the sorted and sortBy methods. So when you have a collection col of A you can sort it with col.sorted provided you have an implicit Ordering[A] in scope.
It's up to you to figure out if Ordering is what you want or if abstract class and concrete implementation is required.
Keep in mind you can always implement you custom Ordering like:
new Ordering[Int] {
override def compare(x: X, y: X) = ???
}
Is there a way to define something like a typeclass (probably a trait?), and then later define an instance of that typeclass for a specific type, without modifying the original type definition?
For example, having the following code
class User {
}
trait Printable {
def print(): String
}
Can I somehow make the User class Printable separately from the class definition, without having to say class User extends Printable?
You create a trait for the typeclass you want to define e.g.
trait Printable[T] {
def print(p: T): String
}
then you can define implicit instances of this trait for the types you want:
object Instances {
implicit val UserPrintable = new Printable[User] {
def print(u: User) = u.name
}
}
in any functions that require the typeclass you can add an implicit parameter for the instance:
def writePrintable[T](p: T)(implicit pclass: Printable[T]) {
println(pclass.print(p))
}
then you can call writePrintable by importing the instance implementation e.g.
import Instances._
writePrintable(new User("user name"))
I'm doing an exercise to implement a functional binary-search-tree in Scala, following a similar pattern that I've seen used in Haskell. I have a structure that looks something like this:
trait TreeNode[A] {
def isLeaf: Boolean
def traverse: Seq[A]
...
}
case class Branch[A](value: A, left: TreeNode[A], right: TreeNode[A]) extends TreeNode[A] {
def isLeaf: Boolean = false
def traverse: Seq[A] = ...
...
}
case class Leaf[A]() extends TreeNode[A] {
def isLeaf: Boolean = true
def traverse: Seq[A] = Seq[A]()
...
}
I'd like to put a type constraint on A so that it will only accept objects that extend Ordered. It looks like I need to define a view bound on A ([A <% Ordered[A]]) on Branch and Leaf, as well as the TreeNode trait.. I can't do this on the TreeNode trait, however, because view bounds aren't accepted.
As I understand, <%-style view-bounds are syntactic sugar for an implicit definition, so there should be a way to write to define the bound manually within the TreeNode trait. I'm not sure how I'm supposed to do this, though. I've looked around a bit, but haven't gotten much further than that some sort of implicit needs to be defined.
Can anybody point me in the right direction? Am I approaching this from the wrong angle entirely?
The problem is that view bounds as well as context bounds are just syntactic sugar for specific types of implicit parameters. When applied to a type parameter of a generic class (as opposed to when applied to a generic method), these implicits are added to the constructor of the class.
Because traits have no constructor (or rather, only have a single parameterless constructor), there is nowhere to pass these implicit parameters and thus context bounds and view bounds are illegal on generic traits.
The simplest solution would be to turn TreeNode into an abstract class.:
abstract class TreeNode[A <% Ordered[A]]
Note that as advised by Ben James, using a context bound with an Ordering is usually better than a view bound with an Ordered (it is more general). However the problem is still the same: won't work on a trait.
If turning TreeNode into a class is not practical (say you need to mix it at various places in the type hierarchy), you can define an abstract method in TreeNode that will provide the implicit value (of type Ordered[A]) and have all the classes that extend it define it. This unfortunately more verbose and explicit, but you can't do much better in this case:
trait TreeNode[A] {
implicit protected def toOrdered: A => Ordered[A]
}
case class Branch[A<%Ordered[A]](value: A, left: TreeNode[A], right: TreeNode[A]) extends TreeNode[A] {
protected def toOrdered = implicitly[A => Ordered[A]]
}
case class Leaf[A<%Ordered[A]]() extends TreeNode[A] {
protected def toOrdered = implicitly[A => Ordered[A]]
}
Note that for a more concise definition, you could equivalently define Leaf like this:
case class Leaf[A](implicit protected val toOrdered: A => Ordered[A]) extends TreeNode[A]
You could provide the "evidence" that A is Ordered by requiring an abstract member of type Ordered[A] on the trait:
trait TreeNode[A] {
implicit val evidence: Ordered[A]
}
You would then be forced to provide this in any concrete subtypes, this proving that A is Ordered:
case class Leaf[A](value: A)(implicit ev: Ordered[A]) extends TreeNode[A] {
val evidence = ev
}
You might instead want to constrain A to a type which has an implicit Ordering[A] - this is not an inheritance relationship; it is more like a haskell typeclass. But the implementation in terms of the above technique would be the same.
#ben-james's answer is great, I would like improve it a bit to avoid redundant vals in classes.
The idea is to define implicit constructor parameter name the same as it is defined in trait that holds implicit value.
The idea is to avoid this line:
val evidence = ev
Here is a complete example (gist)
trait PrettyPrinted[A] extends (A => String)
object PrettyPrinted {
def apply[A](f: A => String): PrettyPrinted[A] = f(_)
}
trait Printable[A] {
implicit def printer: PrettyPrinted[A]
}
// implicit parameter name is important
case class Person(name: String, age: Int)
(implicit val printer: PrettyPrinted[Person])
extends Printable[Person]
object Person {
implicit val printer: PrettyPrinted[Person] =
PrettyPrinted { p =>
s"Person[name = ${p.name}, age = ${p.age}]"
}
}
// works also with regular classes
class Car(val name: String)
(implicit val printer: PrettyPrinted[Car])
extends Printable[Car]
object Car {
implicit val printer: PrettyPrinted[Car] =
PrettyPrinted { c =>
s"Car[name = ${c.name}]"
}
}
I'm looking for a way to define a method that returns a type T where T = the type of the subclass.
I know I could possibly do this using abstract types, but dislike the overhead of having to redefine T for each subclass.
Some sample code:
object Helper {
def help[A <: MyClass](cls: A): Option[A] = { cls.foo() map { _.asInstanceOf[A] } }
}
class MyClass {
type T <: MyClass
def foo(): Option[T] = Some(this.asInstanceOf[T])
}
class ChildClass extends MyClass {
type T = ChildClass
}
Possibly a new language feature has made this easier? Or can I use this.type in some way? It's important to me that I be able to define a helper class that can call into foo in this way.
If you are always returning this, then you can indeed have as return type this.type. Or have you tried it already?
this.type is especially useful e.g. when you want to chain calls to the same object, or provide a static guarantee that you will be returning the same object (and not a copy). For instance, Buffers in Scala have the append operation :+, which returns a Buffer[A], and +=, which returns this.type. The former duplicates the mutable sequence; the latter guarantees that you update the original object.
To follow up on Jean-Phillippe's answer, who wrote his exactly when I'm writing mine, here's the code:
trait SomeTrait {
def foo: this.type = this
}
class UsesTrait extends SomeTrait
object Main {
def main(args: Array[String]) {
println((new UsesTrait).foo) // prints UsesTrait#<hash value>
}
}
I found the following idiom useful:
class MyClass[T] {
self: T =>
def foo(): Option[T] = Some(this)
}
class ChildClass extends MyClass[ChildClass]
new ChildClass().foo()
//--> Option[ChildClass] = Some(ChildClass#2487b1)