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 (:~:) COMBINES
Merge combines two values according to base type semantics. For Integer, this adds:
target :~: DrivingAge(80) //for Integer: 70 + 80 = 150
For String, merge concatenates. For other types, merge follows that type's semantics.
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
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 (:~:) === //For Integer, merge adds the values mergeTarget <- DrivingAge(20) mergeSource <- DrivingAge(30) mergeTarget :~: mergeSource stdout.println(`After merge 20+30: mergeTarget=${mergeTarget}`) // === 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: constrained, copy, assignment, mutating, transfer, replace, operator, merge, delegate