Skip to content

Commit

Permalink
Reduce misleading verbiage on file style
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Mar 25, 2024
1 parent 097c4f9 commit 8bc786e
Showing 1 changed file with 27 additions and 42 deletions.
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`.

0 comments on commit 8bc786e

Please sign in to comment.