How to create a custom collection that extends on Sets In Scala? - 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.

Related

Custom Collection extending on Set in 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.)

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

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

Immutable composable builder in scala

I'm interested how to improve the piece of code bellow. The idea is to build an immutable composable builder. In the end the builder just builds a Map[String, Object]. I want to be able to define core builder components that can be reused and to also let people define their own additional builders to extend the main builder. I'm able to do so but not without the ugly use of reflection. The code looks as follows:
object TestPizzaBuilder {
def main(args: Array[String]): Unit = {
val build = new PizzaBuilder()
.withCheese("blue")
.withSauce("tomato")
.build()
println(build)
}
}
object PizzaBuilder {
type BuilderParams = Map[String, Object]
}
class PizzaBuilder(params: BuilderParams = Map.empty) extends BaseBuilder[PizzaBuilder](params: BuilderParams)
with CheeseBuilder[PizzaBuilder]
with SauceBuilder[PizzaBuilder] {
}
abstract class BaseBuilder[A <: BaseBuilder[A]](params: BuilderParams)(implicit tag: ClassTag[A]) {
protected def _copy(tuples: (String, Object)*): A = {
val constr = tag.runtimeClass.getConstructors()(0)
constr.newInstance(params ++ tuples).asInstanceOf[A]
}
def build(): Map[String, Object] = {
params
}
}
trait CheeseBuilder[A <: BaseBuilder[A]] {
this: BaseBuilder[A] =>
def withCheese(cheese: String): A = _copy("cheese" -> cheese)
}
trait SauceBuilder[A <: BaseBuilder[A]] {
this: BaseBuilder[A] =>
def withSauce(sauce: String): A = _copy("sauce" -> sauce)
}
Do you have suggestions how reflection can be avoided in this scenario yet keeping the builder immutable and also allowing to compose the builder of tiny other builders.
Smallest change would be to pass the constructor (as a function) instead of a ClassTag:
abstract class BaseBuilder[A <: BaseBuilder[A]](params: BuilderParams)(constructor: BuilderParams => A) {
protected def _copy(tuples: (String, Object)*): A = constructor(params ++ tuples)
def build(): Map[String, Object] = {
params
}
}
// or class PizzaBuilder(params: BuilderParams = Map.empty) extends BaseBuilder[PizzaBuilder](params)(new PizzaBuilder(_))
case class PizzaBuilder(params: BuilderParams = Map.empty) extends BaseBuilder[PizzaBuilder](params)(PizzaBuilder)
with CheeseBuilder[PizzaBuilder]
with SauceBuilder[PizzaBuilder] {
}

How to extend mutable Map in Scala

I would like to extend mutable Map in Scala, because I need some special behaviour when adding a new tuple.
I have the following
package my.package
import collection.mutable.Map
class Unit[T1,T2](map: Map[T1,T2]) extends Map[T1,T2]{
override def get(key: T1): Option[T2] = super.get(key)
override def iterator: Iterator[(T1, T2)] = super.iterator
override def -=(key: T1): Map[T1, T2] = super.-(key)
override def +=[T3 >: T2] (kv: (T1, T3)): Map[T1, T3] = super.+[T3](kv)
}
The problem is with the syntax of the += method. It says that method += overrides nothing. If I change += to +, there is an issue that class Unit must either be declared as abstract or implement abstract member +=.
EDIT
This is syntacticly correct
class Unit[T1,T2] extends Map[T1,T2]{
override def get(key: T1): Option[T2] = super.get(key)
override def iterator: Iterator[(T1, T2)] = super.iterator
override def -=(key: T1): Map[T1, T2] = super.-(key)
override def += (kv: (T1, T2)): Map[T1, T2] = super.+[T2](kv)
}
But it would be better to extend HashMap instead of Map which is a trait, cause I need to change only one function for adding a new tuple.
EDIT
And below this is what I wanted to have.
import collection.mutable.HashMap
import scala.math.{log,ceil}
class Unit[T1>:String,T2>:String] extends HashMap[T1,T2]{
override def +=(kv: (T1, T2)): this.type = {
val bits = ceil(log2(this.size)).toInt match {
case x: Int if (x < 5) => 5
case x => x
}
val key = Range(0,(bits - this.size.toBinaryString.size)).foldLeft("")((a,_)=>a+"0")+this.size.toBinaryString
this.put(kv._1, key)
this
}
val lnOf2 = log(2) // natural log of 2
def log2(x: Double): Double = log(x) / lnOf2
}
It's supposed to be named += but its return type must be Unit (since it's a mutable map) and you are trying to return a Map. Note that your class is named Unit so be careful there.