6

In Chapter 22 of "Programming in Scala" book, the :: class (cons) is defined as

final case class ::[T](hd: T, tl: List[T]) extends List[T] {
  //...
}

The :: method in class List is defined as follows:

def ::[U >: T](x: U): List[U] = new scala.::(x, this)

Why is the new required to create an instance of the finalcaseclass ::? Is this purely for disambiguation?

1
  • 4
    final only means that the class can not be extended, it has nothing to do with instance creation :-). Case class is basically a class that can be compared in a 'match case' block. Commented Dec 15, 2011 at 2:32

2 Answers 2

7

With case classes you automatically get a companion object whose apply method calls the constructor, in the same way as you can do this with an ordinary class:

class Foo(val value: Int) 
object Foo { def apply(value: Int) = new Foo(value) }

val x = new Foo(42)  //
val y = Foo(42)      // both work the same

You can instantiate case classes with new if you want to. It might in theory be slightly faster because it doesn't have to go via the companion object's apply method, but I tried a quick benchmark and saw absolutely no difference in performance, so I guess it's optimised by the compiler, or just an immeasurably small difference compared to the actual construction.

So I don't think the new in the example you give has any significance and could just as well have been left out.

Sign up to request clarification or add additional context in comments.

Comments

3

You are correct; the new is not mandatory. They could have defined the instance method List#:: like this just as well:

def ::[U >: T](x: U): List[U] = scala.::(x, this)

(Note that we have:

type :: = collection.immutable.::
val  :: = collection.immutable.::

defined in the scala package object; the first is why your new scala.::(x, this) works, and the second is why my scala.::(x, this) works.)

The form the library uses calls the constructor directly, as yours does. The alternative calls the apply method of the synthetic companion object generated for the :: case class, which simply calls the constructor anyway. Perhaps calling the constructor was deemed clearer, or more efficient? (Efficiency gains should be close to nothing, though, since if the compiler doesn't inline the call to apply, the JVM will.) I suppose the most compact form:

def ::[U >: T](x: U) = ::(x, this)

could be mistaken for some wacky (i.e., impossible) sort of recursive invocation, and at any rate blurs the distinction between the class called :: and the List method called ::, which Prof. Odersky takes pains to keep separate in order to maximize reader comprehension.

Hope this helps.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.