p0107.md 8.9 KB

Code and name organization

Pull request

Table of contents

Problem

How do developers store code for the compiler, and access it for reuse?

Proposal

Adopt an approach with tiered files, libraries, packages and namespaces in the design.

Out-of-scope issues

Related issues that are out-of-scope for this proposal are:

  • Access control: while there is some implicit access control from interface vs implementation considerations for libraries, they are more about addressing circular dependencies in code.

  • Aliasing implementation: while the alias keyword is critical to how easy or difficult refactoring is, it should be designed on its own.

  • Compilation details: this proposal sets up a framework that should enable well-designed compilation, but does not set about to design how compilation will work.

  • File-private identifiers: Something similar to C++ static functions may exist. However, that will be addressed separately.

  • Incremental migration and unused imports: incrementally migrating a declaration from one library to another might require an intermediate state where callers import both libraries, with consequent issues. However, it may also not require such. Whether it does, or whether tooling needs to be added to support the specific intermediary state of transitional, unused imports, is out of scope.

  • Name lookup, including addressing conflicting names between imports and names in the current file: the name lookup design is likely to address this better, including offering syntax that could refer to it if needed.

    • After discussion, we believe we do not need to support package renaming. However, that final decision should be based on name lookup addressing the issue, as implications need to be considered more deeply.
  • Package management: while we want to choose syntax that won't impose barriers on building package management into Carbon, we should not make assumptions about how package management should work.

  • Prelude package, or fundamentals: while we've discussed how to handle name lookup for things like Int32, this proposal mainly lays out a framework where options for addressing that are possible.

This proposal should not be interpreted as addressing these issues. A separate discussion of these issues will remain necessary.

Open questions for the decision

Extended open question comparisons may be found in the examples doc in addition to the code_and_organization.md alternatives section.

Should we switch to a library-oriented structure that's package-agnostic?

Decision: No.

Right now, the package syntax is very package-oriented. We could instead eliminate package semantics from code and organization, relying only on libraries and removing the link to distribution. This is the collapse the package concept into libraries alternative.

Does the core team agree with the approach to packages and libraries? If not, does the alternative capture what the core team wants to be turned into the proposal, or is some other approach preferred?

Should there be a tight association between file paths and packages/libraries?

Decision: Make paths correspond to libraries for API files, not impl files. Keep package.

Right now, the package syntax requires the package's own name be repeated through code. This touches on a couple alternatives:

The end result of taking both alternatives would be that:

  • The package and library would no longer need to be specified on the first line.
    • The import would still need a library.
  • The package keyword would always be used to refer to the current package.
    • Referring to the current package by name would be disallowed, to allow for easier renames of conflicting package names.

Justification

  • Software and language evolution:

    • The syntax and interactions between package and import should enable moving code between files and libraries with fewer modifications to callers, easing maintenance of large codebases.

      • In C++ terms, #include updates are avoidable when moving code around.
  • Code that is easy to read, understand, and write:

    • By setting up imports so that each name in a file is unique and refers to the source package, we make the meaning of symbols clear and easier to understand.

    • The proposed namespace syntax additionally makes it clear when the package's default namespace is not being used.

      • This is in contrast to C++ namespaces, where the entire body of code above the line of code in question may be used to start a namespace.
    • Clearly marking interfaces will make it easier for both client code and IDE tab completion to more easily determine which APIs can be used from a given library.

  • Fast and scalable development:

    • The structure of libraries and imports should help enable separate compilation, particularly improving performance for large codebases.
  • Interoperability with and migration from existing C++ code:

    • The syntax of import should enable extending imports for use in interoperability code.

Rationale

This proposal provides an organizational structure that seems both workable and aligns well with Carbon's goals:

  • Distinct and required top-level namespace -- "package"s from the proposal -- both matches software best practices for long-term evolution, and avoids complex and user-confusing corner cases.
  • Providing a fine-grained import structure as provided by the "library" concept supports scalable build system implementations while ensuring explicit dependencies.
  • The structured namespace facilities provide a clear mechanism to migrate existing hierarchical naming structures in C++ code.

Open questions

Should we switch to a library-oriented structure that's package-agnostic?

  • Decision: No.
  • Rationale: While this would simplify the overall set of constructs needed, removing the concept of a global namespace remained desirable and would require re-introducing much of the complexity around top-level namespaces. Overall, the simplification trade-off didn't seem significantly better.

Should there be a tight association between file paths and packages/libraries?

  • Decision: Yes, for the API files in libraries. Specifically, the library name should still be written in the source, but it should be checked to match -- after some platform-specific translation -- against the path.
  • Note: Sufficient restrictions to result in a portable and simple translation on different filesystems should be imposed, but the Core team was happy for these restrictions to be developed as part of implementation work.
  • Rationale: This will improve usability and readability for users by making it obvious how to find the files that are being imported. Similarly, this will improve tooling by increasing the ease with which tools can find imported APIs.