I have a custom type MySeq
extending IndexedSeq[Int]
and its implicit
conversion:
package example
import scala.language.implicitConversions
class MySeq(vals: IndexedSeq[Int]) extends IndexedSeq[Int] {
def apply(i: Int): Int = vals(i)
def length: Int = vals.length
}
object MySeq {
implicit def seq2MySeq(vals: Int*): MySeq = new MySeq(vals.toIndexedSeq)
}
I want to be able to call some function of type MySeq => T
as follows:
package example
object Hello extends App {
def foo(xs: MySeq): MySeq = xs
val ret = foo(1, 2, 3)
}
But I get a Too many arguments for method foo(MySeq)
error when compiling with scala-2.13.8.
What am I missing/misunderstanding?
CodePudding user response:
You can implicitly convert only 1 value to another 1 value, you cannot use conversion to "overload" unary method into variadic method.
You could implement conversions so that
foo(Seq(1, 2, 3))
would become
foo(MySeq.seq2MySeq(Seq(1, 2, 3))
but to be able to use
foo(1, 2, 3)
you would have to overload the method e.g.
def foo(ints: Int*) = foo(MySeq(ints))
CodePudding user response:
implicit
conversions can be useful, but they have always been easy to misuse.
From the Baeldung Blog:
The major drawbacks with implicit in Scala 2 are:
- Usage of the keyword implicit for unrelated functionalities
- Unintended conversions due to implicit conversions
- Unclear compiler error messages
You said you are still using 2.13.8
, and this post talks mostly about what has changed in Scala 3, but the caveats of implicit
can be difficult to debug and understand, and they are highlighted at the beginning of this post.
In Scala 3, for these reasons (and others), they have reworked implicit
s (and introduced a new system that is far more explicit and powerful given
/using
[but that's a whole 'nother can of worms; very powerful and useful, but only in Scala 3 ])
In your case, I would recommend a simple overload to your apply
method for MySeq
, no implicit
conversion necessary:
class MySeq( vals: IndexedSeq[Int] ) extends IndexedSeq[Int] {
// Unchanged
}
object MySeq {
def apply( vals: Int* ): MySeq = new MySeq( vals.toIndexedSeq )
}
@main
def runner(): Unit = {
// use overloaded apply, convenient but explicit conversion
val mySeqFromVarArg: MySeq = MySeq( 1, 2, 3 )
}