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)