Lexical Structure
Klyn source files are intentionally simple to read: indentation defines blocks, comments use
#, and most punctuation exists only where it improves clarity. This page covers
the lexical rules you need before writing larger programs.
#!/usr/bin/env klyn
package my.app
import klyn.math
const LIMIT = 10
def compute() as Int:
return Int(Random.random() * LIMIT)
Not every file needs every part. The shebang is optional. Omitting the package declaration
places the source in the default package; its directory never creates an implicit package.
A declared package must match the source directory. Imports appear only when you need packages
outside the automatically imported base package klyn.
A block starts after a trailing :. The following lines must be indented with
spaces. Misaligned blocks and tabs are syntax errors.
if total > 0:
print("positive")
else:
print("zero or negative")
Keep top-level code flush-left. Leading indentation before a top-level statement is rejected, and tabs should not be used as indentation.
A variable belongs to the block in which it is first declared. It is visible from nested
blocks, but never from a parent or sibling block. This rule applies consistently to
if, for, while, try, catch,
finally, and every branch of a match. A for binding is
local to its loop.
total = 0
for value in [10, 20, 30]:
doubled = value * 2
total += doubled
print(total) # 120
# print(value) # TypeError: value is outside its scope
An assignment targets the nearest visible variable. Declare shared state before entering a control-flow block when that block must update it. A name first assigned inside the block instead belongs to that block and disappears when execution leaves it.
calculationRequired = true
result = 0
if calculationRequired:
result = 42 # Updates the enclosing variable.
elapsed = 5 # Declares a variable local to this branch.
print(result)
# print(elapsed) # TypeError: elapsed is outside its scope.
Sibling branches never share declarations made inside one another. For a computed selection,
prefer a match expression so the compiler can infer one compatible result type
without leaking branch-local names.
status = 200
label = match status:
case 200:
"success"
case 404:
"not found"
default:
"error"
| Kind | Typical form | Examples |
|---|---|---|
| Types | UpperCamelCase | Rational, TimeZone, ArrayList |
| Functions and methods | lowerCamelCase | timeMs, toString |
| Variables and properties | lowerCamelCase | count, userName |
| Private backing fields | leading underscore | _value, _items |
count = 10
unsignedCount = 10u
ratio = 0.5
floatRatio = 0.5f
notANumber = nan
singleInfinity = inff
utf16Unit = `A`
initial = 'A'
smile = '😀'
name = "Klyn"
message = """First line
Second line
Third line"""
Integer literals default to Int. Floating-point literals default to
Double. Explicit suffixes such as u and f are useful
when you want a more precise literal type at the source level. Klyn also reserves
nan, nanf, inf, and inff for special
floating-point values; their exact types and comparison rules are detailed in
Typing and Constants.
Backticks delimit one 16-bit CodeUnit, while apostrophes delimit one Unicode
scalar Char. A Char can therefore hold a supplementary character such
as 😀 without splitting it into UTF-16 surrogates. See
CodeUnit, Char, and Unicode for conversions and the
string indexing model.
Klyn includes keywords for declarations, flow control, typing, and object-oriented features. The ones you will encounter first are:
Continue with Packages and Imports before splitting code across multiple files or packages.
Line comments start with
#. KlynDoc-style documentation comments use the familiar/** ... */form.