What's the difference between a class with a c

2019-04-05 02:29发布

问题:

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?

回答1:

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.