Can I overload methods with different parameterised types in EK9?

← Generics · Ref: Q655

Because EK9 creates independent types for each parameterisation (no erasure), you can overload methods with different parameterised types. This is impossible in Java due to type erasure.

OVERLOADING WORKS

Because List of Integer and List of String are distinct types:

  process(items as List of Integer)
  process(items as List of String)

Both signatures coexist without ambiguity.

WHY JAVA CANNOT

Java erases generics at runtime: both List<Integer> and List<String> become List. Two methods with the same erased signature conflict.

AMBIGUITY DETECTION (E06140)

EK9 still detects GENUINE ambiguity. If two overloads match equally well, E06140 is raised. This happens with coercion costs, not with distinct parameterised types.

DISTINCT TYPE ARGUMENTS

Overloading with different type arguments is always unambiguous:

  handler(opt as Optional of String)
  handler(opt as Optional of Integer)

The compiler resolves the correct overload from the argument type.

See Q653 for type independence. See Q196 for multi-parameter generics. See Q194 for generic class basics.

Example

defines module qa.genericsdeep.methodoverloading

  defines function

    <?-
      Functions accepting different parameterised types.
      Each List parameterisation is an independent type,
      so these are unambiguous overloads (unlike Java with erasure).
    -?>
    sumIntegers()
      -> items as List of Integer
      <- rtn as Integer: 0
      for item in items
        rtn += item

    joinStrings()
      -> items as List of String
      <- rtn as String: ""
      for item in items
        rtn += item

    countIntegers() as pure
      -> items as List of Integer
      <- rtn as Integer: length items

    countStrings() as pure
      -> items as List of String
      <- rtn as Integer: length items

  defines program

    MethodOverloadingDemo()
      stdout <- Stdout()

      // === INTEGER LIST ===

      numbers <- List() of Integer
      numbers += 10
      numbers += 20
      numbers += 30
      intSum <- sumIntegers(numbers)
      stdout.println(`Integer sum: ${intSum}`)

      // === STRING LIST ===

      words <- List() of String
      words += "hello"
      words += " "
      words += "world"
      joined <- joinStrings(words)
      stdout.println(`Joined: ${joined}`)

      // === COUNT FUNCTIONS FOR DIFFERENT LIST TYPES ===

      intCount <- countIntegers(numbers)
      stdout.println(`Integer count: ${intCount}`)

      strCount <- countStrings(words)
      stdout.println(`String count: ${strCount}`)

Common mistakes

E01030 — E01030 is raised when two overloads match equally well, creating genuine ambiguity. Declaring two functions with identical signatures (same name, same parameter types) would be ambiguous. EK9 allows overloading with different parameterised types because they are independent. See ek9 -h E01030 for details.

Incorrect:

sumIntegers()
      -> items as List of Integer
      <- rtn as Integer: 0
    sumIntegers()
      -> items as List of Integer
      <- rtn as Integer: 0

Correct:

sumIntegers()
      -> items as List of Integer
      <- rtn as Integer: 0
Other ways to ask this
  • Does EK9 allow method overloading with generics unlike Java?
  • What is E06140 ambiguous method match?
  • How do independent generic types enable overloading?

Coming from another language?

Java: cannot overload methods with different generic parameterisations (erasure). C++: can overload with different template instantiations. Rust: no method overloading (uses traits instead). Go: no method overloading. Kotlin: same erasure limitation as Java. EK9: full overloading with distinct parameterised types because no erasure.

Keywords: distinct, migrate, method, ambiguity, erasure, overload, type-parameter, E06140, generic, parameterised