Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce misleading verbiage on file style #3000

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 27 additions & 42 deletions _style/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,45 @@ previous-page: method-invocation
next-page: scaladoc
---

As a rule, files should contain a *single* logical compilation unit. By
"logical" I mean a class, trait or object. One exception to this
guideline is for classes or traits which have companion objects.
Companion objects should be grouped with their corresponding class or
trait in the same file. These files should be named according to the
class, trait or object they contain:
The unit of work for the compiler is a "compilation unit",
which is usually just an ordinary file.
The Scala language places few restrictions on how code is organized across files.
The definition of a class, or equivalently a trait or object, can't be split over multiple files,
so it must be contained within a single file.
A class and its companion object must be defined together in the same file.
A sealed class can be extended only in the same file, so all its subclasses must be defined there.

package com.novell.coolness
Similarly, there are no restrictions on the name of a source file or where it is located in the file system,
although certain conventions are broadly honored in practice.
Generally, the file is named after the class it contains,
or if it has more than one class, the parent class.

For example, a file, `Inbox.scala`, is expected to contain `Inbox` and its companion:

package org.coolness

class Inbox { ... }

// companion object
object Inbox { ... }

These compilation units should be placed within a file named
`Inbox.scala` within the `com/novell/coolness` directory. In short, the
Java file naming and positioning conventions should be preferred,
despite the fact that Scala allows for greater flexibility in this
regard.

## Multi-Unit Files
The file may be located in a directory, `org/coolness`, following Java tooling conventions,
but this is at the discretion of the developer and for their convenience.

Despite what was said above, there are some important situations which
warrant the inclusion of multiple compilation units within a single
file. One common example is that of a sealed trait and several
sub-classes (often emulating the ADT language feature available in
functional languages):
It is natural to put the following `Option` ADT in a file, `Option.scala`:

sealed trait Option[+A]

case class Some[A](a: A) extends Option[A]

case object None extends Option[Nothing]

Because of the nature of sealed superclasses (and traits), all subtypes
*must* be included in the same file. Thus, such a situation definitely
qualifies as an instance where the preference for single-unit files
should be ignored.

Another case is when multiple classes logically form a single, cohesive
group, sharing concepts to the point where maintenance is greatly served
by containing them within a single file. These situations are harder to
predict than the aforementioned sealed supertype exception. Generally
speaking, if it is *easier* to perform long-term maintenance and
development on several units in a single file rather than spread across
multiple, then such an organizational strategy should be preferred for
these classes. However, keep in mind that when multiple units are
contained within a single file, it is often more difficult to find
specific units when it comes time to make changes.

**All multi-unit files should be given camelCase names with a lower-case
first letter.** This is a very important convention. It differentiates
multi- from single-unit files, greatly easing the process of finding
declarations. These filenames may be based upon a significant type which
they contain (e.g. `option.scala` for the example above), or may be
descriptive of the logical property shared by all units within (e.g.
`ast.scala`).
The related elements, `Some` and `None`, are easily discoverable, even in the absence of tooling.

When unrelated classes are grouped together, perhaps because they implement a feature or a model a domain,
the source file receives a descriptive `camelCase` name.
Some prefer this naming scheme for top-level terms. For example, `object project` would be found in `project.scala`.
Similarly, a package object defined as `package object model` is located in `package.scala` in the `model` source directory.

Files created just for quick testing can have arbitrary names, such as `demo-bug.scala`.

Loading