E02090: a listed trait is already a trait of another listed trait or of the super class - it is inherited through that one

Category: E02xxx Symbol definition · Reported in phase: TYPE_HIERARCHY_CHECKS · Classification: REDUNDANT_TRAIT_REFERENCE · All error codes

What went wrong

A trait in the 'with trait of' list is already a trait of ANOTHER trait in the same list, or of the SUPER CLASS. With 'LoudSpeaker with trait of Speaker', writing 'with trait of LoudSpeaker, Speaker' lists Speaker twice over: everything Speaker brings is already inherited through LoudSpeaker, so the second name adds nothing. The same holds for 'Announcer extends Base with trait of Speaker' when 'Base with trait of Speaker': Announcer is already a Speaker through Base. The message names the trait and where it already comes from: 'Speaker' is already a trait of 'LoudSpeaker' (or 'Base'). Every redundant trait on the declaration is named in that one error ('Speaker' is already a trait of 'LoudSpeaker'; 'Listener' is already a trait of 'LoudListener'; list each once).

The order does not matter ('Speaker, LoudSpeaker' is the same), and neither does the depth: a trait of a trait of a listed trait counts too, and so does a trait of the super class's super class.

How to fix it

  • Delete the redundant name and keep the trait that has it: 'with trait of LoudSpeaker'
  • When the super class has it and it is the only trait listed, delete the whole 'with trait of Speaker': 'Announcer extends Base'
  • The compiler's repair does exactly this for you ('ek9 -fc', 'ek9_compile', 'ek9_edit_file', 'ek9_write_file'), since it is the only reading. By hand: delete the name from the list.
  • Listed 'by' a delegate ('Announcer extends Base with trait of Speaker by speaker'), the message says it cannot be delegated again here: the super class (or the listed trait that has it) already provides Speaker, so this type cannot hand it to another object. Nothing is repaired - deleting the name would silently drop the delegation. Decide which you want: keep what the super class provides and delete 'Speaker by speaker', or delegate a different trait.

The [EXAMPLE] section below shows a class listing both, and the class listing only the trait that has the other; the second example shows a class whose super class already has the trait.

Common causes

  • Listing every trait a type should satisfy, without noticing that one of them already has another, or that the super class already has it
  • A trait gained a trait of its own, or a super class gained a trait, after the types using it were written

Note

A diamond - two DIFFERENT listed traits, or the super class and a listed trait, that share a trait you do NOT list ('with trait of LoudSpeaker, QuietSpeaker' where both are Speakers) - is fine: each of the shared trait's methods reaches the type along both routes but is one method. Two different traits that each implement the same method is a real conflict, and that stays E06150: override the method in the type and choose.

See also

  • E02050: the same trait listed twice
  • E06150: conflicting methods from different traits
  • E05020: circular trait hierarchy

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E02090: a listed trait is already a trait of another listed trait or of the super class - it is inherited through that one

#!ek9
defines module error.e02090.bad

  defines trait

    Speaker
      speak()
        <- rtn as String: "hello"

    LoudSpeaker with trait of Speaker
      shout()
        <- rtn as String: "HELLO"

  defines class

    //LoudSpeaker already has Speaker, so listing Speaker again adds nothing
    Megaphone with trait of LoudSpeaker, Speaker
      default operator ?

    Stage with trait of Speaker as open
      default operator ?

    //The super class Stage already has Speaker, so listing it again adds nothing
    Podium extends Stage with trait of Speaker
      default operator ?

Fixed: List only the trait that has the other - it brings both; a trait the super class has is not listed again

#!ek9
defines module error.e02090.good

  defines trait

    Speaker
      speak()
        <- rtn as String: "hello"

    LoudSpeaker with trait of Speaker
      shout()
        <- rtn as String: "HELLO"

  defines class

    //A Megaphone is a LoudSpeaker and so a Speaker too
    Megaphone with trait of LoudSpeaker
      default operator ?

    Stage with trait of Speaker as open
      default operator ?

    //A Podium is a Stage and so a Speaker too
    Podium extends Stage
      default operator ?

  defines program

    Announce()
      stdout <- Stdout()
      megaphone <- Megaphone()
      podium <- Podium()
      stdout.println(`${megaphone.speak()} ${megaphone.shout()} ${podium.speak()}`)