# Operator precedence table

> The table runs from lowest to highest binding. Operators with higher binding group first. For example, a && b || c parses as (a && b) || c because && binds more tightly than || .

Website: https://harnlang.com/spec/language/03-operator-precedence-table.html

This page documents Harn, which is pre-1.0. Language, standard library, and CLI APIs may change. If the intended version is unclear, clarify before using this page.

---

<!-- Generated from spec/chapters/*.md by scripts/sync_language_spec.harn -->

## Operator precedence table

The table runs from lowest to highest binding. Operators with higher binding
group first. For example, `a && b || c` parses as `(a && b) || c` because `&&`
binds more tightly than `||`.

| Precedence | Operators | Associativity | Description |
|---|---|---|---|
| 1 | `\|>` | Left | Pipe |
| 2 | `? :` | Right | Ternary conditional |
| 3 | `\|\|` | Left | Logical OR |
| 4 | `&&` | Left | Logical AND |
| 5 | `==` `!=` | Left | Equality |
| 6 | `<` `>` `<=` `>=` `in` `not in` | Left | Comparison / membership |
| 7 | `+` `-` | Left | Additive |
| 8 | `??` | Left | Nil coalescing |
| 9 | `*` `/` `%` | Left | Multiplicative |
| 10 | `!` `-` (unary) | Right (prefix) | Unary |
| 11 | `**` | Right | Exponentiation |
| 12 | `.` `?.` `[]` `?.[]` `[:]` `()` `?` `!` | Left | Postfix |

`!` appears at two precedence levels with two distinct meanings: a **prefix**
`!` (level 10) is logical negation (`!ok`), while a **postfix** `!` (level 12)
is the non-null assertion (`value!`). They never collide — a `!` before an
operand is negation, a `!` after one is the assertion — and `!=` is a single
token, so neither reading is ambiguous.

Exponentiation binds more tightly than a unary prefix on its **left** operand,
so `-2 ** 2` parses as `-(2 ** 2)` (`-4`), matching Python, Ruby, and ordinary
math notation rather than the spreadsheet `(-2) ** 2` reading. The **right**
(exponent) operand still accepts a unary prefix, so `2 ** -3` is `2 ** (-3)`,
and chained `**` remains right-associative (`2 ** 3 ** 2` is `2 ** (3 ** 2)`).

### Multiline expressions

Binary operators `|>`, `||`, `&&`, `==`, `!=`, `<`, `>`, `<=`, `>=`, `??`,
`+`, `*`, `/`, `%`, `**`, and the `.` / `?.` member access operators can span
multiple lines. The operator at the start of a continuation line causes the
parser to treat it as a continuation of the previous expression rather than a
new statement.

Note: `-` does not support multiline continuation because it is also a unary
negation prefix. Keyword operators `in`, `not in`, and `to` also require an
explicit backslash continuation.

```harn,ignore
const result = items
  .filter({ x -> x > 0 })
  .map({ x -> x * 2 })

const msg = "hello"
  + " "
  + "world"

const ok = check_a()
  && check_b()
  || fallback()
```

### Pipe placeholder (`_`)

When the right side of `|>` contains `_` identifiers, the expression is
automatically wrapped in a closure where `_` is replaced with the piped
value:

```harn
// desugars to: |> { __pipe -> split(__pipe, " ") }
"hello world" |> split(_, " ")
// desugars to: |> { __pipe -> __pipe.sorted() }
[3, 1, 2] |> _.sorted()
// desugars to: |> { __pipe -> len(__pipe) }
items |> len(_)
```

Without `_`, the pipe passes the value as the sole argument to the callable on
the right side. Use `_` whenever the piped value should be placed inside a
larger expression or a specific argument position.

---

## Read next

- [Grammar](https://harnlang.com/spec/language/02-grammar.md)
- [Scope rules](https://harnlang.com/spec/language/04-scope-rules.md)
