- Proposal: ARO-0052
- Author: ARO Language Team
- Status: Implemented
- Requires: ARO-0001
This proposal extends numeric literal syntax to allow underscore (_) characters as visual separators in decimal integer and floating-point literals. This feature improves readability of large numbers by allowing grouping of digits, consistent with existing support for underscores in hexadecimal and binary literals.
Large numeric literals are difficult to read without visual grouping:
Create the <budget> with 1000000000.
Create the <population> with 7900000000.
Create the <pi-precise> with 3.14159265358979.
These numbers require mental effort to count digits and understand magnitude.
Underscore separators allow natural digit grouping:
Create the <budget> with 1_000_000_000.
Create the <population> with 7_900_000_000.
Create the <pi-precise> with 3.141_592_653_589_79.
The underscores are purely visual and do not affect the numeric value.
ARO already supports underscores in hexadecimal and binary literals:
Create the <color> with 0xFF_FF_FF.
Create the <flags> with 0b1010_1010.
This proposal extends the same convenience to decimal literals.
integer_literal = [ "-" ] , digit , { digit | "_" , digit } ;Valid examples:
1_000
1_000_000
1_000_000_000
123_456_789
Invalid examples:
_1000 (* Cannot start with underscore *)
1000_ (* Cannot end with underscore *)
1__000 (* Cannot have adjacent underscores *)
float_literal = [ "-" ] , integer_part , "." , fraction_part , [ exponent ] ;
integer_part = digit , { digit | "_" , digit } ;
fraction_part = digit , { digit | "_" , digit } ;
exponent = ( "e" | "E" ) , [ "+" | "-" ] , digit , { digit | "_" , digit } ;Valid examples:
1_234.567_890
3.141_592_653
1_000.00
1e1_0
1.5e1_000
Invalid examples:
1_.5 (* Underscore cannot be adjacent to decimal point *)
1._5 (* Underscore cannot be adjacent to decimal point *)
1.5_e10 (* Underscore cannot be adjacent to exponent marker *)
1.5e_10 (* Underscore cannot be adjacent to exponent marker *)
Underscores do not affect the numeric value:
| Literal | Value |
|---|---|
1_000_000 |
1000000 |
1000000 |
1000000 |
1_234.567_890 |
1234.56789 |
1234.56789 |
1234.56789 |
Underscores can appear between any digits, not just at thousand separators:
(* All valid - grouping is flexible *)
Create the <binary-style> with 1111_0000_1111_0000.
Create the <phone-style> with 555_123_4567.
Create the <date-style> with 2024_01_15.
The scanNumber() method in Lexer.swift is modified to:
- Accept
_characters between digits in the integer part - Accept
_characters between digits after the decimal point - Accept
_characters between digits in the exponent - Filter out underscores before parsing with
Int()orDouble()
The lexer enforces:
- Underscore must be between two digits
- No leading underscores (before first digit)
- No trailing underscores (after last digit)
- No adjacent underscores
- No underscores adjacent to
.ore/E
(Application-Start: Financial Demo) {
Create the <principal> with 1_000_000.
Create the <rate> with 0.05.
Create the <years> with 10.
Compute the <interest> from <principal> * <rate> * <years>.
Log "Interest on $1,000,000: " to the <console>.
Log <interest> to the <console>.
Return an <OK: status> for the <demo>.
}
(Application-Start: Science Demo) {
Create the <avogadro> with 6.022_140_76e23.
Create the <planck> with 6.626_070_15e-34.
Log "Avogadro's number: " to the <console>.
Log <avogadro> to the <console>.
Return an <OK: status> for the <demo>.
}
(Application-Start: Large Numbers) {
Create the <billion> with 1_000_000_000.
Create the <trillion> with 1_000_000_000_000.
Log "One billion: " to the <console>.
Log <billion> to the <console>.
Log "One trillion: " to the <console>.
Log <trillion> to the <console>.
Return an <OK: status> for the <demo>.
}
| Language | Syntax | Example |
|---|---|---|
| ARO | _ separator |
1_000_000 |
| Swift | _ separator |
1_000_000 |
| Rust | _ separator |
1_000_000 |
| Python | _ separator |
1_000_000 |
| Java | _ separator |
1_000_000 |
| JavaScript | _ separator |
1_000_000 |
ARO follows the widely-adopted convention of using underscores as numeric separators.
| Aspect | Description |
|---|---|
| Purpose | Improve readability of large numeric literals |
| Syntax | Underscore (_) between digits |
| Scope | Decimal integers, floats, and exponents |
| Semantics | Purely visual, no effect on value |
| Consistency | Matches existing hex/binary underscore support |
Sources/AROParser/Lexer.swift- Lexer implementationTests/AROParserTests/LexerTests.swift- Unit testsExamples/NumericSeparators/- Example usage- ARO-0001: Language Fundamentals - Number literal syntax