No predeclared identifiers, Core is a keyword

Pull request

Table of contents

Abstract

Introduce a principle that the Carbon language should not encroach on the developer’s namespace. Satisfy this principle by making Core a keyword.

Problem

Ongoing design work needs rules for how to expose types such as a primitive array type to Carbon code, and in particular, if we choose to make it available by default, whether that should be accomplished by a keyword or a predeclared identifier.

Background

See the Background section of the added principle.

Proposal

We choose to not have any predeclared identifiers in Carbon. If a word has special meaning to the language, then that word is a keyword, and a plain identifier with no special meaning is always available using raw identifier syntax.

Details

See the principle document for details of the added principle. In addition, we make one change and one clarification:

  • Core is changed from being an identifier that happens to be the name of the Carbon standard library, and happens to be predeclared in every source file as naming that library, to being a keyword. The keyword can only be used:

    • When importing the Core package.
    • When implementing the Core package as part of the language implementation.
    • As a keyword naming the Core package, much like the package keyword.

    The identifier r#Core can be used freely and does not conflict with the keyword. This includes use of r#Core as the name of a package. Language constructs that are defined in terms of entities in the Core package refer specifically to the package named with the keyword Core, not to any other entity named Core.

  • The self keyword is now included in the list of keywords. It is already treated as a keyword by the toolchain.

Rationale

  • Language tools and ecosystem
    • Code generation tools can have a uniform handling for all words with special meaning, with no need to alter the spelling of names from other languages.
    • Language tools can determine the meaning of Core.<name> without needing to do any name lookup or sophisticated analysis.
  • Software and language evolution
    • Migration between versions of Carbon with a changed set of reserved words can be done uniformly.
    • Adding names to the prelude remains a non-breaking change. Adding new predeclared names requires adding a keyword, with the same cost and value tradeoffs regardless of whether the keyword names a library declaration or introduces new language syntax.
  • Code that is easy to read, understand, and write
    • Syntax highlighting tools can easily distinguish between words with special meaning and words with program-defined meaning.
    • The meaning of core language constructs can be defined as a rewrite in terms of Core.<name> without concern that Core may have some different local interpretation.
  • Interoperability with and migration from existing C++ code
    • All C++ identifiers are nameable from Carbon code without conflicts. Virtual functions introduced in Carbon can be overridden in Carbon regardless of their name. C++ code can be migrated to Carbon even if its name in C++ has special meaning in Carbon.
  • Principle: Prefer providing only one way to do a given thing
    • This proposal specifies that there is only one way to give words special meaning in Carbon, and one way to resolve issues if that special meaning conflicts with another desired meaning.

Future work

Package name Cpp

The special package name Cpp that refers to code written in C++ is not made a keyword by this proposal, but this proposal is also not deciding that it should not be a keyword. While this name has special meaning to the language, it’s not predeclared in any context, so it’s considered to be out of scope. A future proposal that describes the details of C++ import should determine whether this name becomes a keyword. Notably, making Cpp a keyword would also allow an import Cpp declaration to have custom syntax, which may be useful.

Package name Main

The special package name Main that is currently reserved in all package name contexts is not made a keyword in this proposal either. There would be no meaning in making it a keyword, as it is never used as a special package name in Carbon source files. However, we could consider using an empty package name as the name of the main package, and unreserving the package name Main, if it becomes a concern that we reserve this name.

Alternatives considered

Have both predeclared identifiers and keywords

We could provide both predeclared identifiers and keywords. Many languages follow this path. However, predeclared identifiers have some problems compared to keywords:

  • In order to locally declare a name matching a predeclared identifier, the name would need to be shadowed.
    • Such shadowing may be invalid, depending on how the name is used.
    • Readability is harmed by using a name used as basic vocabulary with a different, local meaning.
    • Shadowing a predeclared identifier typically makes the original name hard to access – an alias or similar must be established in advance.
  • There need to be two different stories for how to deal with adding a new word with special meaning to the language, depending on whether it is a keyword.
  • For each word with special meaning, we must make an arbitrary decision as to which kind it is, resulting in a largely meaningless distinction that nonetheless is visible and would need to be known by developers in some contexts.

Reserve words with a certain spelling

We could reserve words with certain spellings for future use as keywords or as vendor extensions. Some languages do this:

  • C reserves words starting with an underscore followed by a capital letter or an underscore.
  • C++ additionally reserves words containing a double underscore anywhere.
  • Python uses the __name__ namespace for certain special names, and by convention these names are reserved for that purpose.

In Carbon we could accomplish this by saying that all words of the reserved forms are keywords, with no meaning ascribed to them yet.

However, we do not have a clear need for such reserved words at this time, and we would not want to use such spellings when we do add language keywords later. Moreover, C++ programs frequently declare reserved words in practice, and we should expect the same in Carbon. Without enforcement, the names are not effectively reserved.

If we find a need at a later time to introduce vendor-specific language extension keywords, we can revisit this, but should also consider alternatives such as a k#foo spelling to turn what is normally an identifier into a (potentially vendor-specific) keyword.