What does the merge operator ':~:' do to a value that is already set?
← Operators and Expressions · Ref: Q1405
Nothing. ':~:' never overwrites a set value; it fills whatever is unset or missing, element by element, recursing into compatible nested structures; Lists append, Sets take the union. The first value recorded wins.
SINGLE VALUES
For a single value (Integer, Float, String, Boolean, Character, Date, Time, Money, Optional and the rest) that means: the target takes the source ONLY when the target is unset and the source is set.
count <- Integer() count :~: 5 count :~: 7 stdout.println($count)
The first merge fills the unset count with 5; the second is ignored because count is now set.
THE FOUR CASES
- set target, set source: the target is kept
- set target, unset source: the target is kept
- unset target, set source: the target takes the source
- unset target, unset source: the target stays unset
Money follows the same rule whatever the currency: a set 10.00#GBP merged with 5.00#USD stays 10.00#GBP.
TO OVERWRITE
Use ':=:' (copy) or ':^:' (replace) when you mean to replace a set value.
NOT THE SAME AS A STREAM
Streaming into a value with '>' is a fold, not a merge, so 'cat [1, 2, 3] > total' still sums to 6.
See Q1406 for merging Dicts gathered from several tasks. See Q1409 for Lists and Sets. See Q1410 for writing a merge of your own. See Q1058 for copy, replace and merge on records.
Example
defines module qa.operators.mergerulesinglevalues defines program MergeRuleSingleValuesDemo() stdout <- Stdout() //A set target is never overwritten kept <- 10 kept :~: 20 stdout.println(`integer set kept: ${kept}`) //An unset target takes a set source filled <- Integer() filled :~: 30 stdout.println(`integer unset filled: ${filled}`) text <- "original" text :~: "replacement" stdout.println(`string set kept: ${text}`) noText <- String() noText :~: "supplied" stdout.println(`string unset filled: ${noText}`) //Money keeps a set value whatever the source currency price <- 10.00#GBP price :~: 5.00#USD stdout.println(`money other currency kept: ${price}`) //The first value recorded wins first <- Integer() second <- 5 first :~: second first :~: 7 stdout.println(`first recorded wins: ${first}`) //Streaming into a value is a fold, not a merge total <- Integer() cat [1, 2, 3] > total stdout.println(`pipe still sums: ${total}`)
Common mistakes
E08080 — Merging a variable into itself can never change it, so the compiler reports a self assignment. Merge a different value in. See ek9 -h E08080 for details.
Incorrect:
first :~: first
Correct:
first :~: second
Other ways to ask this
- Does ':~:' overwrite an Integer or String that already has a value?
- Why did merging 5 into 10 leave 10?
- When does merge take the source value for a single value?
- Is merge the same as copy for a Date or Money?
Coming from another language?
Java: there is no merge operator; Map.putIfAbsent and Optional.or are the nearest single-purpose equivalents. Kotlin: '?:' gives a default for a null, but does not mutate. Python: dict.setdefault for one key. EK9: one operator, ':~:', with one rule on every built-in type - a set value is never overwritten, an unset one is filled.
Keywords: E08080, unset target, Money currency, fill, merge, single value, :~:, first recorded wins, overwrite