# Part I: Foundation

**In this part:**

- [Introduction](#introduction) - What is Jac, principles, comparison to Python
- [Getting Started](#getting-started) - Installation, first program, CLI basics
- [Language Basics](#language-basics) - Syntax, comments, code structure
- [Types and Values](#types-and-values) - Type system, generics, literals
- [Variables and Scope](#variables-and-scope) - Local, instance, global variables
- [Operators](#operators) - Arithmetic, comparison, logical, graph operators
- [Control Flow](#control-flow) - Conditionals, loops, pattern matching

---

## Introduction

### 1 What is Jac?

Jac is an AI-native full-stack programming language with Python-like syntax that compiles to Python bytecode, JavaScript, and native machine code (C-ABI compatible). It introduces Object-Spatial Programming (OSP) and novel constructs for AI-integrated programming (such as `by llm()`), providing a unified language for backend, frontend, and AI development with full access to the PyPI, npm, and native ecosystems.

```jac
with entry {
    print("Hello, Jac!");
}
```

### 2 The Six Principles

| Principle | Description |
|-----------|-------------|
| **AI-Native** | LLMs as first-class citizens through Meaning Typed Programming |
| **Full-Stack** | Backend and frontend in one unified language |
| **Multi-Target** | Compiles to Python bytecode, JS, and native machine code -- full PyPI, npm, and native ecosystem access |
| **Object-Spatial** | Graph-based domain modeling with mobile walkers |
| **Cloud-Native** | One-command deployment with automatic scaling |
| **Human & AI Friendly** | Readable structure for both humans and AI models |

### 3 Designed for Humans and AI

Jac is built for clarity and architectural transparency:

- `has` declarations for clean attribute definitions
- `impl` separation keeps interfaces distinct from implementations
- Structure that humans can reason about AND models can reliably generate

### 4 When to Use Jac

Jac excels at:

- Graph-structured applications (social networks, knowledge graphs)
- AI-powered applications with LLM integration
- Full-stack web applications
- Agentic AI systems
- Rapid prototyping

### 5 Jac vs Python

```jac
obj Person {
    has name: str;
    has age: int;

    def greet() -> str {
        return f"Hi, I'm {self.name}";
    }
}
```

**Key differences from Python:**

| Feature | Python | Jac |
|---------|--------|-----|
| Blocks | Indentation | Braces `{}` |
| Statements | Newline-terminated | Semicolons required |
| Fields | `self.x = x` | `has x: Type;` |
| Methods | `def method():` | `def method() { }` |
| Abilities | N/A | `can` (walker entry/exit only) |
| Types | Optional | Mandatory |

---

## Getting Started

### 1 Installation

```bash
# Full installation with all plugins
pip install jaseci

# Minimal installation
pip install jaclang

# Individual plugins
pip install byllm        # LLM integration
pip install jac-client   # Full-stack web
pip install jac-scale    # Production deployment
```

### 2 Your First Program

Create a file `hello.jac`:

```jac
def greet(name: str) -> str {
    return f"Hello, {name}!";
}

with entry {
    print(greet("World"));
}
```

Run it:

```bash
jac hello.jac
```

Note: `jac` is shorthand for `jac run`.

### 3 Project Structure

```
my_project/
├── jac.toml           # Project configuration
├── main.jac           # Entry point
├── app.jac            # Full-stack entry (jac-client)
├── models/
│   ├── __init__.jac
│   └── user.jac
└── tests/
    └── test_models.jac
```

**File Extensions:**

| Extension | Purpose |
|-----------|---------|
| `.jac` | Universal Jac code (head module) |
| `.sv.jac` | Server-variant code |
| `.cl.jac` | Client-variant code |
| `.na.jac` | Native-variant code (compiles to LLVM IR, JIT-executed) |
| `.impl.jac` | Implementation file (annex) |
| `.test.jac` | Test file (annex) |

Files sharing the same base name form a single logical module. For example, `mymod.jac`, `mymod.sv.jac`, `mymod.cl.jac`, `mymod.impl.jac`, and `mymod.test.jac` are all part of the `mymod` module. Variant files (`.sv.jac`, `.cl.jac`, `.na.jac`) are automatically discovered and merged during compilation -- see [Variant Modules](functions-objects.md#variant-modules) for details.

### 4 Editor Setup

Install the VS Code extension for Jac language support:

```bash
# Start the language server
jac lsp
```

---

## Language Basics

### 1 Source Code Encoding

Jac source files are UTF-8 encoded. Unicode is fully supported in strings and comments.

### 2 Comments

```jac
# Single-line comment

#* Multi-line
   comment *#

"""Docstring for modules, classes, and functions"""
```

!!! tip "Coming from Python"
    The biggest syntactic differences: Jac uses **braces** `{ }` instead of indentation for blocks, and **semicolons** `;` to terminate statements. Everything else -- variables, control flow, imports -- is very similar to Python.

### 3 Statements and Expressions

All statements end with semicolons:

```jac
with entry {
    x = 5;
    print(x);
    result = compute(x) + 10;
}
```

### 4 Code Blocks

Code blocks use braces:

```jac
with entry {
    if condition {
        statement1;
        statement2;
    }
}
```

### 5 Keywords

Jac keywords are reserved and cannot be used as identifiers:

| Category | Keywords |
|----------|----------|
| **Archetypes** | `obj`, `node`, `edge`, `walker`, `class`, `enum` |
| **Abilities** | `can`, `def`, `init`, `postinit` |
| **Access** | `pub`, `priv`, `protect`, `static`, `override`, `abs`, `Self` |
| **Control** | `if`, `elif`, `else`, `while`, `for`, `match`, `case`, `switch`, `default` |
| **Loop** | `break`, `continue` |
| **Return** | `return`, `yield`, `report`, `skip` |
| **Exception** | `try`, `except`, `finally`, `raise`, `assert` |
| **OSP** | `visit`, `disengage`, `spawn`, `here`, `root`, `visitor`, `entry`, `exit` |
| **Module** | `import`, `include`, `from`, `as`, `glob` |
| **Blocks** | `cl` (client), `sv` (server), `na` (native) |
| **Other** | `with`, `test`, `impl`, `sem`, `by`, `del`, `in`, `is`, `and`, `or`, `not`, `async`, `await`, `flow`, `wait`, `lambda`, `props` |

**Note:** The abstract modifier keyword is `abs`, not `abstract`.

### 6 Identifiers

Valid identifiers start with a letter or underscore, followed by letters, digits, or underscores.

To use a reserved keyword as an identifier, escape it with a backtick prefix:

```jac
obj Example {
    has `class: str;  # Backtick-escaped keyword used as identifier
}
```

!!! danger
    Backtick-escaped keywords in `has` declarations **do not work** -- they cause a `SyntaxError` in Python's dataclass machinery at runtime. Choose a non-keyword identifier instead (e.g., `has cls: str;` or `has kind: str;`).

!!! note "Special variable references don't need backtick escaping"
    The following are **built-in references**, not regular identifiers. Use them directly without backticks: `self`, `Self`, `super`, `root`, `here`, `visitor`, `init`, `postinit`. `self` is the current instance; `Self` is the enclosing type. For example, write `self.name`, `root ++> node`, and `def init()` -- never `` `self ``, `` `root ``, or `` `init ``.

### 7 Entry Point Variants

Entry points define where code execution begins. Unlike Python's `if __name__ == "__main__"` pattern, Jac provides explicit entry block syntax. Use `entry` for code that always runs, `entry:__main__` for main-module-only code (like tests or CLI scripts), and named entries for exposing multiple entry points from a single file.

!!! tip "Coming from Python"
    Python's `if __name__ == "__main__":` becomes `with entry:__main__ { }`. Plain `with entry { }` runs every time the module loads (like top-level Python code).

```jac
# Default entry - always runs when this module loads
with entry {
    print("Always runs");
}

# Main entry - only runs when this file is executed directly
# Similar to Python's if __name__ == "__main__"
with entry:__main__ {
    print("Only when this file is main");
}
```

---

## Types and Values

Jac is statically typed -- all variables, fields, and function signatures require type annotations. This enables better tooling, clearer APIs, and catches errors at compile time rather than runtime. The type system is compatible with Python's typing module.

### 1 Builtin Types

| Type | Description | Example |
|------|-------------|---------|
| `int` | Integer | `42`, `-17`, `0x1F` |
| `float` | Floating point | `3.14`, `1e-10` |
| `str` | String | `"hello"`, `'world'` |
| `bool` | Boolean | `True`, `False` |
| `bytes` | Byte sequence | `b"data"` |
| `list` | Mutable sequence | `[1, 2, 3]` |
| `tuple` | Immutable sequence | `(1, 2, 3)` |
| `set` | Unique values | `{1, 2, 3}` |
| `dict` | Key-value mapping | `{"a": 1}` |
| `any` | Any type | -- |
| `type` | Type object | -- |
| `None` | Null value | `None` |

**Fixed-width types** (for native code and C interop):

| Type | Description | C Equivalent |
|------|-------------|--------------|
| `i8`, `u8` | 8-bit signed/unsigned integer | `int8_t`, `uint8_t` |
| `i16`, `u16` | 16-bit signed/unsigned integer | `int16_t`, `uint16_t` |
| `i32`, `u32` | 32-bit signed/unsigned integer | `int32_t`, `uint32_t` |
| `i64`, `u64` | 64-bit signed/unsigned integer | `int64_t`, `uint64_t` |
| `f32` | 32-bit float | `float` |
| `f64` | 64-bit float | `double` |
| `c_void` | Opaque pointer | `void*` |

These types are used in `.na.jac` files for C library interop. The compiler automatically coerces between Jac's standard types (`int` = `i64`, `float` = `f64`) and fixed-width types at call boundaries.

### 2 Type Annotations

Type annotations are required for fields and function signatures:

```jac
obj Example {
    has name: str;
    has count: int = 0;
    has items: list[str] = [];
    has mapping: dict[str, int] = {};
}
```

### 3 Generic Types

Jac will support generic type parameters using Python-style syntax (coming soon):

```jac
# Generic function (coming soon):
# def first[T](items: list[T]) -> T {
#     return items[0];
# }

# Generic object (coming soon):
# obj Container[T] {
#     has value: T;
# }

# For now, use `any` as a placeholder:
def first(items: list) -> any {
    return items[0];
}

obj Container {
    has value: any;
}
```

### 4 The `Self` Type

`Self` (capital S) is a special type that refers to the enclosing archetype. It is distinct from `self` (lowercase), which refers to the current instance.

```jac
obj Node {
    has value: int = 0,
        next: Self | None = None;  # Self = Node in type annotations

    class def create(v: int) -> Self {  # Self = cls in class methods
        return Self(value=v);
    }

    def set_next(n: Self) -> Self {  # Self as parameter and return type
        self.next = n;
        return self;
    }
}
```

`Self` is polymorphic -- in a subclass, it resolves to the subclass type, not the parent. See [Class Methods and Self](functions-objects.md#6-static-methods-and-class-methods) for usage details.

### 5 Union Types

```jac
obj Example {
    has value: int | str | None;
}

def process(data: list[int] | dict[str, int]) -> None {
    # Handle either type
}
```

### 6 Type References

Type references are used in OSP operations like filtering graph traversals by node type. The `Root` keyword refers to the root node type in entry/exit clauses, and the `(?:TypeName)` syntax filters collections or traversals by type.

```jac
def example() {
    # In edge references
    [-->](?:Person);  # Filter nodes by Person type
}
```

### 7 Literals

**Numbers:**

```jac
def example() {
    decimal = 42;
    hex = 0x2A;
    octal = 0o52;
    binary = 0b101010;
    floating = 3.14159;
    scientific = 1.5e-10;

    # Underscore separators (for readability)
    million = 1_000_000;
    hex_word = 0xFF_FF;
}
```

**Strings:**

```jac
def example() {
    regular = "hello\nworld";
    raw = r"no\escape";
    bytes_lit = b"binary data";
    x = 42;
    f_string = f"Value: {x}";
    multiline = """
        Multiple
        lines
    """;
}
```

### 8 F-String Format Specifications

F-strings support powerful formatting with the syntax `{expression:format_spec}`.

**Basic formatting:**

```jac
def example() {
    name = "Alice";
    age = 30;

    # Simple interpolation
    greeting = f"Hello, {name}!";

    # With expressions
    message = f"In 5 years: {age + 5}";
}
```

**Width and alignment:**

```jac
def example() {
    name = "Alice";
    # Width specification
    f"{name:10}";           # "Alice     " (10 chars, left-aligned)
    f"{name:>10}";          # "     Alice" (right-aligned)
    f"{name:^10}";          # "  Alice   " (centered)
    f"{name:<10}";          # "Alice     " (left-aligned, explicit)

    # Fill character
    f"{name:*>10}";         # "*****Alice" (fill with *)
    f"{name:-^10}";         # "--Alice---" (centered with -)
}
```

**Number formatting:**

```jac
def example() {
    n = 42;
    pi = 3.14159265;

    # Integer formats
    f"{n:d}";               # "42" (decimal)
    f"{n:b}";               # "101010" (binary)
    f"{n:o}";               # "52" (octal)
    f"{n:x}";               # "2a" (hex lowercase)
    f"{n:X}";               # "2A" (hex uppercase)
    f"{n:05d}";             # "00042" (zero-padded, width 5)

    # Float formats
    f"{pi:f}";              # "3.141593" (fixed-point, 6 decimals default)
    f"{pi:.2f}";            # "3.14" (2 decimal places)
    f"{pi:10.2f}";          # "      3.14" (width 10, 2 decimals)
    f"{pi:e}";              # "3.141593e+00" (scientific notation)
    f"{pi:.2e}";            # "3.14e+00" (scientific, 2 decimals)
    f"{pi:g}";              # "3.14159" (general format)

    # Percentage
    ratio = 0.756;
    f"{ratio:.1%}";         # "75.6%"

    # Thousands separator
    big = 1234567;
    f"{big:,}";             # "1,234,567"
    f"{big:_}";             # "1_234_567" (underscore separator)
}
```

**Sign and padding:**

```jac
def example() {
    x = 42;
    y = -42;

    f"{x:+}";               # "+42" (always show sign)
    f"{y:+}";               # "-42"
    f"{x:05}";              # "00042" (zero-padded)
}
```

**Conversions (`!r`, `!s`, `!a`):**

```jac
def example() {
    text = "hello\nworld";

    f"{text}";              # "hello\nworld" (default str())
    f"{text!s}";            # "hello\nworld" (explicit str())
    f"{text!r}";            # "'hello\\nworld'" (repr())
    f"{text!a}";            # "'hello\\nworld'" (ascii())
}
```

**Nested expressions:**

```jac
def example() {
    width = 10;
    pi = 3.14159;

    # Dynamic width
    f"{pi:{width}}";   # "   3.14159"

    # Expression in format
    value = "test";
    f"{value:>10}";    # "      test"
}
```

**Format specification grammar:**

```
[[fill]align][sign][#][0][width][grouping][.precision][type]

fill      : any character
align     : '<' (left) | '>' (right) | '^' (center) | '=' (pad after sign)
sign      : '+' | '-' | ' '
#         : alternate form (0x for hex, etc.)
0         : zero-pad
width     : minimum width
grouping  : ',' or '_' for thousands
precision : digits after decimal
type      : 's' 'd' 'f' 'e' 'g' 'b' 'o' 'x' 'X' '%'
```

**Collections:**

```jac
def example() {
    list_lit = [1, 2, 3];
    tuple_lit = (1, 2, 3);
    set_lit = {1, 2, 3};
    dict_lit = {"key": "value", "num": 42};
    empty_dict: dict = {};
    empty_list: list = [];
}
```

??? example "Try it: Literals and collections"
    ```jac
    with entry {
        name = "Jac";
        nums = [1, 2, 3, 4, 5];
        info = {"language": name, "version": "0.10"};
        evens = [x for x in nums if x % 2 == 0];
        print(f"{name} evens: {evens}");
        print(f"Info: {info}");
    }
    ```

---

## Variables and Scope

Jac distinguishes between local variables (within functions), instance variables (`has` declarations in objects), and global variables (`glob`). Unlike Python where you assign `self.x = value` in `__init__`, Jac uses declarative `has` statements that make your data model explicit and visible at a glance.

### 1 Local Variables

```jac
def example() {
    # Type inferred
    x = 42;
    name = "Alice";

    # Explicit type
    count: int = 0;
    items: list[str] = [];
}
```

### 2 Instance Variables (has)

The `has` keyword declares instance variables in a clean, declarative style. Unlike Python's `self.x = value` pattern scattered throughout `__init__`, `has` statements appear at the top of your class definition, making the data model immediately visible. This design improves readability for both humans and AI code generators.

!!! tip "Coming from Python"
    In Python you write `self.x = value` inside `__init__`. In Jac, `has x: Type = value;` at the top of an `obj` replaces both the `__init__` parameter and the assignment -- no `self` needed for declarations.

```jac
obj Person {
    has name: str;                    # Required
    has age: int = 0;                 # With default
    static has count: int = 0;        # Static (class-level)
}
```

**Deferred Initialization:**

Use `by postinit` when a field depends on other fields:

```jac
obj Rectangle {
    has width: float;
    has height: float;
    has area: float by postinit;

    def postinit {
        self.area = self.width * self.height;
    }
}
```

### 3 Global Variables (glob)

The `glob` keyword declares module-level variables, replacing Python's convention of bare global assignments.

!!! tip "Coming from Python"
    Python uses plain global assignment (`DEBUG = True`) and the `global` keyword inside functions. Jac uses `glob` for declarations (`glob DEBUG: bool = True;`) and still uses `global` inside functions to modify them.

```jac
glob PI: float = 3.14159;
glob config: dict = {};

with entry {
    print(PI);
}
```

### 4 Scope Rules

**Scope Resolution Order (LEGB):**

When Jac looks up a name, it searches in this order:

1. **L**ocal: Names in the current function/block
2. **E**nclosing: Names in enclosing functions (for nested functions)
3. **G**lobal: Names at module level (`glob` declarations)
4. **B**uilt-in: Pre-defined names (`print`, `len`, `range`, etc.)

```jac
glob x = "global";

def outer -> None {
    x = "enclosing";

    def inner -> None {
        x = "local";
        print(x);  # "local" - found in Local scope
    }

    inner();
    print(x);  # "enclosing" - found in Enclosing scope
}
```

**Modifying outer scope variables:**

```jac
glob counter: int = 0;

def increment -> None {
    global counter;    # Declares intent to modify global
    counter += 1;
}

def outer -> None {
    x = 10;
    def inner -> None {
        nonlocal x;    # Declares intent to modify enclosing
        x += 1;
    }
    inner();
    print(x);  # 11
}
```

**Block scope behavior:**

```jac
def example() {
    if True {
        block_var = 42;    # Created in block
    }
    # block_var is still accessible here in Jac (unlike some languages)

    for i in range(3) {
        loop_var = i;
    }
    # loop_var and i are accessible here
}
```

### 5 Truthiness

Values are evaluated as boolean in conditions. The following are **falsy** (evaluate to `False`):

| Type | Falsy Values |
|------|--------------|
| `bool` | `False` |
| `None` | `None` |
| `int` | `0` |
| `float` | `0.0` |
| `str` | `""` (empty string) |
| `list` | `[]` (empty list) |
| `tuple` | `()` (empty tuple) |
| `dict` | `{}` (empty dict) |
| `set` | `set()` (empty set) |

All other values are **truthy**.

**Examples:**

```jac
def example() {
    # Falsy values
    if not 0 { print("0 is falsy"); }
    if not "" { print("empty string is falsy"); }
    if not [] { print("empty list is falsy"); }
    if not None { print("None is falsy"); }

    # Truthy values
    if 1 { print("non-zero is truthy"); }
    if "hello" { print("non-empty string is truthy"); }
    if [1, 2] { print("non-empty list is truthy"); }

    # Common patterns
    items = [1, 2, 3];
    if items {
        print(items);
    } else {
        print("No items to process");
    }

    # Default value pattern
    user_input = "";
    name = user_input or "Anonymous";
}
```

---

## Operators

Jac includes all standard Python operators plus several unique operators for graph manipulation (`++>`, `-->`, etc.), null-safe access (`?.`, `?[]`), piping (`|>`, `:>`), and LLM delegation (`by`). These Jac-specific operators are covered in sections 6.6-6.9.

### 1 Arithmetic Operators

| Operator | Description | Example |
|----------|-------------|---------|
| `+` | Addition | `a + b` |
| `-` | Subtraction | `a - b` |
| `*` | Multiplication | `a * b` |
| `/` | Division | `a / b` |
| `//` | Floor division | `a // b` |
| `%` | Modulo | `a % b` |
| `**` | Exponentiation | `a ** b` |
| `@` | Matrix multiplication | `a @ b` |

### 2 Comparison Operators

| Operator | Description |
|----------|-------------|
| `==` | Equal |
| `!=` | Not equal |
| `<` | Less than |
| `>` | Greater than |
| `<=` | Less than or equal |
| `>=` | Greater than or equal |
| `is` | Identity |
| `is not` | Not identity |
| `in` | Membership |
| `not in` | Not membership |

### 3 Logical Operators

```jac
def example() {
    a = True;
    b = False;

    # Word form (preferred)
    result = a and b;
    result = a or b;
    result = not a;

    # Symbol form (also valid)
    result = a && b;
    result = a || b;
}
```

### 4 Bitwise Operators

| Operator | Name | Description |
|----------|------|-------------|
| `&` | AND | 1 if both bits are 1 |
| `\|` | OR | 1 if either bit is 1 |
| `^` | XOR | 1 if bits are different |
| `~` | NOT | Inverts all bits |
| `<<` | Left shift | Shifts bits left, fills with 0 |
| `>>` | Right shift | Shifts bits right |

**Examples:**

```jac
def example() {
    flags = 0b1010;
    FLAG_MASK = 0b0010;
    NEW_FLAG = 0b0100;
    value = 16;

    # Bitwise AND - check if bit is set
    has_flag = (flags & FLAG_MASK) != 0;

    # Bitwise OR - set a bit
    flags = flags | NEW_FLAG;

    # Bitwise XOR - toggle a bit
    flags = flags ^ FLAG_MASK;

    # Bitwise NOT - invert all bits
    inverted = ~value;

    # Left shift - multiply by 2^n
    doubled = value << 1;      # value * 2
    quadrupled = value << 2;   # value * 4

    # Right shift - divide by 2^n
    halved = value >> 1;       # value // 2
    quartered = value >> 2;    # value // 4
}
```

**Common bit manipulation patterns:**

```jac
# Check if nth bit is set
def is_bit_set(value: int, n: int) -> bool {
    return (value & (1 << n)) != 0;
}

# Set nth bit
def set_bit(value: int, n: int) -> int {
    return value | (1 << n);
}

# Clear nth bit
def clear_bit(value: int, n: int) -> int {
    return value & ~(1 << n);
}

# Toggle nth bit
def toggle_bit(value: int, n: int) -> int {
    return value ^ (1 << n);
}

# Check if power of 2
def is_power_of_two(n: int) -> bool {
    return n > 0 and (n & (n - 1)) == 0;
}
```

### 5 Assignment Operators

**Simple Assignment:**

```jac
def example() {
    x = 5;
    name = "Alice";
    a = b = c = 0;  # Chained assignment
}
```

**Walrus Operator (`:=`):**

The walrus operator assigns a value and returns it in a single expression:

```jac
def example() {
    items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

    # In conditionals - assign and test
    if (n := len(items)) > 10 {
        print(f"List has {n} items, too many!");
    }

    # In comprehensions
    data = [1, 2, 3];
    results = [y for x in data if (y := x * 2) > 2];

    # In function calls
    text = "hello";
    print(f"Length: {(n := len(text))}, doubled: {n * 2}");
}
```

**Augmented Assignment Operators:**

All augmented assignments modify the variable in place:

| Operator | Equivalent | Description |
|----------|------------|-------------|
| `x += y` | `x = x + y` | Add and assign |
| `x -= y` | `x = x - y` | Subtract and assign |
| `x *= y` | `x = x * y` | Multiply and assign |
| `x /= y` | `x = x / y` | Divide and assign |
| `x //= y` | `x = x // y` | Floor divide and assign |
| `x %= y` | `x = x % y` | Modulo and assign |
| `x **= y` | `x = x ** y` | Exponentiate and assign |
| `x @= y` | `x = x @ y` | Matrix multiply and assign |
| `x &= y` | `x = x & y` | Bitwise AND and assign |
| `x \|= y` | `x = x \| y` | Bitwise OR and assign |
| `x ^= y` | `x = x ^ y` | Bitwise XOR and assign |
| `x <<= y` | `x = x << y` | Left shift and assign |
| `x >>= y` | `x = x >> y` | Right shift and assign |

```jac
def example() {
    count = 0;
    total = 100.0;
    tax_rate = 1.08;
    value = 2;
    flags = 0b0000;
    NEW_FLAG = 0b0100;
    OLD_FLAG = 0b0010;
    bits = 0b1010;
    mask = 0b0011;
    register = 1;

    # Numeric augmented assignment
    count += 1;
    total *= tax_rate;
    value **= 2;

    # Bitwise augmented assignment
    flags |= NEW_FLAG;      # Set a flag
    flags &= ~OLD_FLAG;     # Clear a flag
    bits ^= mask;           # Toggle bits
    register <<= 4;         # Shift left
}
```

### 6 Null-Safe Operators

The `?` operator provides safe access to potentially null values, returning `None` instead of raising an error.

**Safe attribute access (`?.`):**

```jac
obj Profile {
    has settings: dict = {};
}

obj User {
    has profile: Profile | None = None;
}

def example(item: User | None, user: User | None) {
    # Without null-safe: raises AttributeError if item is None
    value = item.profile;

    # With null-safe: returns None if item is None
    value = item?.profile;

    # Chained - stops at first None
    result = user?.profile?.settings;
}
```

**Safe index access (`?[]`):**

The `?[]` operator safely handles both `None` containers and invalid subscripts. It returns `None` instead of raising `IndexError`, `KeyError`, or `TypeError`:

```jac
def example(my_list: list | None, config: dict | None) {
    # Without null-safe: raises TypeError if list is None
    item = my_list[0];

    # With null-safe: returns None if list is None
    item = my_list?[0];

    # Works with dictionaries too
    value = config?["key"];

    # Also handles out-of-bounds indices
    items = [1, 2, 3];
    result = items?[10];         # None (no IndexError)

    # And missing dictionary keys
    data = {"a": 1};
    result = data?["missing"];   # None (no KeyError)
}
```

**Safe method calls:**

```jac
obj Data {
    def transform(param: str) -> Data {
        return self;
    }
    def format() -> str {
        return "formatted";
    }
}

def example(item: Data | None, data: Data | None) {
    # Returns None if item is None, doesn't call method
    result = item?.transform("x");

    # Chained with arguments
    output = data?.transform("param")?.format();
}
```

**Combining with default values:**

```jac
obj User {
    has name: str = "";
    has is_active: bool = True;
}

def example(user: User | None) {
    # Null-safe with fallback using or
    name = user?.name or "Anonymous";

    # In conditionals
    if user?.is_active {
        print(user);
    }
}
```

**In filter comprehensions:**

```jac
obj Item {
    has value: int = 0;
}

def example() {
    items = [Item(value=1), Item(value=-1), Item(value=2)];
    # The ? in filter comprehensions
    valid_items = items(?value > 0);  # Filter where value > 0
}
```

**Behavior summary:**

| Expression | When `obj` is `None` | When `obj` is valid |
|------------|---------------------|---------------------|
| `obj?.attr` | `None` | `obj.attr` |
| `obj?[key]` | `None` | `obj[key]` |
| `obj?.method()` | `None` | `obj.method()` |
| `obj?.a?.b` | `None` | `obj.a.b` (or `None` if `a` is `None`) |

### 7 Graph Operators (OSP)

Graph operators are fundamental to Object-Spatial Programming. They let you create connections between nodes (`++>`) and traverse the graph (`-->`). Unlike traditional object references, graph connections are first-class entities that can have their own types and attributes. Use these operators whenever you're building or navigating graph structures.

**Connection Operators:**

```jac
node Person {
    has name: str;
}

edge Friend {
    has since: int = 2020;
}

with entry {
    node1 = Person(name="Alice");
    node2 = Person(name="Bob");

    # Untyped connections
    node1 ++> node2;         # Forward
    node1 <++ node2;         # Backward
    node1 <++> node2;        # Bidirectional

    # Typed connections
    alice = Person(name="Alice");
    bob = Person(name="Bob");
    alice +>: Friend(since=2020) :+> bob;
}
```

**Edge Reference Operators:**

```jac
node Item {
    has value: int = 0;
}

edge Link {
    has weight: int = 1;
}

walker Visitor {
    can visit with Item entry {
        # All outgoing edges
        neighbors = [-->];

        # All incoming edges
        sources = [<--];

        # Typed outgoing
        linked = [->:Link:->];

        # Filtered by edge attribute
        heavy = [->:Link:weight > 5:->];
    }
}
```

### 8 Pipe Operators

Pipe operators enable functional-style data transformation by passing results from one operation to the next. Instead of deeply nested function calls like `format(filter(transform(data)))`, you write `data |> transform |> filter |> format` -- reading naturally from left to right. Jac offers three pipe variants: standard pipes for functions, atomic pipes for controlling walker traversal order, and dot pipes for method chaining.

**Standard Pipes (`|>`, `<|`):**

```jac
def double(x: int) -> int { return x * 2; }
def add_one(x: int) -> int { return x + 1; }

def example() {
    data = 5;

    # Forward pipe - data flows left to right
    result = data |> double |> add_one;

    # Equivalent to:
    result = add_one(double(data));
}
```

**Atomic Pipes (`:>`, `<:`):**

Atomic pipes are used with spawn operations and affect traversal order:

```jac
node Item {
    has value: int = 0;
}

walker Visitor {
    can visit with Item entry {
        print(here.value);
    }
}

with entry {
    start = Item(value=1);

    # Atomic pipe forward - depth-first traversal
    start spawn :> Visitor();

    # Standard pipe with spawn - breadth-first traversal
    start spawn |> Visitor();
}
```

**Dot Pipes (`.>`, `<.`):**

Dot pipes chain method calls:

```jac
obj Builder {
    has value: int = 0;

    def add(n: int) -> Builder {
        self.value += n;
        return self;
    }
    def double() -> Builder {
        self.value *= 2;
        return self;
    }
}

def example() {
    # Dot forward pipe
    result = Builder() .> add(5) .> double();

    # Equivalent to:
    result = Builder().add(5).double();
}
```

**Pipe with lambdas:**

```jac
def example() {
    numbers = [1, 2, 3, 4, 5, 6, 7, 8];

    # Using lambdas in pipe chains
    result = numbers
        |> (lambda x: list : [i * 2 for i in x])
        |> (lambda x: list : [i for i in x if i > 10])
        |> sum;
}
```

**Comparison of pipe operators:**

| Operator | Name | Direction | Use Case |
|----------|------|-----------|----------|
| `\|>` | Forward pipe | Left to right | Function composition |
| `<\|` | Backward pipe | Right to left | Reverse composition |
| `:>` | Atomic forward | Left to right | Depth-first spawn |
| `<:` | Atomic backward | Right to left | Reverse atomic |
| `.>` | Dot forward | Left to right | Method chaining |
| `<.` | Dot backward | Right to left | Reverse method chain |

### 9 The `by` Operator

The `by` operator is Jac's mechanism for delegation -- handing off work to an external system. Its most powerful use is with the `byllm` plugin, where `by llm` delegates function implementation to a language model. This enables "Meaning Typed Programming" where you declare *what* a function should do, and the LLM provides *how*. The operator is intentionally generic, allowing plugins to define custom delegation targets.

**General Syntax:**

```jac
def example() {
    # Basic by expression
    result = "hello" by "world";

    # Chained by expressions (right-associative)
    result = "a" by "b" by "c";  # Parsed as: "a" by ("b" by "c")

    # With expressions
    result = (1 + 2) by (3 * 4);
}
```

**With byllm Plugin (LLM Delegation):**

When the `byllm` plugin is installed, `by` enables LLM delegation:

```jac
# Function implementation delegated to LLM
def summarize(text: str) -> str by llm();
sem summarize = "Summarize the given text in 2-3 sentences";

def translate(text: str) -> str by llm(model_name="gpt-4");
sem translate = "Translate the given text to French";

with entry {
    result = summarize("Hello world");
}
```

Use the **`sem` keyword** to attach semantic descriptions to functions, parameters, and fields. These descriptions are included in the compiler-generated prompt, giving the LLM additional context beyond what it can infer from names and types:

```jac
obj Ingredient {
    has name: str;
    has cost: float;
}
sem Ingredient.cost = "Estimated cost in USD";

def plan_shopping(recipe: str) -> list[Ingredient] by llm();
sem plan_shopping = "Generate a shopping list for the given recipe";
sem plan_shopping.recipe = "A description of the meal to prepare";
```

!!! tip
    Always use `sem` to provide context for `by llm()` functions. Docstrings are for human documentation and are not included in compiler-generated prompts.

See [Part V: AI Integration](../plugins/byllm.md) for detailed LLM usage.

### 10 Operator Precedence

Complete precedence table from **lowest** (evaluated last) to **highest** (evaluated first):

| Precedence | Operators | Associativity | Description |
|------------|-----------|---------------|-------------|
| 1 (lowest) | `lambda` | - | Lambda expression |
| 2 | `if else` | Right | Ternary conditional |
| 3 | `by` | Right | By operator (LLM delegation) |
| 4 | `:=` | Right | Walrus operator |
| 5 | `or`, `\|\|` | Left | Logical OR |
| 6 | `and`, `&&` | Left | Logical AND |
| 7 | `not` | - | Logical NOT (unary) |
| 8 | `in`, `not in`, `is`, `is not`, `<`, `<=`, `>`, `>=`, `!=`, `==` | Left | Comparison/membership |
| 9 | `\|` | Left | Bitwise OR |
| 10 | `^` | Left | Bitwise XOR |
| 11 | `&` | Left | Bitwise AND |
| 12 | `<<`, `>>` | Left | Bit shifts |
| 13 | `\|>`, `<\|` | Left | Pipe operators |
| 14 | `+`, `-` | Left | Addition, subtraction |
| 15 | `*`, `/`, `//`, `%`, `@` | Left | Multiplication, division, modulo, matmul |
| 16 | `+x`, `-x`, `~` | - | Unary plus, minus, bitwise NOT |
| 17 | `**` | Right | Exponentiation |
| 18 | `await` | - | Await expression |
| 19 | `spawn` | Left | Walker spawn |
| 20 | `:>`, `<:` | Left | Atomic pipes |
| 21 | `++>`, `<++`, connection ops | Left | Graph connection |
| 22 (highest) | `x[i]`, `x.attr`, `x()`, `x?.attr` | Left | Subscript, attribute, call |

**Examples showing precedence:**

```jac
def f(x: int) -> int { return x + 1; }
def g(x: int) -> int { return x * 2; }

def example() {
    a = 1; b = 2; c = 3; cond = True;

    # Ternary binds loosely
    x = a if cond else b + 1;   # x = a if cond else (b + 1)

    # Logical operators
    x = a or b and c;           # x = a or (b and c)
    x = not a and b;            # x = (not a) and b

    # Comparison chaining
    x = 5;
    valid = 0 < x < 10;         # (0 < x) and (x < 10)

    # Arithmetic
    x = a + b * c;              # x = a + (b * c)
    x = a ** b ** c;            # x = a ** (b ** c)

    # Bitwise
    x = a | b & c;              # x = a | (b & c)
    x = a << 2 + 1;             # x = a << (2 + 1)

    # Pipe operators
    result = a |> f |> g;       # result = g(f(a))

    # Walrus in condition
    items = [1, 2, 3];
    if (n := len(items)) > 2 { print(n); }
}
```

**Short-circuit evaluation:**

`and` and `or` use short-circuit evaluation:

```jac
def example() {
    a = 1; b = 2; c = 3;

    # 'and' stops at first falsy value
    result = a and b and c;  # Returns first falsy, or last value

    # 'or' stops at first truthy value
    result = a or b or c;    # Returns first truthy, or last value

    # Common patterns
    user_input = "";
    fallback = "fallback";
    value = user_input or fallback;     # Use fallback if input is falsy
}
```

??? example "Try it: Operators"
    ```jac
    with entry {
        x = 10;
        y = 3;
        print(f"{x} + {y} = {x + y}");
        print(f"{x} ** {y} = {x ** y}");
        print(f"{x} > {y} = {x > y}");
        print(f"not False = {not False}");
        print(f"{x} in [1,5,10] = {x in [1, 5, 10]}");
    }
    ```

---

## Control Flow

Jac's control flow is familiar to Python developers with a few enhancements: braces instead of indentation, semicolons to end statements, and additional constructs like C-style for loops (`for i = 0 to i < 10 by i += 1`) and `switch` statements. Jac also supports Python's pattern matching (`match/case`) for destructuring complex data.

### 1 Conditional Statements

```jac
def example() {
    condition = True;
    other_condition = False;

    if condition {
        print("condition true");
    } elif other_condition {
        print("other condition");
    } else {
        print("else");
    }

    # Ternary expression
    result = "yes" if condition else "no";
}
```

### 2 While Loops

```jac
def example() {
    count = 0;

    while count < 3 {
        print(count);
        count += 1;
    }

    # With else clause (executes if loop completes normally)
    count = 0;
    while count < 3 {
        count += 1;
    } else {
        print("completed");
    }
}
```

### 3 For Loops

Jac supports Python-style iteration and also adds C-style for loops with explicit initialization, condition, and update expressions. The C-style syntax uses `to` for the condition and `by` for the update step -- useful when you need precise control over loop variables.

```jac
def example() {
    items = [1, 2, 3];

    # Iterate over collection (Python-style)
    for item in items {
        print(item);
    }

    # With index
    for (i, item) in enumerate(items) {
        print(f"{i}: {item}");
    }

    # C-style for loop: for INIT to CONDITION by UPDATE
    for i = 0 to i < 10 by i += 1 {
        print(i);
    }

    # With else clause
    for item in items {
        if item == 5 {
            break;
        }
    } else {
        print("Not found");
    }
}
```

### 4 Pattern Matching

Pattern matching lets you destructure and test complex data in a single construct. Unlike a chain of `if/elif` statements, `match` can extract values from lists, dicts, and objects while testing their structure. Use it when handling multiple data shapes or implementing state machines.

!!! warning "Common Gotcha"
    Match case bodies use **Python-style indentation**, not braces. The `case` keyword is followed by a colon, and the body is indented -- this is the one place in Jac where indentation matters.

**Basic Patterns:**

```jac
obj Point {
    has x: int = 0;
    has y: int = 0;
}

def example(value: any) {
    match value {
        case 0:
            print("zero");

        case 1 | 2 | 3:
            print("small");

        case [x, y]:
            print(f"pair: {x}, {y}");

        case {"key": v}:
            print(f"dict with key: {v}");

        case Point(x=x, y=y):
            print(f"point at {x}, {y}");

        case _:
            print("default");
    }
}
```

**Advanced Patterns:**

```jac
def example(data: any) {
    match data {
        case [1, *middle, 5]:              # Spread: capture remainder
            print(f"Middle: {middle}");

        case {"key1": 1, **rest}:          # Dict spread
            print(f"Rest: {rest}");

        case [1, 2, last as captured]:     # As: bind to name
            print(f"Captured: {captured}");

        case [1, 2] | [3, 4]:              # Or: match either
            print("Matched");
    }
}
```

**Pattern Types:**

| Pattern | Example | Description |
|---------|---------|-------------|
| Literal | `case 42:` | Match exact value |
| Capture | `case x:` | Capture into variable |
| Wildcard | `case _:` | Match anything, don't capture |
| Sequence | `case [a, b]:` | Match list/tuple structure |
| Mapping | `case {"k": v}:` | Match dict structure |
| Class | `case Point(x, y):` | Match class instance |
| Or | `case 1 \| 2:` | Match any option |
| As | `case x as name:` | Capture with alias |
| Star | `case [first, *rest]:` | Capture sequence remainder |
| Double-star | `case {**rest}:` | Capture dict remainder |

### 5 Switch Statement

```jac
def example(value: int) {
    switch value {
        case 1:
            print("one");

        case 2:
            print("two");

        default:
            print("other");
    }
}
```

Note: Like C, cases fall through to subsequent cases. Use `break` to prevent fall-through.

### 6 Loop Control

```jac
def example() {
    items = [1, 2, 3, 4, 5];

    for item in items {
        if item == 2 {
            continue;    # Skip to next iteration
        }
        if item == 4 {
            break;       # Exit loop
        }
        print(item);
    }
}
```

### 7 Context Managers

```jac
def example() {
    with open("file.txt") as f {
        content = f.read();
    }

    # Multiple context managers
    with open("in.txt") as fin, open("out.txt", "w") as fout {
        fout.write(fin.read());
    }
}
```

### 8 Exception Handling

**Basic try/except:**

```jac
def risky_operation() -> int {
    raise ValueError("error");
}

def example() {
    try {
        result = risky_operation();
    } except ValueError {
        print("Value error occurred");
    }
}
```

**Capturing the exception:**

```jac
import json;

def example(input: str) {
    try {
        data = json.loads(input);
    } except ValueError as e {
        print(f"Parse error: {e}");
    } except KeyError as e {
        print(f"Missing key: {e}");
    }
}
```

**Multiple exception types:**

```jac
def process(data: any) -> None {
    print(data);
}

def example(data: any) {
    try {
        process(data);
    } except (TypeError, ValueError) as e {
        print(f"Type or value error: {e}");
    }
}
```

**Full try/except/else/finally:**

```jac
def example() {
    default_data = "default";
    file = None;
    data = "";

    try {
        file = open("data.txt");
        data = file.read();
    } except FileNotFoundError {
        print("File not found");
        data = default_data;
    } except PermissionError as e {
        print(f"Permission denied: {e}");
        raise;  # Re-raise the exception
    } else {
        # Executes only if no exception occurred
        print(f"Read {len(data)} bytes");
    } finally {
        # Always executes (cleanup)
        if file {
            file.close();
        }
    }
}
```

**Raising exceptions:**

```jac
def validate(input: str) -> None {
    if not input {
        # Raise an exception
        raise ValueError("Invalid input");
    }
}

def process(item: str) -> None {
    try {
        validate(item);
    } except ValueError as e {
        # Re-raise with more context
        raise RuntimeError(f"Failed to process: {item}") from e;
    }
}
```

**Custom exceptions:**

```jac
obj ValidationError(Exception) {
    has field: str;
    has message: str;
}

def validate(data: dict) -> None {
    if "name" not in data {
        raise ValidationError(field="name", message="Name is required");
    }
}
```

### 9 Assertions

Assertions verify conditions during development:

```jac
def example() {
    condition = True;
    items = [1, 2, 3];
    value = 42;

    # Basic assertion
    assert condition;

    # Assertion with message
    assert len(items) > 0, "Items list cannot be empty";

    # Type checking
    assert isinstance(value, int), f"Expected int, got {type(value)}";
}

# Invariant checking in class methods
obj Account {
    has balance: float = 0.0;

    def withdraw(amount: float) -> None {
        assert amount > 0, "Withdrawal amount must be positive";
        assert amount <= self.balance, "Insufficient funds";
        self.balance -= amount;
    }
}
```

**Note:** Assertions can be disabled in production with optimization flags. Use exceptions for validation that must always run.

### 10 Generator Functions

Generators produce values lazily using `yield`:

**Basic generator:**

```jac
def count_up(n: int) -> int {
    for i in range(n) {
        yield i;
    }
}

with entry {
    # Usage
    for num in count_up(5) {
        print(num);  # 0, 1, 2, 3, 4
    }
}
```

**Generator with state:**

```jac
def fibonacci(limit: int) -> int {
    a = 0;
    b = 1;
    while a < limit {
        yield a;
        (a, b) = (b, a + b);
    }
}
```

**yield from (delegation):**

```jac
def flatten(nested: list) -> any {
    for item in nested {
        if isinstance(item, list) {
            yield from flatten(item);  # Delegate to sub-generator
        } else {
            yield item;
        }
    }
}

with entry {
    # Usage
    nested = [[1, 2], [3, [4, 5]], 6];
    flat = list(flatten(nested));  # [1, 2, 3, 4, 5, 6]
}
```

**Generator expressions:**

```jac
def example() {
    # Generator expression (lazy)
    squares = (x ** 2 for x in range(1000000));

    # List comprehension (eager)
    squares_list = [x ** 2 for x in range(100)];
}
```

??? example "Try it: Control flow and generators"
    ```jac
    def fizzbuzz(n: int) -> str {
        if n % 15 == 0 { return "FizzBuzz"; }
        elif n % 3 == 0 { return "Fizz"; }
        elif n % 5 == 0 { return "Buzz"; }
        return str(n);
    }

    def countdown(n: int) -> Generator[int] {
        while n > 0 {
            yield n;
            n -= 1;
        }
    }

    with entry {
        results = [fizzbuzz(i) for i in range(1, 16)];
        print(results);
        print([x for x in countdown(5)]);
    }
    ```

---

## Native Compilation

Jac supports compiling to native machine code via LLVM for performance-critical workloads. Native code runs as pure machine code with zero Python interpreter overhead.

### .na.jac Files

Files ending in `.na.jac` are compiled to native code via LLVM IR:

```bash
# Run a native Jac file
jac run compute.na.jac
```

Native code can also be part of a larger module via variant annexing. Given `main.jac`, a sibling `main.na.jac` is automatically discovered, compiled, and merged as the native codespace.

### Supported Features

The native backend supports:

- Primitive types: `int`, `float`, `bool`, `str`
- Fixed-width C types: `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `f32`, `f64`, `c_void`
- Collections: `list`, `dict`, `set` with literals, subscript, iteration, and comprehensions
- Control flow: `if`/`elif`/`else`, `for`, `while`, `match`
- Functions, closures, and cross-module imports
- Context managers (`with` statements)
- Python/native interop (native functions can call Python and vice versa)

### C Library Imports

Import C shared libraries directly in native Jac code:

<!-- jac-skip -->
```jac
# compute.na.jac
import from "libm" {
    def sin(x: f64) -> f64;
    def cos(x: f64) -> f64;
    def sqrt(x: f64) -> f64;
}

with entry {
    result = sqrt(sin(1.0) ** 2 + cos(1.0) ** 2);
    print(result);  # 1.0
}
```

C structs can be declared inside library import blocks and used as normal Jac objects with automatic value-type coercion at call boundaries:

<!-- jac-skip -->
```jac
import from "libgraphics" {
    obj Color {
        has r: u8, g: u8, b: u8, a: u8;
    }
    def set_pixel(x: i32, y: i32, color: Color) -> c_void;
}
```

### Python-Native Interop

Native and Python codespaces can call each other within the same module:

```jac
# main.jac (Python/server codespace)
sv {
    def process_data(data: list) -> list {
        # Python code with full PyPI access
        return sorted(data);
    }
}

# main.na.jac (native codespace)
import from ...main { process_data }

with entry {
    # Native code calling Python function
    result = process_data([3, 1, 2]);
}
```

### Standalone Binaries

Self-contained `.na.jac` files (those with a `with entry {}` block and no Python dependencies) can be compiled to standalone native executables:

```bash
# Compile to a standalone binary
jac nacompile program.na.jac

# Run it directly -- no jac or Python needed
./program
```

The `nacompile` command requires no external compiler, assembler, or linker. The entire pipeline runs in pure Python:

1. The Jac compiler generates LLVM IR from the `.na.jac` source
2. llvmlite emits native object code for the host architecture
3. A built-in pure-Python ELF linker produces a dynamically-linked executable

The resulting binary links only against `libc` at runtime. See [`jac nacompile`](../../reference/cli/index.md#jac-nacompile) for full usage details.

---

## Learn More

**Tutorials:**

- [Jac Basics](../../tutorials/language/basics.md) - Step-by-step introduction to Jac syntax
- [Installation](../../quick-guide/install.md) - Setup and your first Jac program

**Related Reference:**

- [Part II: Functions & Objects](functions-objects.md) - Classes, methods, inheritance
