Visibility of Top-Level Declarations
In the Cangjie programming language, access modifiers can be used to control the visibility of top-level declarations such as types, variables, and functions. Cangjie provides four access modifiers: private, internal, protected, and public. The semantics of these modifiers when applied to top-level elements are as follows:
- private: Visible only within the current file. Members with this modifier cannot be accessed from different files.
- internal: Visible only within the current package and its subpackages (including nested subpackages). Members can be accessed without import within the same package, while subpackages (including nested subpackages) can access these members through imports.
- protected: Visible only within the current module. Files in the same package can access these members without import, while other packages within the same module (but in different packages) can access them through imports. Packages from different modules cannot access these members.
- public: Visible both inside and outside the module. Files in the same package can access these members without import, while other packages can access them through imports.
| Modifier | File | Package & Subpackages | Module | All Packages |
|---------------|------|-----------------------|--------|--------------|
| private | Y | N | N | N |
| internal | Y | Y | N | N |
| protected | Y | Y | Y | N |
| public | Y | Y | Y | Y |
Different top-level declarations support specific access modifiers and have default modifiers (default modifiers apply when the modifier is omitted; these defaults can also be explicitly specified):
- package: Supports internal, protected, and public, with public as the default modifier.
- import: Supports all access modifiers, with private as the default modifier.
- Other top-level declarations support all access modifiers, with internal as the default modifier.
The access level hierarchy in Cangjie is public > protected > internal > private. The access modifier of a declaration cannot be higher than the access level of the types used within that declaration. Refer to the following examples:
- Parameters and return values in function declarations
- Variable declarations
- Type arguments for generic types
- Type bounds in where constraints
Notably:
- public declarations can use any types visible within their package in their initialization expressions or function bodies, including both public and non-public types.
- public top-level declarations can use anonymous functions or any top-level functions, including both public and non-public top-level functions.
- Built-in types such as Rune and Int64 default to public visibility.
> Note:
>
> Within the same package, private custom types (e.g., struct, class, enum, and interface) with the same name are not supported in certain scenarios. Unsupported cases will trigger compiler errors.
For example, in the following program, example1.cj and example2.cj share the same package name. example1.cj defines a private class A, while example2.cj defines a private struct A.
Running this program will output:
package a
private func f1() { 1 } // f1 is visible only within the current file
func f2() { 2 } // f2 is visible only within the current package and subpackages
protected func f3() { 3 } // f3 is visible only within the current module
public func f4() { 4 } // f4 is visible both inside and outside the module// example1.cj
package test
private class A {}
public class D<T> {
private let a: A = A()
}// example2.cj
package test
private struct A {}
public class C<T> {
private let a: A = A()
}error: currently, it is not possible to export two private declarations with the same name