How do copy, replace, and merge operators work with constrained types?

← Advanced Type System · Ref: Q719

Constrained types inherit copy (:=:), replace (:^:), and merge (:~:) operators from their base type, with both operands being the constrained type.

COPY (:=:) DELEGATES TO BASE TYPE

Copy duplicates the value from one variable to another:

  target <- DrivingAge(50)
  source <- DrivingAge(60)
  target :=: source
  //target is now 60

Both operands must be the same constrained type.

REPLACE (:^:) OVERWRITES

Replace destructively overwrites the target value:

  target :^: DrivingAge(70)
  //target is now 70

The semantics depend on the base type's replace implementation.

MERGE (:~:) FILLS, NEVER OVERWRITES

Merge follows the one rule every type shares: ':~:' never overwrites a set value; it fills whatever is unset or missing. A constrained value is a single value, so it takes the source only when it is unset:

  target :~: DrivingAge(80)
  //target is set (70), so it stays 70
  empty <- DrivingAge()
  empty :~: DrivingAge(80)
  //empty was unset, so it is now 80

To overwrite a set value use :=: or :^:.

ARGUMENT TYPE IS CONSTRAINED TYPE

These operators take the constrained type as argument, not the raw base type:

  target :=: DrivingAge(50)    //correct
  //target :=: 50              //wrong — cannot use raw Integer

See Q257 for constrained type overview. See Q241 for mutation operator details. See Q716 for arithmetic operators.

Example

#!ek9
defines module qa.advancedtypes.constrainedcopyreplacemerge

  defines type

    DrivingAge as Integer constrain as
      >= 16 and <= 100

  defines program

    ConstrainedCopyReplaceMergeDemo()
      stdout <- Stdout()

      // === COPY (:=:) ===
      target <- DrivingAge(50)
      source <- DrivingAge(60)

      stdout.println(`Before copy: target=${target}, source=${source}`)
      target :=: source
      stdout.println(`After copy: target=${target}`)

      // === REPLACE (:^:) ===
      target :^: DrivingAge(70)
      stdout.println(`After replace with 70: target=${target}`)

      // === MERGE (:~:) ===
      //Merge never overwrites a set value - mergeTarget keeps 20
      mergeTarget <- DrivingAge(20)
      mergeSource <- DrivingAge(30)
      mergeTarget :~: mergeSource
      stdout.println(`After merge of 30 into 20: mergeTarget=${mergeTarget}`)

      //An unset target is filled by a set source
      emptyTarget <- DrivingAge()
      emptyTarget :~: mergeSource
      stdout.println(`After merge into unset: emptyTarget=${emptyTarget}`)

      // === COPY CONSTRUCTOR (separate from :=:) ===
      original <- DrivingAge(25)
      copied <- DrivingAge(original)
      stdout.println(`Original: ${original}, Copied: ${copied}`)

      // === ASSIGNMENT (:=) VS COPY (:=:) ===
      a <- DrivingAge(40)
      b <- DrivingAge(60)

      //Assignment replaces the variable reference
      a := b
      stdout.println(`After assignment a := b: a=${a}`)

      //Copy delegates to base type copy operator
      c <- DrivingAge(40)
      d <- DrivingAge(60)
      c :=: d
      stdout.println(`After copy c :=: d: c=${c}`)

Common mistakes

E50060 — DrivingAge has no intValue() method in EK9. DrivingAge is a constrained type, not a wrapper. See ek9 -h E50060 for details.

Incorrect:

target <- DrivingAge(50).intValue()

Correct:

target <- DrivingAge(50)

E50060 — DrivingAge has no intValue() method in EK9. Use the promote operator (#^) to extract the Integer value. See ek9 -h E50060 for details.

Incorrect:

copied <- DrivingAge(original).intValue()

Correct:

copied <- DrivingAge(original)
Other ways to ask this
  • Can I use :=:, :^:, and :~: with constrained types?
  • How do I copy values between constrained type variables?
  • What is the difference between copy, replace, and merge for constrained types?

Coming from another language?

Java: no constrained types, no copy/replace/merge operators. Manual clone() or copy constructors. Python: copy.copy() and copy.deepcopy() for object copying. Rust: Clone trait for copy, no replace/merge concept. Go: assignment copies values for value types. Kotlin: data class copy() method. EK9: constrained types inherit :=: (copy), :^: (replace), :~: (merge) from their base type — these operate between same-type constrained values, delegating to the base type's implementation.

Keywords: assignment, constrained, copy, delegate, merge, mutating, operator, replace, transfer