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) = ???
}
Related
I am translating the Haskell code in https://sebfisch.github.io/haskell-regexp/regexp-play.pdf in Scala for self study.
I translated "class Semiring" (page 2) in this way:
trait Semiring[S] {
def zero: S
def one: S
def add(a: S, b: S): S
def mult(a: S, b: S): S
}
and the related class SemiringI (page 7) in this way:
trait SemiringI[S] extends Semiring[S] {
def index: Int => S
}
I had then to provide instances for specific type parameters, so I tried to proceed in what I think is the canonical way, i.e., defining them as implicit vals.
implicit val semiringLeftmost = new Semiring[LeftmostT] {
// ...implementation of zero, one, add, mult...
}
However, I had some problems when I had to define a SemiringI instance for LeftmostT:
implicit val semiringILeftmost = new SemiringI[LeftmostT] {
// ...implementation of zero, one, add, mult (same as for Semiring[LeftmostT])
// ...implementation of index
}
It seemed to me I had to repeat the implementations of the functions already defined in Semiring[LeftmostT], that, of course, would not have been scalable.
I searched the web for answers, but I was not able to find them.
For example, in https://www.slideshare.net/jdegoes/scalaz-8-a-whole-new-game (slide 7) MonoidInt does not reuse the definition of append from Semigroup, as I expected.
At the end, I managed to find a way to proceed, namely:
// traits Semiring[S] and SemiringI[S] defined as above
class semiringLeftmostC extends Semiring[LeftmostT] {
// ...implementation of zero, one, add, mult...
}
implicit val semiringLeftmost = new semiringLeftmostC()
class semiringILeftmostC extends semiringLeftmostC with SemiringI[LeftmostT] {
// ...implementation of index
}
implicit val semiringILeftmost = new semiringILeftmostC()
but I am not sure it is the best one.
Can someone please explain to me whether there are other possibilities to reach the same goals, i.e., reusing code in hierarchies of typeclass instances?
Thanks in advance.
Thanks to this post, and the advent of Scala 3, I was able to write a concise version of the class hierarchy:
trait Semiring[S] {
def zero: S
def one: S
def add(a: S, b: S): S
def mult(a: S, b: S): S
}
trait SemiringI[S] extends Semiring[S] {
def index(i: Int): S
}
given semiringLeftmost: Semiring[LeftmostT] with {
// implementation of Semiring functions
}
given semiringILeftmost: SemiringI[LeftmostT] with {
export semiringLeftmost.*
override def index(i: Int): LeftmostT = ??? // actual implementation not relevant
}
I can infer by the mentioned post, however, that there seems to be no consensus on how to encode typeclass hierarchies in Scala 3. The official documentation examples I found seem to redefine functions in the derived traits (https://dotty.epfl.ch/docs/reference/contextual/type-classes.html).
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.
I have the following code snippet:
abstract class Foo[T <: Foo[T]] { self: T =>
def bar(x: T): T
def newFoo: Foo[T] = {
new Foo[T] { self: T =>
// ...
}
}
}
I have a need to generate a new instance of Foo within a method of my abstract class. Can anyone advise me on how best to approach this?
Thanks,
Hadil
The self-type self: T => implies that your Foo[T] must also be a T. new Foo[T] { ... } isn't an instance of T for any arbitrary T that makes up Foo[T]. You also can't add a self-type to an anonymous class like new Foo[T] { ... }, because it doesn't make sense. Either the concrete class is or isn't a T at that point.
Constructing a method like def newFoo: Foo[T] in a type-safe way isn't really possible with the self-type in place, because you'd need to know how to construct an arbitrary T. You might be able to do what you want with reflection, when each T has the same constructor.
import scala.reflect._
abstract class Foo[T <: Foo[T] : ClassTag] { self: T =>
def bar(x: T): T
def newFoo: Foo[T] = classTag[T].runtimeClass.newInstance.asInstanceOf[T]
}
class Bar extends Foo[Bar] {
def bar(x: Bar): Bar = x
}
scala> val b = new Bar
b: Bar = Bar#2a2d45ba
scala> b.newFoo
res1: Foo[Bar] = Bar#146ba0ac
This ceases to work when there are constructor parameters:
case class Baz(i: Int) extends Foo[Baz] {
def bar(x: Baz): Baz = x
}
scala> val baz = new Baz(0)
baz: Baz = Baz(0)
scala> baz.newFoo
java.lang.InstantiationException: Baz
at java.lang.Class.newInstance(Class.java:427)
at Foo.newFoo(<console>:16)
Well, you do not know the concrete class where Foo will be inherited in the future. So especially, you do not know which constructor parameters this class will have and how to supply arguments for them. If you really would want to do this, you would have to make some assumptions (that you cannot enforce at compile time) to achieve this.
So what you probably should do, is, leave this method abstract and implement it in a subclass. If this is not an option, you probably have some issues with your overall class design. Better present here what you want to model and ask for help.
If you assume, that the constructor of the concrete class won't have any parameters, you can implement newFoo just as
def newFoo = this.getClass.newInstance
There is no need for classTags or other fancy stuff.
What I would like to do is this:
trait Addable[T]{
def plus(x: T): T
}
trait AddableWithBounds[T] extends Addable[T] {
abstract override def plus(x: T): T = limitToBounds(super.plus(x))
def limitToBounds(x: T): T = ... //Some bounds checking
}
class Impl(num: Int) extends AddableWithBounds[Impl] {
override def plus(x: Impl) = new Impl(num + x.num)
}
Reading through various posts it would seem that the reason this is not possible is that after class linearization the stacked trait is only looking in classes to its right for implementations of super.plus(x: T)
That is a technical argument though and I'm interested in the question: Is there a fundamental reason why the implementation could not be taken from the base class? Because as you can see in this example it is not possible to implement the plus method before knowing the actual data type that needs to be added but afaic implementing bounds checking in a trait seems reasonable.
Just as an idea: If the problem is that in this case it is unclear which plus is being overridden in the base class maybe a scope identifier like
def Addable[Impl].plus(x: Impl) = new Impl(num + x.num)
would help.
I would avoid overriding and reliance on some super/sub-type invocation. Why not just implement plus and ask sub-types to provide an auxiliary abstract method:
trait Addable[T] {
def plus(x: T): T
}
trait AddableWithBounds[T] extends Addable[T] {
final def plus(x: T): T = limitToBounds(plusImpl(x))
protected def plusImpl(x: T): T
def limitToBounds(x: T): T = ??? //Some bounds checking
}
class Impl(num: Int) extends AnyRef with AddableWithBounds[Impl] {
protected def plusImpl(x: Impl): Impl = ???
}
You're asking: if super.f is abstract (or "incomplete") after mixin, please just pick a concrete f to serve. Maybe you're saying, only if there's exactly one such f, and it's defined in the current template.
One problem is that if the abstract f is called during initialization, and calls the concrete f in the subclass, the initializer for the subclass hasn't run yet.
This is common gotcha for template methods. I think the Josh Bloch book says don't do that.
But the person writing the stackable trait has no way of knowing that a super was transformed in this way.
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}]"
}
}