Skip to content

Operators ​

Expression binding order ​

Calls, member selection, indexing, and slicing bind to their target before prefix operators. Prefix !, +, -, ^, *, &, <-, go, and await bind before postfix assertions (as? T, as! T) and result propagation (?). Binary expressions then group by the table below. Parentheses override that order.

Binary precedence ​

From lowest to highest; every binary group is left-associative:

LevelOperatorsOperand summary
1||boolean
2&&boolean
3==, !=, ===, !==Compatible comparable values
4<, <=, >, >=Compatible ordered values
5+, -, `, ^`
6*, /, %, <<, >>, &, &^Numeric/integer as applicable

The grouping follows the implemented Go-compatible bitwise precedence. a + b << c means a + (b << c); a | b + c means (a | b) + c.

Boolean and comparison operators ​

! accepts one boolean. && and || accept boolean operands, evaluate left to right, and short-circuit the right operand when the result is already known.

The two equality spellings are semantic aliases: == and === both perform typed equality, while != and !== both perform typed inequality. None performs JavaScript-style coercion. Operands must have compatible identical types and be comparable; slices, maps, and functions are not generally comparable. A concrete nil-capable or nullable counterpart is required when comparing with nil or null.

Ordering accepts two values of the same ordered type. Numeric widths and signedness are not mixed implicitly; strings use Go's byte-wise lexicographic order.

Numeric identity ​

Typed binary operands normally require identical numeric types. A representable untyped constant can combine with a typed operand. Operations preserve defined-type identity where Go does. No implicit signed/unsigned or width conversion occurs.

ts
function combine(left: int, right: int32): int {
  return left | right;
}

Dynamic fixed-width arithmetic preserves Go overflow behavior. Statically known out-of-range constants are source diagnostics.

Unary + and - require numeric values. Binary +, -, *, and / require compatible numeric operands; % is integer-only. + also concatenates two compatible strings. Constant integer division or remainder by zero is rejected, while a data-dependent zero divisor retains Go's runtime panic behavior.

ts
function divide(value: int): int {
  value /= 0;
  return value;
}

Shifts and bitwise operators ​

&, |, ^, &^, <<, and >> require integers; unary ^ is integer complement. Shift operands need not share a type, and the result has the left operand's type.

Negative constant shifts and the compiler's constant-shift limit are rejected before generation. Dynamic negative shifts retain Go runtime panic behavior. Unary &value is address acquisition; binary left & right is bitwise AND.

ts
function move(value: int): int {
  return value << -1;
}

For a nonconstant shift such as 1 << n, an untyped left operand takes its integer type from the destination or a typed peer. This also permits 1.0 << n in an integer context: the literal is exactly representable as an integer. Array indices, slice bounds and allocation sizes supply an int context.

ts
import go fmt from "fmt";

function mask(n: uint): byte {
  return 1 << n;
}

function main(): void {
  const n: uint = 2;
  const values = make[int[]](1.0 << n, 2.0 << n);
  fmt.Println(mask(n), len(values), cap(values));
}

The left operand must fit that type before shifting: 300 << n cannot produce a byte, even if a particular shift count would discard the high bits. A floating-point destination is invalid. Without an integer context, const value = 1.0 << n defaults to a floating-point type and is rejected. An already stored runtime value keeps its type; a later use cannot retroactively change the type of its initializer.

ts
function mask(n: uint): byte {
  return 300 << n;
}

The numeric and bitwise recipe traces masks, complement, signed shift behavior, compound updates, and explicit width conversion in one runnable program.

Pointer operators ​

OperatorMeaning
&valueAddress of an addressable value
*pointerDereference a pointer

Non-addressable temporaries are rejected. Nil pointer dereference preserves Go panic behavior.

ts
struct Point {
  public x: int;
}

function makePoint(): Point {
  return Point { x: 1 };
}

function invalid(): *Point {
  return &makePoint();
}

Updates ​

Supported update statements:

text
+=  -=  *=  /=  %=  &=  |=  ^=  &^=  <<=  >>=  ++  --

Targets can be identifiers, writable fields/properties, assignable indexes, or pointer dereferences. Property updates require an accessible getter and setter and perform ordered read/modify/write calls, not atomic mutation. Generated compound assignment evaluates a selector/index/pointer target once. ++ and -- never produce a value.

Strings support only +=. Remainder and bitwise updates require integers. Map indexes are writable; string indexes, methods, constants, and non-addressable temporary fields/array indexes are not.

Assertions and conversions ​

as? Type performs a checked Go-interface or class downcast and returns value plus boolean. as! Type is forced and panics on failure. Both evaluate the source once.

Type-name calls such as int64(value) or UserID(text) are explicit conversions and follow representability, identity, and Go convertibility rules for the source/target pair.

Result propagation ​

Postfix ? accepts Result<T>, a compatible Go (T, error) result, or a single error inside a Result-returning function. It evaluates the operation once and returns early when the error is non-nil.

A non-void propagated value must directly initialize one binding; propagation cannot be buried in an arbitrary expression. A void or single-error operation may stand alone. Use Failures, Result, and exceptions for the full return and cleanup contract.

Kinmokusei is a pre-1.0 project. Documentation describes implemented behavior.