chenzhongpu
chenzhongpu

Reputation: 6871

Why this case class can hold more parameters than it declares?

See the code,

 case class Wrapped[A](elem: A)(implicit ordering: Ordering[A])
    extends Ordered[Wrapped[A]] {
    def compare(that: Wrapped[A]): Int = ordering.compare(this.elem, that.elem)
  }

I define a case class here.

and then call

Wrapped(1,2,2,4).

To my surprise, even Wrapped(1,2,3,4,5) (any num of parameters) can work fine without compiling error.

Upvotes: 8

Views: 2064

Answers (2)

Gabriele Petronella
Gabriele Petronella

Reputation: 108159

It's called auto-tupling.

The compiler will try to make up for the extra arguments by wrapping all of them in a tuple.

Wrapped(1,2,3,4)

gets automatically turned into

Wrapped((1,2,3,4))

By the way, this is an annoying and surprising feature and I really hope it will be eventually deprecated. In the meanwhile you have two compiler options available:

  • -Ywarn-adapted-args, that warns in case of autotupling
  • -Yno-adapted-args, that gives an error under the same circumstances

Example with warning:

scala -Ywarn-adapted-args

scala> case class Foo[A](a: A)

scala> Foo(1, 2)
<console>:10: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
        signature: Foo.apply[A](a: A): Foo[A]
  given arguments: 1, 2
 after adaptation: Foo((1, 2): (Int, Int))
              Foo(1, 2)
                 ^
res1: Foo[(Int, Int)] = Foo((1,2))

Example with error:

scala -Yno-adapted-args

scala> case class Foo[A](a: A)
defined class Foo

scala> Foo(1, 2)
<console>:10: warning: No automatic adaptation here: use explicit parentheses.
        signature: Foo.apply[A](a: A): Foo[A]
  given arguments: 1, 2
 after adaptation: Foo((1, 2): (Int, Int))
              Foo(1, 2)
                 ^
<console>:10: error: too many arguments for method apply: (a: (Int, Int))Foo[(Int, Int)] in object Foo
              Foo(1, 2)
                 ^

Upvotes: 15

Sergii Lagutin
Sergii Lagutin

Reputation: 10681

Look closer to your code:

Wrapped(1,2,3,4,5)
res0: Wrapped[(Int, Int, Int, Int, Int)] = Wrapped((1,2,3,4,5))

Parameters are compacted into Tuple object. So you have Wrapped[(Int, Int, Int, Int, Int)] instead of desired Wrapped[Int].

Upvotes: 1

Related Questions