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:
ornull, delegate, do, until, and
ref are not Klyn keywords and carry no special syntax. They may be used as normal
identifiers. Loops use while or for. The in keyword is used
for collection membership and for iteration; only out declares an
explicit indirect parameter.
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.