New Issue: Adding an overload to 'map.getValue()' to avoid halting

18786, "bmcdonald3", "Adding an overload to 'map.getValue()' to avoid halting", "2021-12-02T17:49:00Z"

Summary

The getValue() map method halts if the value is not found today and this can cause problems in a parallel context, where wrapping the getValue() check in a if myMap.contains(val) can still halt if the value has been removed in the time from the contains call and the using of getValue(). This can be avoided by adding an overload to getValue() to take a "sentinel" value that will be returned if the value is not found, rather than halting.

Proposed solutions

Proposal 1: Add an overload to getValue() to return a "sentinel" value

proc map.getValue(key) { ... }    // current getValue(), halts if 'key' is not found
proc map.getValue(key, sentinel) { ... }  // returns 'sentinel' if the key is not found

Usage:

var value = map.getValue(key, 0) + 1; // never halts; value either 1 or key+1

Proposal 2: Switch to throw instead of halt to allow catching the error

proc map.getValue(key) throws { ... } 

Usage:

var value: int;
try {
  value = map.getValue(key) + 1;
} catch {
  value = 1;
}

Proposal 3: New function that returns a sentinel and boolean false if key not found

(the name would definitely need some rethinking...)

proc map.getValue(key) { ... } 
proc map.didGetValue(key, sentinel) { ... }

Usage:

var (value, found) = map.didGetValue(key, 0); // if 'key' not found then 'value'=0 and 'found'=false

Previous discussion

See the original user issue: New argument in map.getValue() · Issue #17498 · chapel-lang/chapel · GitHub
Arguments against proposal 1:

  • getReference/getBorrowed don't have as clear of a solution, making some assymetry
  • the syntax isn't particularly elegant and could be better (e.g., var v = try m.getValue(0) else 1;, but something like this wouldn't work today and would be a bigger change)