How do I merge so that the newer value wins, when ':~:' always keeps the value already set?

← Operators and Expressions · Ref: Q1410

Write your own function. ':~:' means one thing on every built-in type - it never overwrites a set value and fills whatever is unset or missing - and that is not configurable. When you need a different policy, say so in a function whose name states it.

NEWER WINS FOR A WHOLE VALUE

For a single value use ':=:' (copy) or ':^:' (replace) - they overwrite.

NEWER WINS, KEY BY KEY

Walk the source and assign each entry. For a Dict, 'dict += DictEntry(key, value)' replaces the value under an existing key:

  newerWins()
    ->
      target as Dict of (String, Integer)
      source as Dict of (String, Integer)
    for entry in source
      target += entry

COMBINE VALUES

To add numbers rather than keep the first, stream them: 'cat values > total' sums, because streaming into a value is a fold, not a merge.

See Q1405 for the merge rule on single values. See Q1406 for gathering partial results with ':~:'. See Q1058 for copy, replace and merge.

Example

defines module qa.operators.mergecustombehaviour

  defines function

    newerWins()
      ->
        target as Dict of (String, Integer)
        source as Dict of (String, Integer)
      for entry in source
        target += entry

  defines program

    MergeCustomBehaviourDemo()
      stdout <- Stdout()

      current <- {"cpu": 1, "disk": 7}
      update <- {"cpu": 4, "ram": 8}

      //The built-in merge keeps what is already set
      merged <- {"cpu": 1, "disk": 7}
      merged :~: update
      stdout.println(`merge keeps: ${merged}`)

      //A named function says the newer value wins
      newerWins(current, update)
      stdout.println(`newer wins: ${current}`)

      //Streaming into a value folds - here it sums
      total <- Integer()
      cat [4, 8, 3] > total
      stdout.println(`summed: ${total}`)
Other ways to ask this
  • Can I make ':~:' overwrite existing values?
  • How do I merge two Dicts where the second one wins?
  • How do I add numbers together when merging instead of keeping the first?
  • What do I use when the built-in merge rule is not what I need?

Coming from another language?

Java: Map.merge(key, value, remappingFunction) lets every call choose its own policy. Python: dict.update lets the newer win. EK9: ':~:' has one fixed meaning (first recorded wins, fill the gaps); any other policy is an ordinary, named function.

Keywords: custom merge, merge, newer wins, remapping function, :~:, overwrite, merge policy