Custom Collection extending on Set in Scala - scala

This is a follow-up on the below question:
How to create a custom collection that extends on Sets In Scala?
I have a basic class that extends on the Set collection and most of the functions like filter, collect and others are working :
import scala.collection._
class TestSet[A]
extends mutable.Set[A]
with mutable.SetOps[A, mutable.Set, TestSet[A]] {
private var data = mutable.Set.empty[A]
override protected def fromSpecific(coll: IterableOnce[A]): TestSet[A] = TestSet.from(coll)
override protected def newSpecificBuilder: mutable.Builder[A, TestSet[A]] = TestSet.newBuilder
override def empty: TestSet[A] = TestSet.empty
override def clear(): Unit = {
data = mutable.Set.empty
}
override def subtractOne(elem: A): TestSet.this.type = {
data -= elem
this
}
override def addOne(elem: A): TestSet.this.type = {
data += elem
this
}
override def contains(elem: A): Boolean = data.contains(elem)
override def iterator: Iterator[A] = {
data.iterator
}
}
object TestSet {
def empty[A] = new TestSet[A]
def from[A](source: IterableOnce[A]): TestSet[A] =
source match {
case pm: TestSet[A] => pm
case _ => (newBuilder ++= source).result()
}
def apply[A](elem: A*): TestSet[A] = from(elem)
def newBuilder[A]: mutable.Builder[A, TestSet[A]] =
new mutable.GrowableBuilder[A, TestSet[A]](empty)
import scala.language.implicitConversions
implicit def toFactory[A](self: this.type): Factory[A, TestSet[A]] =
new Factory[A, TestSet[A]] {
def fromSpecific(it: IterableOnce[A]): TestSet[A] = self.from(it)
def newBuilder: mutable.Builder[A, TestSet[A]] = self.newBuilder
}
}
It might not be possible but I originally wanted SetOps with the following types mutable.SetOps[A, TestSet, TestSet[A]] instead of mutable.SetOps[A, mutable.Set, TestSet[A]], but I am having trouble redefining iterableFactory.
A working snippet can be found here: https://scastie.scala-lang.org/4Qi8ZueDTpScDwxDfqptew

The scaladoc of IterableFactory says "Base trait for companion objects..." which is a hint that the companion of your TestSet should implement that trait.
All you need to do is add...
object TestSet extends IterableFactory[TestSet] {
// ...
}
...and then remove your def apply[A](elem: A*): TestSet[A] from the companion (because that is already inherited from IterableFactory).
Then you'd do the following in your class:
class TestSet[A]
extends mutable.Set[A]
with mutable.SetOps[A, TestSet, TestSet[A]] {
// ...
// returns your companion object
override def iterableFactory: IterableFactory[TestSet] = TestSet
// ...
}
And that's all it would need.
(This is so simple because you already implemented all abstract members of IterableFactory[TestSet] in your companion object - it would not work if the companion were empty.)

Related

How to create a custom collection that extends on Sets In Scala?

I want to create a new custom Scala collection from existing Set Collection which I can later extend with some additional functions.
For the moment, I am trying to make it behave as the standard collection Set. I tried the following link : https://docs.scala-lang.org/overviews/core/custom-collections.html where they have a custom collection that extends on Map. However extending on Set seems a bit different and I am having a ton of type incompatibility that I am not able to resolve.
Here's my starting code : the parts I am not able to define are addOne, substractOne, contains and iterator.
import scala.collection._
class TestSet[A]
extends mutable.Set[A]
with mutable.SetOps[A, mutable.Set, TestSet[A]] {
override def empty: TestSet[A] = new TestSet
// Members declared in scala.collection.mutable.Clearable
override def clear(): Unit = immutable.Set.empty
// Members declared in scala.collection.IterableOps
override protected def fromSpecific(coll: IterableOnce[A]): TestSet[A] = TestSet.from(coll)
override protected def newSpecificBuilder: mutable.Builder[A, TestSet[A]] = TestSet.newBuilder
override def className = "TestSet"
//override def subtractOne(elem: A): TestSet.this.type = ???
//override def addOne(elem: A): TestSet.this.type = ???
//override def contains(elem: A): Boolean = ???
//override def iterator: Iterator[A] = {
//}
}
object TestSet {
def empty[A] = new TestSet[A]
def from[A](source: IterableOnce[A]): TestSet[A] =
source match {
case pm: TestSet[A] => pm
case _ => (newBuilder ++= source).result()
}
def apply[A](elem: A*): TestSet[A] = from(elem)
def newBuilder[A]: mutable.Builder[A, TestSet[A]] =
new mutable.GrowableBuilder[A, TestSet[A]](empty)
import scala.language.implicitConversions
implicit def toFactory[A](self: this.type): Factory[A, TestSet[A]] =
new Factory[A, TestSet[A]] {
def fromSpecific(it: IterableOnce[A]): TestSet[A] = self.from(it)
def newBuilder: mutable.Builder[A, TestSet[A]] = self.newBuilder
}
}
I will interpret your question as "I want to do something similar as the Map-example from https://docs.scala-lang.org/overviews/core/custom-collections.html for a mutable Set but now am stuck with this code" and will try to answer that (ignoring any other aspects of your question).
What you need to understand is that mutable.Set and mutable.SetOps are just traits that provide some reusable parts of implementation, but they do not contain any actual data structures.
So if you want to implement your own implementation, you will have to provide the actual underlying data structure yourself (similar to how the PrefixMap from that link has private var suffixes and private var value).
For example, you could use an underlying immutable Set like this:
class TestSet[A]
extends mutable.Set[A]
with mutable.SetOps[A, mutable.Set, TestSet[A]] {
// the underlying data structure
private var data = mutable.Set.empty[A]
// ATTENTION: your implementation was different and buggy
override def clear(): Unit = {
data = mutable.Set.empty
}
override def subtractOne(elem: A): TestSet.this.type = {
data = data - elem
this
}
override def addOne(elem: A): TestSet.this.type = {
data = data + elem
this
}
override def contains(elem: A): Boolean = data.contains(elem)
override def iterator: Iterator[A] = {
data.iterator
}
// ...
}
Note that the above is just an example of what you could do in order to get your code to work - I'm not saying that it's a good idea.

Syntax extension using type class methods in Scala

I want to bind a check method to the Test in such a way that the implementation does not contain an argument (look at the last line). It is necessary to use type classes here, but I'm new in Scala, so I have problems.
Object Checker is my attempts to solve the problem. Perhaps it is enough to make changes to it...
trait Test[+T] extends Iterable[T]
class TestIterable[+T](iterable: Iterable[T]) extends Test[T] {
override def iterator: Iterator[T] = iterable.iterator
}
object Test {
def apply[T](iterable: Iterable[T]): Test[T] = new TestIterable[T](iterable)
}
trait Check[M] {
def check(m: M): M
}
object Checker {
def apply[M](implicit instance: Check[M]): Check[M] = instance
implicit def checkSyntax[M: Check](m: M): CheckOps[M] = new CheckOps[M](m)
private implicit def test[T](m: Test[T]) : Check[Test[T]] = {
new Check[Test[T]] {
override def check(m: Test[T]) = m
}
}
final class CheckOps[M: Check](m: M) {
def x2: M = Checker[M].check(m)
}
}
import Checker._
val test123 = Test(Seq(1, 2, 3))
Test(test123).check

Return a child class from apply method of base trait

I'm struggling to understand if it possible for a apply function to return an instance of a specific class. Here is an example:
I have an abstract trait
trait BaseTrait {
def add(s: Int): Int
}
and two classes that inherit this trait and:
override an abstract method
specify a method another_method
class Child1 extends BaseTrait {
override def add(s: Int): Int = {
s + s
}
def another_method(): Unit = {
println("Another method in Child1")
}
}
class Child2 extends BaseTrait {
override def add(s: Int): Int = {
s + s
}
def another_method(): Unit = {
println("Another method in Child2")
}
}
When I try to access the contents of child classes from a utility function in a Base Trait
object BaseTrait {
def apply(t: String): BaseTrait = {
t match {
case "one" => new Child1()
case "two" => new Child2()
}
}
}
val child2 = BaseTrait("one")
i don't see another_method method
child2.another_method() // cannot resolve symbol another method
Question: is there a way in Scala (generics/lower-upper bounds) to configure an apply method in such a way that it returns an instances of classes where it will be possible to access both overridden abstract methods AND methods belonging to this exact class (not just those that are defined in BaseTrait)
In this particular case you could try literal types
object BaseTrait {
def apply(t: "one"): Child1 = new Child1()
def apply(t: "two"): Child2 = new Child2()
}
val child1 = BaseTrait("one")
child1.another_method()
// Another method in Child1
Besides overloading you can also try a type class
object BaseTrait {
def apply[S <: String with Singleton](t: S)(implicit tc: MyTypeclass[S]): tc.Out = tc()
}
trait MyTypeclass[S <: String] {
type Out <: BaseTrait
def apply(): Out
}
object MyTypeclass {
implicit val one = new MyTypeclass["one"] {
override type Out = Child1
override def apply() = new Child1()
}
implicit val two = new MyTypeclass["two"] {
override type Out = Child2
override def apply() = new Child2()
}
}
val child2 = BaseTrait("one")
child2.another_method()
(Scala 2.13)

How to override an implicit value, that is imported?

I have tried solutions, described in How to override an implicit value?, but it does not help. Here is a code example.
A definition of TestImplicit abstraction with 2 different implementations (analogue of ExecutionContextExecutor):
trait TestImplicit {
def f(s:String):Unit
}
object TestImplicitImpl1 extends TestImplicit {
override def f(s: String): Unit = println(s"1: $s")
}
object TestImplicitImpl2 extends TestImplicit {
override def f(s: String): Unit = println(s"2: $s")
}
And in the ImplDefinition object a q variable is defined to be used implicitly via import (analogue of ExecutionContext.Implicits.global):
object ImplDefinition {
implicit val q:TestImplicit = TestImplicitImpl1
}
Client that defines a method, accepting TestImplicit implicitly (analogue of scala.concurrent.Future):
trait TestImplicitClient {
def fu(implicit ti:TestImplicit):Unit
}
object TestImplicitClient extends TestImplicitClient {
override def fu(implicit ti: TestImplicit): Unit = {
println("client")
ti.f("param")
}
}
The next step, a client of client, that chooses which implementation of TestImplicit should be used, the decision is done via import (analogue of API that uses Future):
object ClientOfClient {
import somepackage.ImplDefinition.q
def t():Unit =
TestImplicitClient.fu
}
Now in test, I want to use this ClientOfClient.t(), but I need to override implicit, and use TestImplicitImpl2 instead. The main idea behind - implicits should be defined/overridable by the client of API, but not by API itself:
import somepackage.{ClientOfClient, TestImplicit, TestImplicitImpl2}
import org.junit.Test
class ImplTest {
// trying to hide it via import, does not help
import somepackage.ImplDefinition.{q => _,_}
#Test def test(): Unit ={
//trying to hide it via downgrading to non-implicit, does not work either
val q = somepackage.ImplDefinition.q
implicit val ti = TestImplicitImpl2
ClientOfClient.t()
}
}
Each time I run test, I get in the output:
client
1: param
But not expected:
client
2: param
How can I fix it? I need a way to allow clients to override implicits and stay with as simple API as possible. Which means, I do not want to add additional implicit parameter into ClientOfClient.t() method.
As soon as you have a singleton object ClientOfClient with a hard-coded constant TestImplicitImpl1 everywhere, there is essentially nothing you can do. But there are several work-arounds.
1. Use default implicit parameters
object ClientOfClient {
def t()(implicit ti: TestImplicit = ImplDefinition.q): Unit =
TestImplicitClient.fu
}
object ImplTest {
def test(): Unit = {
implicit val ti2 = TestImplicitImpl2
ClientOfClient.t()
}
}
ImplTest.test() // 2: param
2. Supply the implicit through a separate method that can be overridden
If you want to make the implicit overridable, then make ClientOfClient extendable, and create a method (here "cocti") that returns the implicit, instead of importing the implicit directly. You can then override the method (whereas you cannot override an import).
This here produces 2: param in the end of the day:
trait TestImplicit {
def f(s: String): Unit
}
object TestImplicitImpl1 extends TestImplicit {
override def f(s: String): Unit = println(s"1: $s")
}
object TestImplicitImpl2 extends TestImplicit {
override def f(s: String): Unit = println(s"2: $s")
}
object ImplDefinition {
implicit val q: TestImplicit = TestImplicitImpl1
}
trait TestImplicitClient {
def fu(implicit ti: TestImplicit): Unit
}
object TestImplicitClient extends TestImplicitClient {
override def fu(implicit ti: TestImplicit): Unit = {
println("client")
ti.f("param")
}
}
class ClientOfClient {
implicit def cocti: TestImplicit = {
ImplDefinition.q
}
def t():Unit =
TestImplicitClient.fu
}
object ImplTest {
def test(): Unit = {
implicit val ti2 = TestImplicitImpl2
new ClientOfClient {
override def cocti = ti2
}.t()
}
}
ImplTest.test() // 2: param

Scala: recursive implicit type

I have the following traits for parsing that give file positions for the beginning and end of the object:
case class FilePosn(lineNum :Int, tabs: Int, spaces: Int, fileName: String)
{/*code omitted*/}
trait PosnEnds
{
def startPosn: FilePosn
def endPosn: FilePosn
def multiLine: Boolean = startPosn.lineNum != endPosn.lineNum
def OneLine: Boolean = startPosn.lineNum == endPosn.lineNum
def indent: Int = startPosn.tabs
def startLine: Int = startPosn.lineNum
def endLine: Int = endPosn.lineNum
}
object FilePosnVoid extends FilePosn(0, 0, 0, "There is no File position")
{ override def posnString(indentSize: Int): String = "No File Posn: " }
In the companion object I create an implicit, so sequences of PosnEnds are themselves implicitly PosnEnds:
object PosnEnds
{
implicit class ImpPosnEndsSeq[A <: PosnEnds](thisSeq: Seq[A]) extends PosnEnds
{
override def startPosn: FilePosn = thisSeq.fHead(FilePosnVoid, (h, t) => h.startPosn)
override def endPosn: FilePosn = thisSeq.fLast(FilePosnVoid, _.endPosn)
}
}
Is there anyway to use implicits recursively so a Seq[Seq[A]] and a Seq[Seq[Seq[A]]] etc will be implicitly converted to a PosnEnds trait? In practice I probably won't need huge levels of depth, but it would be nice to use an elegant solution that implicitly converted Seq of arbitrary depth.
Currently for depth 2 I'm using:
implicit class ImpPosnEndsSeqSeq[A <: PosnEnds](thisSeq: Seq[Seq[A]]) extends PosnEnds
{
override def startPosn: FilePosn = thisSeq.fHead(FilePosnVoid, (h, t) => h.startPosn)
override def endPosn: FilePosn = thisSeq.fLast(FilePosnVoid, _.endPosn)
}
Yes. You could do it with typeclass mediator.
I allow myself to do some minor changes in your example to make it more reproducible. Inside object PosnEnds I have
val void = new FilePosn(0, 0, 0, "There is no File position") {
override def posnString(indentSize: Int): String = "No File Posn: "
}
def empty = new PosnEnds {
def startPosn: FilePosn = void
def endPosn: FilePosn = void
}
Thing you need first is some simple typeclass like
trait MakePosnEnds[X] extends (X => PosnEnds)
Now you can introduce canonical elements for induction:
implicit object idMakePosnEnds extends MakePosnEnds[PosnEnds] {
def apply(x: PosnEnds) = x
}
implicit def seqMakePosnEnds[X](implicit recur: MakePosnEnds[X]) = new MakePosnEnds[Seq[X]] {
def apply(x: Seq[X]): PosnEnds = new PosnEnds {
val thisSeq = x.map(recur)
override def startPosn: FilePosn = thisSeq.headOption.fold(void)(_.startPosn)
override def endPosn: FilePosn = thisSeq.lastOption.fold(void)(_.endPosn)
}
}
Finally you can define your implicit conversion
implicit def toPosnEnds[X](x: X)(implicit make: MakePosnEnds[X]): PosnEnds = make(x)
From this point
Seq(Seq(Seq(empty))).startLine
compiles and runs succesfully
Major difference with your attempt: we dont wait implicit conversion to stack. Implicit resolution can be recursive, but implicit conversion can not.
So we are using some value-less type, i.e something that could be achieved using only implicit arguments which means could be constructed by the compiler.
And only then projecting this logic to the concrete value.