I want to be able to write:
JavaList.of("X", "Y")
to get a mutable Java list. I’m okay with getting an ArrayList
by default, but I’d like to keep the possibility of switching to LinkedList
if needed.
Here’s my current attempt:
trait JavaListFactory[C[_]]:
def from[A](seq: Seq[A]): C[A]
given ArrayList: JavaListFactory[util.ArrayList] with
def from[A](seq: Seq[A]): util.ArrayList[A] = util.ArrayList(seq.asJava)
object LinkedList extends JavaListFactory[util.LinkedList]:
def from[A](seq: Seq[A]): util.LinkedList[A] = util.LinkedList(seq.asJava)
object JavaList:
def of[A, C[_] <: util.List[?]](values: A*)(using factory: JavaListFactory[C]): C[A] =
factory.from(values)
and my questions:
I define my own factory because the standard ones seem too rich for my purpose (in particular, I don’t want to bother implementing a newBuilder
method). Am I missing a simple one somewhere?
I can write JavaList.of("X", "Y")
(and get an ArrayList
) or JavaList.of("X", "Y")(using LinkedList)
to get a LinkedList
. However, I cannot switch from ArrayList
to LinkedList
with a simple import. Instead, I need a rather ugly given
:
given JavaListFactory[util.LinkedList] = LinkedList
(which exposes the factory trait)
I also don’t like this util.List[?]
in my signature.
Any suggestions for improvements?
charpov:
I also don’t like this util.List[?]
in my signature.
Yeah, also I think that is wrong.
It should be C[x] <: util.List[x]
charpov:
However, I cannot switch from ArrayList
to LinkedList
with a simple import. Instead, I need a rather ugly given
:
You could put each implicit into its own object, that way users must need to import one.
Like:
object JavaList:
def of[A, C[x] <: util.List[x]](values: A*)(using factory: JavaListFactory[C]): C[A] =
factory.from(values)
trait JavaListFactory[C[_]]:
def from[A](seq: Seq[A]): C[A]
object arrayList:
given JavaListFactory[util.ArrayList] with
def from[A](seq: Seq[A]): util.ArrayList[A] =
util.ArrayList(seq.asJava)
object linkedList:
given JavaListFactory[util.LinkedList] with
def from[A](seq: Seq[A]): util.LinkedList[A] =
util.LinkedList(seq.asJava)
And the usage would be something like:
import JavaList.arrayList.given
val javaList = JavaList.of("foo", "bar") // ArrayList
1 Like
I prefer this route so I can have ArrayList
by default:
object ArrayList:
given factory: JavaListFactory[util.ArrayList] with
def from[A](seq: Seq[A]): util.ArrayList[A] = util.ArrayList(seq.asJava)
object LinkedList:
given factory: JavaListFactory[util.LinkedList] with
def from[A](seq: Seq[A]): util.LinkedList[A] = util.LinkedList(seq.asJava)
given JavaListFactory[util.ArrayList] = ArrayList.factory
This allows:
// ArrayList by default
JavaList.of("X", "Y")
// LinkedList explicitly
JavaList.of("X", "Y")(using LinkedList.factory)
// LinkedList by import
import LinkedList.factory
JavaList.of("X", "Y")
Thanks for the help.