Why can't a local construct share a name with a referenced (imported) type in EK9?

← Syntax and Structure Rules · Ref: Q1306

EK9 refuses to pick a winner when a locally-defined construct (class, record, trait, function) shares its name with a type brought in via a 'references' block. Both the import and the local definition want the same short name, so any later use of that name is ambiguous - the compiler rejects it immediately with E03010 rather than silently choosing one.

Fix: rename the local construct to a distinct name (e.g. ItemList instead of List). The referenced type keeps its short name, the local type gets its own, and every use resolves to exactly one symbol.

Note that a local construct named after a BUILT-IN type (a class called List, say) is refused earlier, with E01090 (the name of a built-in construct cannot be given a second meaning), before references are even checked. E03010 is for the names of types that come from another module; a single file can show it only by referencing a type of its own module (references qa.syntaxrules.referencecollision::ItemList while also defining ItemList). Alternatively, drop the reference and use the fully qualified 'module::Type' form inline when the imported type is needed.

See Q726 for references block syntax. See Q832 for the design rationale.

Example

defines module qa.syntaxrules.referencecollision

  //'List' is imported via references and keeps that short name.
  references
    org.ek9.lang::List

  //THE FIX: the local construct is named distinctly (ItemList), so it does
  //NOT collide with the referenced 'List'. Also referencing a type called
  //ItemList (from another module) would trigger E03010 CONSTRUCT_REFERENCE_CONFLICT;
  //naming this class 'List' is E01090 instead, because List is built in.
  defines class

    ItemList
      items as List of String?

      ItemList()
        items: List() of String

      ItemList()
        -> initial as String
        items: List() of String
        items += initial

      add()
        -> item as String
        items += item

      size()
        <- rtn as Integer: length items

      default operator ?

  defines program

    ReferenceCollisionDemo()
      stdout <- Stdout()

      //'List' resolves unambiguously to the referenced org.ek9.lang::List.
      basket <- ItemList("apple")
      basket.add("pear")

      stdout.println(`Basket holds ${basket.size()} items`)

Common mistakes

E03010 — Referencing 'ItemList' via references and then defining a local class also named 'ItemList' makes the short name ambiguous - neither the reference nor the local definition takes priority, so EK9 raises E03010 (here the referenced type stands in for one from another module). Rename the local construct so each name resolves to exactly one symbol, or drop the reference and use the fully qualified name inline. See ek9 -h E03010 for details.

Incorrect:

  references
    org.ek9.lang::List
    qa.syntaxrules.referencecollision::ItemList

Correct:

  references
    org.ek9.lang::List
Other ways to ask this
  • What triggers E03010 CONSTRUCT_REFERENCE_CONFLICT?
  • Why does referencing a type and then defining a local class with the same name fail to compile?
  • How do I resolve a name collision between a references import and a local type?

Coming from another language?

Java: wildcard imports (import java.util.*) silently shadow local types; the conflict surfaces only when two imports expose the same name. Python: 'from module import *' overwrites local names with no warning. C#: 'using' directives let a local type silently win over an imported one. EK9: neither the reference nor the local takes priority - the collision is a compile-time error (E03010) and the developer must choose a distinct name.

Keywords: E03010, name, collision, rename, references, import, conflict, local, syntax