Why don't Dict and List have a .get() method in EK9?

← Safe Value Access · Ref: Q165

EK9 deliberately omits .get() on Dict and List because it forces a fallback value, eliminating null returns entirely. This is a design philosophy choice, not an oversight.

THE PROBLEM WITH GET

In Java, map.get(key) returns null if the key is missing. This creates silent null propagation: the null travels through your code until it eventually causes a NullPointerException far from the original lookup. In Python, dict[key] throws KeyError. In Go, accessing a missing map key returns the zero value with no indication it was missing.

THE GETORDEFAULT SOLUTION

By requiring a default value, EK9 ensures every lookup returns a meaningful, usable result:

  ages.getOrDefault("Alice", 0)

You must think about the missing-key case at the point of access. The compiler cannot let you forget.

CONSISTENT ACROSS ALL TYPES

The same pattern works on Dict, List, Optional, and Result:

  dict.getOrDefault(key, default)
  list.getOrDefault(index, default)
  optional.getOrDefault(default)
  result.okOrDefault(default)

One mental model for safe access everywhere.

See Q46 for Dict basics. See Q45 for List basics. See Q47 for Optional. See Q48 for Result. See Q166 for the consistent safe-access pattern. See Q168 for fallback values. See Q169 for callbacks.

Example

defines module qa.safeaccess.designphilosophy

  defines program
    WhyNoGetDemo()
      stdout <- Stdout()

      // === THE GETORDEFAULT APPROACH ===

      // Dict: always provide a fallback
      ages <- {"Alice": 30, "Bob": 25}
      aliceAge <- ages.getOrDefault("Alice", 0)
      stdout.println(`Alice: ${aliceAge}`)

      unknownAge <- ages.getOrDefault("Unknown", 0)
      stdout.println(`Unknown (default 0): ${unknownAge}`)

      // List: always provide a fallback
      numbers <- [10, 20, 30]
      first <- numbers.getOrDefault(0, -1)
      stdout.println(`First: ${first}`)

      outOfBounds <- numbers.getOrDefault(99, -1)
      stdout.println(`Out of bounds (default -1): ${outOfBounds}`)

      // Optional: always provide a fallback
      opt <- Optional("Hello")
      optVal <- opt.getOrDefault("default")
      stdout.println(`Optional: ${optVal}`)

      emptyOpt <- Optional() of String
      emptyVal <- emptyOpt.getOrDefault("default")
      stdout.println(`Empty optional: ${emptyVal}`)

      // Result: always provide a fallback
      okResult <- Result("Success", Integer())
      okVal <- okResult.okOrDefault("fallback")
      stdout.println(`Result ok: ${okVal}`)

      errResult <- Result(String(), 42)
      errOk <- errResult.okOrDefault("fallback")
      stdout.println(`Error result okOrDefault: ${errOk}`)

Common mistakes

E50060 — Dict does not have a .get() method — only getOrDefault(). Calling .get() triggers E50060 — method not resolved. This is by design: getOrDefault forces you to handle the missing-key case at the point of access. See ek9 -h E50060 for details.

Incorrect:

aliceAge <- ages.get("Alice")

Correct:

aliceAge <- ages.getOrDefault("Alice", 0)

E08030 — Optional does have .get() but it requires a ? guard check first. Calling .get() without checking triggers E08030 — has not been checked before access. Use getOrDefault() for guard-free access. See ek9 -h E08030 for details.

Incorrect:

optVal <- opt.get()

Correct:

optVal <- opt.getOrDefault("default")
Other ways to ask this
  • Why does EK9 force me to use getOrDefault instead of get?
  • Why is there no .get() on Dict or List in EK9?
  • What is the design philosophy behind getOrDefault in EK9?

Coming from another language?

Java: map.get() returns null (NPE risk), map.getOrDefault() added in Java 8 but optional. Python: dict[key] throws KeyError, dict.get(key, default) is the safe form. Rust: HashMap.get() returns Option, forces handling. Go: map[key] returns zero value silently, comma-ok idiom for detection. JavaScript: obj[key] returns undefined, no built-in safe access. EK9: no .get() exists, getOrDefault() is the only access method, forces explicit handling of missing keys.

Keywords: function, access, safe, list, getOrDefault, null, missing, philosophy, null-safe, dict, guard, design, crash, why, exception, get, migrate