What's the difference between a class with a companion object and a class and object with the same name?
Asked Answered
S

1

13

A Scala class's "companion object" can be viewed as a singleton object with the same fully qualified name as the class (i.e. same name, in same package). They are used to hold utility functions common to all instances of the class, as a replacement for Java's static methods.

However, in various places in the docs and in questions, it say that companion objects must be defined in the same compilation unit. For example, they must be defined in the same file; companion objects cannot be defined for Java objects; in the REPL, they must be defined on the same input line, hence the warning message:

warning: previously defined class Foo is not a companion to object Foo.
Companions must be defined together; you may wish to use :paste mode for this.

This implies that there must be a distinction between a class with its companion object, and just a class and object with the same (fully qualified) name. What is this distinction?

Seventh answered 22/7, 2012 at 22:1 Comment(0)
S
17

Let's call the class class SomeClass (though it could also be e.g. a trait).

Private members

Methods of the companion object (object SomeClass) have access to private methods/data of instances of class SomeClass.

If your companion object only uses the public interface of your class (e.g. just defines constants), there's no practical difference. But there are a number of cases where it's useful to let utility functions access private members. For example, object SomeClass could define a factory method apply that sets up private members of class SomeClass, without having to expose setters in the public interface. In such cases, you must therefore define a companion object by putting the definition of object SomeClass in the same compilation unit as class SomeClass.

Another difference is that the compiler searches for implicits in companion objects of a type (and its supertypes). So if you are using implicit conversions you define in the code of class SomeClass, you must define them in the companion object.

Comments

The combination of the two also explains the same-compilation-unit restriction.

  • scalac can't compile object SomeClass until it knows what private members of class SomeClass it calls.
  • scalac can't compile class SomeClass until it knows what implicits it calls. So the companion object must be compiled no later than class SomeClass.

It follows they must be compiled at the same time. Further, the current compiler apparently compiles separate files separately (cf. the lack of support for splitting classes across multiple files), restricting it to the same compilation unit.

Seventh answered 22/7, 2012 at 22:1 Comment(1)
The "same compilation unit" restriction is not just an implementation detail of the compiler or laziness on part of the compiler engineers. It is also a useful way to prove that you have the right to access the private members of the class, i.e. break encapsulation: if you can edit the file anyway, then encapsulation is already out the window, so you don't lose any safety by exposing them to the companion object. If anybody could define companion objects anytime anywhere, they could trivially break encapsulation of third-party classes just by adding a companion object to them.Nannienanning

© 2022 - 2024 — McMap. All rights reserved.