E05090: can be used with :=:, :~:, +=, -=, /= and *=. But not direct assignment

Category: E05xxx Explicit type symbol definition · Reported in phase: SYMBOL_DEFINITION · Classification: USE_OF_THIS_OR_SUPER_INAPPROPRIATE · All error codes

What went wrong

You cannot directly assign to 'this' or 'super' using := operator. 'this' is the current object instance, not a variable that can be reassigned. Use mutating operators to modify object state instead.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 743 (What are the restrictions on this and super in EK9?)

[ALLOWED OPERATORS WITH THIS/SUPER]

  • :=: (copy) - copy state from another instance
  • :~: (merge) - fill what is unset here from another instance (never overwrites a set value)
  • :^: (replace) - replace content
  • += -= *= /= (compound assignment if defined)

How to fix it

  1. Use :=: to copy state from another object into this
  2. Use :~: to fill whatever is unset in this from another object (set values are kept)
  3. Assign to individual fields: this.field := value

Rationale

  • 'this' IS the current instance - you can't make it a different object
  • Reassigning would break object identity and references
  • Copy/merge operators transfer state without changing identity

Common causes

  • Thinking 'this' is like a regular variable
  • Coming from languages where this pattern is allowed
  • Wanting to "replace" the current object (use copy instead)

See also

  • E05070: inappropriate use of 'this'
  • E05080: inappropriate use of 'super'

Examples

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

Fails with E05090: can be used with :=:, :~:, +=, -=, /= and *=. But not direct assignment

#!ek9
defines module error.e05090.bad

  defines class

    C0 as open
      //Explicitly allow this to be null
      p0 as Integer?

      default C0()

      //define the copy operator
      operator :=:
        -> param as C0
        this.p0 :=: param.p0

    CC0 extends C0
      //Explicitly allow this to be null
      p11 as Integer?

      default CC0()

    C1
      p1 as String: String()

      C1()
        -> param as C1
        this: param

      C1()
        -> param as String
        this.p1: param

      //This is not allowed, developer probably would mean copy the values.

    C2
      p1 as String: String()

      //This is not allowed, this is always set and so makes no sense.
      C2()
        -> param as C2
        this :=? param

    C2a
      p1 as String: String()

      //This is not allowed - cannot use direct assignment := to this
      //Use :=: (copy), :~: (merge), or +=, -=, /=, *= instead
      C2a()
        -> param as C2a
        this := param

    C2b extends C2a
      p2 as String: String()

      //This is not allowed - cannot use direct assignment := to super
      C2b()
        -> param as C2a
        super := param

    //But these are allowed
    C3
      p1 as String: String()

      //Get a full copy of the values from param into this. - i.e. copy the mainValue of param over
      C3()
        -> param as C3
        this :=: param

      //define the copy operator
      operator :=:
        -> param as C3
        this.p1 :=: param.p1

    C4
      p1 as String: String()
      p2 as String: "Steve"
      //Get a merge of values from param into this. - i.e. copy the mainValue of param over
      C4()
        -> param as C4
        this :~: param

      //define the merge operator
      operator :~:
        -> param as C4
        //So if p1 or p2 is unset in this, but param p1/p2 is not then it gets merged in as appropriate
        this.p1 :~: param.p1
        this.p2 :~: param.p2

Fixed: Copy (:=:) or merge (:~:) into this; never assign to this or super

#!ek9
defines module error.e05090.good

  defines class

    Account
      owner as String: String()

      Account()
        -> other as Account
        this :=: other

      Account()
        -> owner as String
        this.owner: owner

      default operator ?

      operator :=:
        -> other as Account
        this.owner :=: other.owner

    Settings
      theme as String: String()
      language as String: "en"

      Settings()
        -> defaults as Settings
        this :~: defaults

      default operator ?

      operator :~:
        -> other as Settings
        this.theme :~: other.theme
        this.language :~: other.language

Questions and answers

These Q&A entries show E05090 and its fix: