Chapters Syntax & types

Syntax & types

On this page

Proposed syntax

These are design decisions, not a description of a working implementation. Some behavior is still unresolved.

Functions and blocks

Declare a function with fn, explicit parameter types, and an optional return type after the closing parenthesis. A colon and indentation define its body.

fn search(nums: [int], target: int) int:
    left = 0
    right = nums.size - 1

There is no arrow before the return type. Birdie aims to infer return types when they are unambiguous.

Static types, local inference

Birdie is designed to be statically typed. It infers local variable types, collection types, and generic arguments where practical. Ambiguous types should produce a diagnostic rather than silently become dynamic values.

The initial design includes:

Type Meaning
int Signed, arbitrary-precision integer
bool true or false
str String, written with double quotes
char One Unicode scalar value, written with single quotes
[T] Growable list of elements of type T
(A, B) Fixed pair with a type for each position

Variables

= introduces a variable if the name is new, or reassigns an existing variable. Reassignment must remain compatible with the inferred type.

Variables require an initial value. Every read must have an assignment on every execution path that reaches it. Assignment inside a block updates an existing enclosing local variable.

Whether a variable first introduced in a block is visible outside that block is still an open question.

Loops

A single binding yields values. Two bindings yield the zero-based index and value.

for num in nums:
    seen[num] = true

for i, num in nums:
    seen[num] = i

while tests the condition before each iteration. Parenthesized bindings unpack a tuple, as in for (x, y) in points:.

Conditions

Conditions accept booleans, lists, maps, and stacks. Empty collections are false; nonempty collections are true. Numbers require an explicit comparison, such as count != 0.

not returns a boolean. or evaluates left to right and short-circuits when the left operand is true.

Integers and division

int does not have fixed-width overflow, but its size is limited by available resources. The cost of an operation depends on operand size.

// is floor division: 7 // 2 is 3, while -7 // 2 is -4. Division by zero is a runtime error. / is reserved for fractional division; floating-point behavior remains undecided.

Strings and characters

String iteration yields char values. String length and indices count Unicode scalar values, not bytes. A visible symbol may contain more than one scalar value.

An empty or multi-scalar character literal is an error. Conversion and concatenation between char and str are still open questions.