Rule Reference¶
Each rule is listed with its default status, a description of what it checks, and examples of incorrect and correct code.
style/acronym-casing¶
Default: on
Known acronyms in type names must be fully uppercased. The recognized acronyms are: API, AST, CSS, DNS, FFI, FIFO, HTML, HTTP, IMAP, JSON, MIME, SMTP, SSH, SSL, TCP, TLS, UDP, URI, URL, UUID, XML.
Incorrect:
class JsonParser
primitive HttpMethod
Correct:
class JSONParser
primitive HTTPMethod
style/blank-lines¶
Default: on
Blank line conventions within and between entities.
Within entities:
- No blank line between the entity declaration and the first body content (docstring or first member).
- No blank lines between consecutive fields.
- Exactly one blank line before each method. Exception: when both the preceding method and the current method are one-liners, zero blank lines are also allowed.
Between entities:
- Exactly one blank line between consecutive entities. Exception: when both entities are one-liners, zero blank lines are also allowed.
Incorrect:
class Foo
let x: U32 = 0
let y: U32 = 1
fun apply(): U32 => x + y
Correct:
class Foo
let x: U32 = 0
let y: U32 = 1
fun apply(): U32 => x + y
style/comment-spacing¶
Default: on
Line comments (//) must be followed by exactly one space. An empty comment (// with nothing after it) is also acceptable. This rule does not apply inside string literals, including triple-quoted strings.
Incorrect:
//This comment has no space
// This comment has two spaces
Correct:
// This comment has one space
//
// Empty comment above is fine
let url = "http://example.com" // inside strings is ignored
style/dot-spacing¶
Default: on
. must have no spaces around it. .> must be spaced as an infix operator with spaces on both sides. Both operators skip the “before” check on continuation lines where the operator is the first non-whitespace character.
Incorrect:
let x = foo .bar
let y = foo. bar
let z = foo.>bar
Correct:
let x = foo.bar
let y = foo .> bar
// Continuation lines are fine
let z = foo
.bar
.> baz
style/file-naming¶
Default: on
The file name must match the principal type defined in the file, converted to snake_case. The principal type is determined by a heuristic: if the file contains a single entity, that entity is principal. If a trait or interface is present alongside other types, the trait or interface is principal. Files with multiple unrelated types (no clear principal) are not checked. Private types preserve their leading underscore in the filename.
Files named _test.pony that contain a Main actor are exempt (standard test runner convention).
Incorrect:
// File: parser.pony
class FooParser
// Error: expected file name foo_parser.pony
Correct:
// File: foo_parser.pony
class FooParser
// File: _private_helper.pony
class _PrivateHelper
// File: runnable.pony
trait Runnable
class Runner // trait is principal, so runnable.pony is correct
style/hard-tabs¶
Default: on
Tab characters are not allowed anywhere in source files. Pony uses spaces for indentation.
A violation is a literal tab character in the source. Since tabs are invisible in rendered text, a tab-indented line looks like a space-indented line but triggers this rule. Editors should be configured to insert spaces instead of tabs.
Correct:
actor Main
new create(env: Env) =>
env.out.print("spaces, not tabs")
style/line-length¶
Default: on
Lines must not exceed 80 codepoints. Multi-byte UTF-8 characters count as one codepoint each. A line of exactly 80 codepoints is acceptable; 81 or more triggers a violation.
Incorrect:
// The following line is too long
let description = "This string is far too long to fit within the eighty codepoint limit for lines"
Correct:
let description =
"This string has been split" +
" across multiple lines"
style/match-case-indent¶
Default: on
The | introducing each match case must align with the match keyword’s column. This makes the match structure visually clear regardless of nesting depth. Inline continuation pipes (e.g., | "a" | "b") are not checked since only the leading | on each line needs alignment.
Incorrect:
match x
| let s: String => s
| let n: U32 => n.string()
end
Correct:
match x
| let s: String => s
| let n: U32 => n.string()
end
style/match-no-single-line¶
Default: on
Match expressions must span multiple lines. A single-line match is harder to scan and usually indicates the expression would be clearer as an if/else chain.
Incorrect:
let y = match x | let s: String => s else "" end
Correct:
let y =
match x
| let s: String => s
else
""
end
style/member-naming¶
Default: on
Fields, methods, parameters, and local variables must use snake_case. Names may start with a leading underscore for private visibility. The discard pattern _ by itself is not checked. Trailing primes (e.g., value') are permitted.
Incorrect:
class Foo
let myField: U32 = 0
var someValue: String = ""
fun doSomething(): None =>
let myVar: U32 = 1
None
Correct:
class Foo
let my_field: U32 = 0
var _some_value: String = ""
fun do_something(): None =>
let my_var: U32 = 1
None
style/package-naming¶
Default: off
The package directory name must be snake_case, containing only lowercase letters, digits, and underscores. This rule is off by default because application packages often use hyphens to match CLI naming conventions.
Incorrect (if enabled):
MyPackage/
main.pony
my-package/
main.pony
Correct:
my_package/
main.pony
style/partial-call-spacing¶
Default: on
The ? at partial call sites must immediately follow ) with no space. This is the opposite convention from method declarations.
Incorrect:
let x = foo() ?
let y = bar(1, 2) ?
Correct:
let x = foo()?
let y = bar(1, 2)?
style/partial-spacing¶
Default: on
The ? in partial method declarations must have surrounding spaces. A space is required before ? and a space or end-of-line after it.
Incorrect:
class Foo
fun bar()? => None
Correct:
class Foo
fun bar() ? => None
style/public-docstring¶
Default: on
Public types and public methods must have a docstring. A type or method is public if its name does not start with _.
Several exemptions apply. No docstring is required for:
- Types or methods annotated with
\nodoc\ - Methods inside private types or
\nodoc\-annotated types Mainactors- Well-known method names:
create,string,eq,ne,hash,hash64,compare,lt,le,ge,gt,dispose,has_next,next,values,size - Type aliases (Pony does not support docstrings on type aliases)
- Methods inside anonymous
objectliterals - Concrete methods with 3 or fewer top-level expressions in the body (abstract methods are not exempt)
Incorrect:
class Foo
fun my_method(a: U32, b: U32, c: U32, d: U32): U32 =>
let x = a + b
let y = c + d
let z = x * y
z + 1
Correct:
class Foo
"""A class that does arithmetic."""
fun my_method(a: U32, b: U32, c: U32, d: U32): U32 =>
"""Combine four values through addition and multiplication."""
let x = a + b
let y = c + d
let z = x * y
z + 1
fun apply(): U32 =>
// Exempt: 3 or fewer expressions
let x: U32 = 1
let y: U32 = 2
x + y
style/trailing-whitespace¶
Default: on
Lines must not have trailing spaces or tabs. Completely empty lines (zero length) are not flagged.
Because trailing whitespace is invisible in rendered text, violations are not visible in code examples. A violation is one or more space or tab characters between the last visible character on a line and the line ending.
Correct:
class Foo
fun apply(): None =>
let x = 1
None
style/type-naming¶
Default: on
Type names must use CamelCase. Names may start with a leading underscore for private visibility. After the optional leading underscore, the name must begin with an uppercase letter and contain only letters and digits. Underscores within the name are not allowed. Trailing primes are permitted.
Incorrect:
class foo_parser
primitive my_helper
actor some_actor
Correct:
class FooParser
primitive _MyHelper
actor SomeActor