This is a quite long answer but I hope it clarifies a bit potential usage scenarios.
So, why Anonymous object is good if we don't want to reuse?
I think that unlike the other two the term "anonymous object" is not well-defined in the Scala world. I can think of several things that might be called so:
- Some object that you don't assign to any named variable or field. This can happen in several cases. For example consider
foldLeft on some collection. You want to pass the initial value there but you typically don't need to give it any name as this is a disposable object. Another case is when such object contains some piece of logic you want to use (a kind of strategy pattern). Consider following piece from standard ParIterableLike
def count(p: T => Boolean): Int = {
tasksupport.executeAndWaitResult(new Count(p, splitter))
}
This particular implementation uses named method tasksupport because it wants it to be customizable. But if not that, it might have been something like
def count(p: T => Boolean): Int = {
new ExecutionContextTaskSupport.executeAndWaitResult(new Count(p, splitter))
}
and new ExecutionContextTaskSupport would be an anonymous object.
Something that should be called an "anonymous type object".
- This happens quite often if you implement an evidence for some type-classes. Consider this example from Play-Json
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 the class for residentReads will be generated by a macro behind Json.reads and you don't care what type it has as long as it implements the Reads trait.
- Or if you have a template method that depends on some strategy returned. I.e these are the cases when all the caller needs to know about the type is that it matches some specified interface contract (i.e. extends certain
trait). Consider this piece 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 don't care of the specific type as long as it meets the contract of ExecutionContextExecutorService and particularly we don't care that it is based on ExecutionContextImpl rather than any other implementation.
And actually case #1 and #2 (i.e. "an anonymous object of an anonymous type") are often combined if you need to pass somewhere a piece of work that for some reasons doesn't fit simple Function interface (either because it needs more than one life-cycle method or for historical compatibility reasons). The 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 a piece of work to execute and we want to wrap the runnable we've got as a parameter with another one that will call deregisterThread at the end but we don't care about the name of the object or its actual type.
what's the real purpose of Companion Object?
I can think of several major reasons to use Companion Objects.
- Something that in Java world would be a
static method or a static field. For instance assume you write you custom arbitrary-precision arithmetic BigInt. Where would you put well-known constants such as zero so they would be accessible from the outside? The companion object is the answer. Another quite typical usage for this kind of companion objects is means to provide some factory methods (typically via apply) so for example you can write
List.empty
List(1, 2, 3)
without the new keyword
- You have some class and you want to provide some shared default instance for it. It is not necessary a singleton in terms that you are quite OK with creating more instances of that class. For example
scala.util.Random defines both class and a companion object as
object Random extends Random
so you can do just
Random.nextInt
- Something that is probably most deservedly might be called a "companion object". You have some hierarchy of classes and a piece of logic that should be bound to each class in the hierarchy but is not of the type of the classes in the hierarchy. This might sound a bit complicated but is not that hard. The
scala.concurrent package employs 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 a few levels down to inheritance tree is implemented by the List companion object
object List extends SeqFactory[List] {
/** $genericCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] =
ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
def newBuilder[A]: Builder[A, List[A]] = new ListBuffer[A]
// some other stuff
}
This canBuildFrom is actually used by many collection methods that transform them into other collections such as ++ or map. Moreover this clever trick allows you to write something like this with mapping to other collection type:
val list: List[Int] = Vector(1, 2, 3).map(x => 2 * x)(breakout)