E08256: MutexLock construction is only allowed as a field initialiser on a class or component

Category: E08xxx Pre-IR checks (flow analysis) · Reported in phase: FULL_RESOLUTION · Classification: MUTEX_LOCK_CONSTRUCTION_OUTSIDE_FIELD_INITIALISER · All error codes

What went wrong

MutexLock construction (the call to the MutexLock constructor) was attempted from a location that is not a field initialiser of a class or component. MutexLock construction is only allowed as the initialiser of a field on a class or component — for example:

MyHolder
  lockedValue as MutexLock of String: MutexLock("initial")

Locals, function returns, and constructions inside method bodies are all rejected.

Rationale

EK9's compile-time concurrency safety relies on every lock having a stable, field-rooted home. The compiler tracks lock identity statically across the program for data-race detection (slice 1) and deadlock detection (slice 2). Locks declared as locals, returned from functions, or constructed inside method bodies have transient lifetimes that defeat this analysis.

Restricting construction to field initialisers also keeps the API surface clean: callers see a class with protected operations, never the lock object itself.

How to fix it

  1. Wrap the lock in a class with the lock as a field (the [EXAMPLE] section below: a 'NameHolder' builds its 'MutexLock of String' in the field initialiser and changes it only through a MutexKey in 'rename()')
  2. Expose the protected operations as methods on the wrapping class. The lock never leaves the class.
  3. If the lock needs an initial value computed from constructor args, the wrapping class's field initialiser can call a helper that computes the value — but the MutexLock(...) call itself must be the field initialiser.

Common causes

  • Treating MutexLock as a local variable holding "protected state" that gets shared via the local. Pass the wrapping class instead.
  • Building a helper function that returns a fresh MutexLock. Replace with a class whose field initialiser builds it.
  • Trying to construct the lock inside a method body to avoid the field-initialiser pattern. The field initialiser IS the only legal construction site.

Worked examples

  • ek9 -q 158 (How do I protect shared data from concurrent access in EK9?)

See also

  • E08254: MutexLock cannot appear in a generic type parameter
  • E08257: MutexLock argument must be a fresh value

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E08256: MutexLock construction is only allowed as a field initialiser on a class or component

#!ek9
defines module error.e08256.bad

  defines function

    //Local MutexLock inside a function body — rejected.
    badLocalLock()
      lock <- MutexLock("Steve")
      require lock?

    //Returning a freshly-constructed MutexLock — rejected, because the
    //construction site is inside the function body, not a field initialiser.
    badReturningLock()
      <- rtn as MutexLock of String: MutexLock("Stephen")

Fixed: Construct a MutexLock only as a field initialiser of a class or component

#!ek9
defines module error.e08256.good

  defines class

    NameHolder
      name as MutexLock of String: MutexLock("Steve")

      rename()
        -> newName as String
        key <- (newName) is MutexKey of String as function
          lockedItem :=: newName
        require name.enter(key)

      default operator ?

Questions and answers

These Q&A entries show E08256 and its fix: