Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

scala

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.

like image 838
chenzhongpu Avatar asked Mar 25 '15 09:03

chenzhongpu


People also ask

Why use case classes in scala?

The one of the topmost benefit of Case Class is that Scala Compiler affix a method with the name of the class having identical number of parameters as defined in the class definition, because of that you can create objects of the Case Class even in the absence of the keyword new.

How do I create a dynamic case class in scala?

Parse your CSV header to know field names and data types. Generate a case class with the above information and write to a file on disk. Load the generated source files and compile them using the interpreter.

What does case do in scala?

Case class in scala is used in pattern matching. While defining a case class, we just require a case keyword followed by the name of our class and a list of parameters; if any, otherwise, it can be empty as well.


2 Answers

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)
                 ^
like image 138
Gabriele Petronella Avatar answered Oct 02 '22 09:10

Gabriele Petronella


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].

like image 33
Sergii Lagutin Avatar answered Oct 02 '22 09:10

Sergii Lagutin