Skip to content

Value and Identity Semantics ​

This page is the normative source for assignment, parameter passing, returns, equality, and copying in Norm. The object model, containers, and reference syntax follow these rules.

Data categories ​

Norm distinguishes value from identity:

CategoryTypesAssignment, parameters, and returns==
ValueInteger, Boolean, String, enums, user-defined values, built-in containersProduces a logically independent valueStructural equality
Identityclass instancesCopies an object reference and shares the objectObject identity

The = operator always copies the value of its right-hand expression. A class variable's value is an object reference, while a container's value is its container structure.

norm
Box first = Box(value: 1)
Box second = first
second.value = 2
printLine(first.value)

This prints 2.

Classes and explicit copying ​

Assignment, parameter passing, and returns preserve a class instance's identity. Every class provides copy(), which creates a new top-level object and assigns each field using the ordinary rules. Value fields become logically independent; class fields still refer to the same nested objects. Norm does not perform implicit recursive object cloning.

norm
Box second = first.copy()

Containers ​

Array, List, Map, Set, Stack, Queue, Deque, Pair, Range, and StringBuilder are values. Copying one creates an independent structure and assigns each element according to its category. Value elements thus become logically independent, while class elements keep their identity. Containers use one recursive equality-and-hash rule, including for Map keys and Set elements. Equatable and Hashable are explicit domain protocols and do not override this built-in key semantics.

An indexed result used directly to mutate a container retains its location in that container: rows[0].add(1) changes the nested list. By contrast, var row = rows[0] copies the list under assignment rules, so subsequent changes to row do not affect rows. Passing or returning an indexed result follows the same copying rules.

Executable example ​

This program compares structural values, independent container structures, shared class identity, and the field-wise behavior of copy():

norm
value Position {
  Integer row
  Integer column
}

class Marker {
  String label
  Integer visits = 0

  Void visit() {
    visits = visits + 1
  }
}

class Board {
  Marker marker
  List<Integer> route
}

Void appendStep(List<Integer> route) {
  route.add(9)
}

main() {
  Position start = Position(row: 2, column: 3)
  Position same = Position(row: 2, column: 3)
  printLine(start == same)

  List<Integer> original = [1, 2]
  List<Integer> changed = original
  changed.add(3)
  appendStep(changed)
  printLine(original.size())
  printLine(changed.size())

  Marker marker = Marker(label: "start")
  Board first = Board(marker: marker, route: original)
  Board alias = first
  alias.marker.visit()
  printLine(first == alias)
  printLine(first.marker.visits)

  Board copy = first.copy()
  copy.route.add(4)
  copy.marker.visit()
  printLine(first == copy)
  printLine(first.route.size())
  printLine(copy.route.size())
  printLine(first.marker.visits)
}

The checked output is maintained beside the source in norm/tests/docs/language/value_identity.out.

Evaluation and calls ​

Argument expressions are evaluated from left to right in source order. Labels only select parameter slots and never reorder evaluation. Multi-parameter calls use name: value; a bare identifier is shorthand only when it matches the parameter at the same position. A single argument may omit its label.

norm
merge(left: mergeSort(left), right: mergeSort(right))

Implementation freedom ​

Logical independence does not require immediate deep copying. An executor may use copy-on-write, structural sharing, escape analysis, or copy elimination, provided identity, equality, mutation results, and source evaluation order remain unchanged.

ref<T> ​

ref<T> represents the identity of a value storage location. It is not required for class sharing and does not accept class types. &location takes an address, *reference reads the stored value, and *reference = value writes it. Ref equality compares location identity. Refs are confined to local variables and callable parameters, cannot escape through returns, fields, containers, generic arguments, function types, or lambda capture, and use lexical scope or a single call as their lifetime boundary. The normative rules are in the ref<T> grammar.

Norm 0.25