Feng Style Guide
This document records recommended conventions for Feng code. Its purpose is to help projects, teams, and individuals maintain a consistent style without changing language semantics.
Everything in this document is advisory rather than mandatory:
- It does not define syntax.
- It does not change semantic analysis, compiler behavior, or runtime behavior.
- The compiler and runtime must not change a program's meaning based on whether it follows these recommendations.
- Teams may refine these recommendations to suit their collaboration practices or deviate from them for a well-founded reason.
1 General Principles
- Style recommendations should improve readability, consistency, and maintainability rather than introduce additional semantic burden.
- Naming should make a symbol's broad category immediately recognizable, such as a contract, type, member, local binding, or constant-like global binding.
- Keep the style consistent within a file, module, and project. Avoid mixing multiple conventions for the same kind of symbol.
2 Naming
2.1 Naming spec Contracts
- Use PascalCase for contracts declared with
spec, whether they are object contracts or callable contracts. - Rationale: at the point of use, a contract normally acts as an abstract type or callable shape. PascalCase distinguishes it clearly from ordinary values and members.
Recommended:
spec CommitOptions {
var message: i32;
}
spec ValueFormatter(value: i32): string;
2.2 Naming type Declarations and Members
- Use PascalCase for types declared with
type. - Use camelCase for fields, methods, constructor parameters, and ordinary member names.
- This naturally separates type names from member names.
Recommended:
type UserProfile {
let displayName: string;
var loginCount: i32;
func incrementLoginCount(): void {
self.loginCount = self.loginCount + 1;
}
}
2.3 Naming Local let and var Bindings
- Use camelCase for local
letandvarbindings inside functions, methods, and blocks. - Keep names readable even when a variable is used only in a small local scope; avoid abbreviations with no clear meaning.
Recommended:
func commit(message: string): void {
let trimmedMessage = message;
var retryCount = 0;
}
2.4 Naming Immutable Global Bindings
- When a top-level global
letbinding has constant-like semantics, use UPPER_SNAKE_CASE. - The key distinction is not that every
letshould be uppercase, but that a global, immutable, semantically constant value benefits from this convention.
Recommended:
let DEFAULT_PORT = 8080;
let MAX_RETRY_COUNT = 3;
Do not apply the same style to an ordinary local binding:
func run(): void {
let TEMP_VALUE = 1;
}
3 Blank Lines and Layout
3.1 Blank Lines Between Functions and Methods
- Separate functions at the same level with one blank line.
- Separate methods in the same
typewith one blank line. - This makes declaration boundaries easier to scan.
Recommended:
func load(): void {
sync();
}
func save(): void {
flush();
}
type User {
func open(): void {
sync();
}
func close(): void {
flush();
}
}
3.2 Blank Lines Inside Functions and Methods
- Keep function and method bodies compact; normally, do not add blank lines unnecessarily.
- Use a small number of blank lines only when they clearly separate logical phases.
- Prefer uninterrupted reading for short functions.
Recommended:
func commit(message: string): void {
let normalizedMessage = message;
writeLog(normalizedMessage);
flush();
}
4 Indentation and Braces
4.1 Indentation
- Use two spaces consistently for indentation.
- Do not mix indentation widths within a file.
- If a project uses an automatic formatter, configure its default output to follow this guide.
Recommended:
func main(args: string[]) {
if true {
print(args);
}
}
4.2 Brace Placement
- Put an opening brace on the same line as the construct that introduces the block.
- Apply this convention to
func,type,if,else,for,while,try,catch,defer, and other block constructs.
Recommended:
type User {
func commit(message: i32): i32 {
return message;
}
}
if ready {
run();
} else {
stop();
}
5 Consistency
- Consistency matters more than any individual style recommendation.
- When a project already has a stable style, new code should follow the existing conventions.
- If a team later provides an automatic formatter, treat its output as the automated application of these recommendations. This document remains a style guide, not a language definition.
5.1 Keep Type Suffixes Adjacent
- Write the array type suffix
[]immediately after the preceding type, without a space between the type and the brackets. - Apply the same rule after a generic type instance. Prefer
string[]andMap<K, V>[]overstring []andMap<K, V> [].
5.2 Keep Generic Angle Brackets Adjacent
- Write generic parameter lists and explicit type-argument lists immediately after the preceding type, function, or method name. Do not insert a space before
<or before>. - Apply the same convention to constrained type parameters and nested generics. Prefer
Map<K: Hashable<K>, V>andBox<Map<string, int>>overMap < K: Hashable<K>, V >andBox<Map<string, int> >.
6 Documentation Comments
6.1 Public API Documentation Comments
- Always place a
/** */documentation comment immediately before a public API, especially for public declarations in thestdstandard library and official packages. - Provide a concise and accurate summary for top-level
open type,open spec,open fit, andopen funcdeclarations, as well as public member methods. - Add
@param,@return, or implementation notes when parameters, return values, complexity, zero-value behavior, or visible side effects affect how callers use the API. - When a public API explicitly
throws a catchable Feng exception, use@throwsto document its type or value and the condition that triggers it. - When a public API invokes a runtime panic because the caller violated a precondition, use
@panicto document that condition. Do not write it as@throws, because a runtime panic is not a Feng exception thatcatchcan handle. There is no need to repeat non-caller preconditions such as allocation failure or corrupted runtime state on every API. - Document stable semantics that callers need to know. Avoid turning internal implementation details that may change into API contracts.
7 Relationship to Other Documentation
- This document describes recommended style only; it does not define syntax or semantics.
- This document provides coding-style guidance only; it does not define syntax, semantics, the type system, function rules, lifetimes, or interoperability behavior.