This is a fairly long answer, but I hope it clarifies a few possible use cases.
So why is an anonymous object good if we don't want to reuse it?
I think that unlike the other two, the term “anonymous object” is not defined in the Scala world. I can think of a few things that could be called like this:
- Some objects that you do not assign to any named variable or field. This can happen in several cases. For example, consider
foldLeft in some collection. You want to pass the initial value, but usually you do not need to specify its name, since it is a one-time object. Another case is when such an object contains some part of the logic that you want to use (a kind of strategy template ). Consider the following snippet from a standard ParIterableLike
def count(p: T => Boolean): Int = { tasksupport.executeAndWaitResult(new Count(p, splitter)) }
This particular implementation uses the named tasksupport method because it wants it to be configured. But if not for this, perhaps it was something like
def count(p: T => Boolean): Int = { new ExecutionContextTaskSupport.executeAndWaitResult(new Count(p, splitter)) }
and new ExecutionContextTaskSupport will be an anonymous object.
Something to be called an anonymous type .
case class Resident(name: String, age: Int, role: Option[String]) import play.api.libs.json._ implicit val residentReads = Json.reads[Resident] // In a request, a JsValue is likely to come from `request.body.asJson` // or just `request.body` if using the `Action(parse.json)` body parser val jsonString: JsValue = Json.parse( """{ "name" : "Fiver", "age" : 4 }""" ) val residentFromJson: JsResult[Resident] = Json.fromJson[Resident](jsonString)
Here, the object and class for residentReads will be generated by the macro for Json.reads , and you don't care what type it has as long as it implements the Reads flag.
- Or if you have a template method that depends on the strategy returned. I. These are cases when all callers need to know about the type, are that it corresponds to a specific interface contract (i.e. Extends a specific
trait ). Consider this snippet from ExecutionContextImpl
def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl with ExecutionContextExecutorService = { new ExecutionContextImpl(Option(es).getOrElse(createDefaultExecutorService(reporter)), reporter) with ExecutionContextExecutorService { final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService] override def execute(command: Runnable) = executor.execute(command) override def shutdown() { asExecutorService.shutdown() } override def shutdownNow() = asExecutorService.shutdownNow() override def isShutdown = asExecutorService.isShutdown override def isTerminated = asExecutorService.isTerminated override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit) override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable) override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t) override def submit(runnable: Runnable) = asExecutorService.submit(runnable) override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables) override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit) override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables) override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit) } }
Again, the caller does not care about a particular type if it conforms to the ExecutionContextExecutorService contract, and it doesn’t matter to us that it is based on ExecutionContextImpl , and not on any other implementation.
In fact, cases # 1 and # 2 (i.e., an anonymous object of an anonymous type) are often combined if you need to transfer some part of the work, which for some reason is not suitable for the simple Function interface (or because it requires more than one life cycle method, or for reasons of historical compatibility). A prime example of this is java.lang.Runnable . And here is another example from ExecutionContextImpl :
// As per ThreadFactory contract newThread should return `null` if cannot create new thread. def newThread(runnable: Runnable): Thread = if (reserveThread()) wire(new Thread(new Runnable { // We have to decrement the current thread count when the thread exits override def run() = try runnable.run() finally deregisterThread() })) else null
The Thread class requires Runnable as part of the work to be done, and we want to wrap Runnable we got as a parameter with another, which will call deregisterThread at the end, but we don’t care about the name of the object or its actual type.
What is the real purpose of the Companion object?
I can think of a few basic reasons for using Companion objects.
- Something that in the Java world would be a
static way or a static field. For example, suppose you are writing arbitrary arithmetic of arbitrary precision BigInt . Where would you place known constants such as zero so that they are accessible from the outside? The defendant is a companion object. Another fairly typical use for such companion objects is to provide some factory methods (usually via apply ), so you can write
List.empty List(1, 2, 3)
without the keyword new
- You have some kind of class, and you want to provide a shared default instance for it. There is no need for a singleton in terms of the fact that everything is fine with you, creating more instances of this class. For example,
scala.util.Random defines both a class and a companion object as
object Random extends Random
so that you can only do
Random.nextInt
- Something that is probably most deservedly called a "companion object." You have a class hierarchy and a piece of logic that needs to be attached to each class in the hierarchy, but not related to the type of classes in the hierarchy. It may seem a bit complicated, but it is not so difficult. The
scala.concurrent package uses this idea a lot. Consider, for example:
abstract class GenTraversableFactory[CC[X] <: GenTraversable[X] with GenericTraversableTemplate[X, CC]] extends GenericCompanion[CC] { private[this] val ReusableCBFInstance: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] { override def apply() = newBuilder[Nothing] } def ReusableCBF: GenericCanBuildFrom[Nothing] = ReusableCBFInstance // some other stuff }
which several levels to the inheritance tree is implemented using the List of the companion object
object List extends SeqFactory[List] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] def newBuilder[A]: Builder[A, List[A]] = new ListBuffer[A]
This canBuildFrom actually used by many collection methods that convert them to other collections, such as ++ or map . In addition, this clever trick allows you to write something like this when matching with another type of collection:
val list: List[Int] = Vector(1, 2, 3).map(x => 2 * x)(breakout)