Core syntax Control flow

Statements and Control Flow

Klyn uses indentation-defined blocks and a compact statement vocabulary. This page covers the control-flow statements you will use constantly in real code.

Assignment
count = 10
name as String = "Ada"
count += 1
count--

Assignment updates the nearest visible variable while preserving its established type. If no visible variable has that name, the assignment declares it in the current lexical block. Such a declaration is not visible after that block ends.

If, Elif, Else
score = 72
if score >= 90:
    print("excellent")
elif score >= 50:
    print("pass")
else:
    print("retry")

Every branch owns a lexical scope. A variable declared before the conditional can be updated by any branch; a variable first declared in an if, elif, or else branch remains local to that branch.

score = 72
label = "unknown"

if score >= 50:
    label = "pass"
    congratulation = "well done"
else:
    label = "retry"

print(label)
# print(congratulation)  # TypeError: the name belongs to the if branch.
Match
value = 2
match value:
    case 0:
        print("zero")
    case 1 | 2:
        print("small")
    case 3 to 10:
        print("range")
    default:
        print("other")

match compares one subject against ordered cases. A case can use an exact value, several alternatives separated by |, or an inclusive interval with to. default handles the fallback branch.

text = "dominique@example.com"
match text:
    case /^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]{2,}$/:
        print("email")
    case /^[0-9]{2}-[0-9]{2}-[0-9]{4}$/:
        print("date")
    default:
        print("unknown")

Regex cases use the same literal syntax as regular expressions and test the subject with pattern matching.

command = "ls"
action = match command:
    case "ls" | "dir":
        "listing"
    case "ps":
        "processes"
    default:
        "unknown"

A match expression returns the expression produced by the first matching branch. Use this form when a value must remain available after the match. Variables first declared inside a case or default block remain local to that branch.

value = 1
result = 0

match value:
    case 0:
        result = 10
        explanation = "zero"
    case 1:
        result = 20
    default:
        result = 30

print(result)
# print(explanation)  # TypeError: explanation belongs to one case only.
While Loops
i = 0
while i < 3:
    print(i)
    i += 1

Use while when the continuation condition depends on values updated in the body. Variables declared before the loop can be updated by it; names first declared in the body are local to the body.

Range Loops
for i = 0 to 5:
    print(i)

Both bounds are inclusive. The example prints 0 through 5. The binding i exists only in the loop body. When iterating over indices, use an explicit upper bound such as values.size - 1.

Collection Iteration
for value in [10, 20, 30]:
    print(value)

config = {"theme": "dark", "fullscreen": true}

for key in config:
    print(key)

for pair in config.items():
    print(pair)

Iterating directly over a map yields keys. Use keys(), values(), or items() when you want a specific view. Each iteration binding is local to its loop and cannot be read after that loop ends.

Break and Continue
while true:
    text = input("> ")
    if text == "":
        continue
    if text == "quit":
        break
    print(text)
Assert and Pass
count = 1
featurePending = true

assert count > 0

if featurePending:
    pass

assert is appropriate for invariants and tests. pass is an explicit placeholder that leaves a block intentionally empty.