Strange Return Type Issue

I defined a variable private var _ref: Ref[this.type, Entity] = null that is supposed to have the type Ref[Entity, Entity], but it its type is compiling to Ref[(e: Entity), Entity].

Here is the register method in contex:

class InstanceManager[T]() {

  val onRegister = Event[(T, Int)]
  val onDestroy = Event[(T, Int)]

  private var _refs: Map[Int, T] = Map.empty
  private var _nextRefNr: Int = 0
  private def _newRefNr(): Int = this.synchronized {
    val id = _nextRefNr
    _nextRefNr += 1
    id
  }

  ...

  def register(t: T): Ref[T, T] = this.synchronized {
    require(t != null, "'t' may not be null")
    var nr = _newRefNr()
    _refs += nr -> t
    onRegister.emit((t, nr))
    Ref[T, T](nr, this)
  }
}

This is how the InstanceManager is being created in my project:

class World {
  private[core] val _entityManager = InstanceManager[Entity]()
}

Here is the problematic code:

class Entity private (using val world: World) {
  private var _ref: Ref[this.type, Entity] = null
  def ref: Ref[this.type, Entity] = _ref

  ...
}
object Entity {
  def makeReady(e: Entity): Ref[Entity, Entity] = {
    e._ref = e.world._entityManager.register(e)
    e.onReady.emit()
    return e.ref
  }

  def apply(name: String = "Unnamed Entity")(using world: World) =
    var entity = new Entity()
    entity.name = name
    makeReady(entity)
}

This is a copy-paste of the compile-time error I get when hovering over the _ref term in the first line of the makeReady method:

Expression type:

Ref[(e : engine.core.Entity), Entity]
Symbol signature:

var _ref: Ref[? <: Entity, Entity]

Here’s another of the error I get when hovering over the register term:

Found:    lib.instance_management.Ref[engine.core.Entity, engine.core.Entity]
Required: lib.instance_management.Ref[(e : engine.core.Entity), engine.core.Entity]bloop(7)
Expression type:

Ref[(e : engine.core.Entity), Entity]
Symbol signature:

def register[K <: Entity](t: K): Ref[K, Entity]

The project is a mess, but you can clone this commit to look at the code if you are interested.

If anyone could explain why the register method is returning Ref[(e : Entity), Entity] instead of Ref[Entity, Entity] I would greatly appreciate it!

Thank you for your time.

It’s the other way round. A self-contained, minimalist scenario might be this:

class Ref[K, T >: K]

def register[T](t: T): Ref[T, T] = ???

class Entity:
  var ref: Ref[this.type, Entity] = null

def mkEnt() =
  val e = new Entity
  e.ref = register(e)

You have e: Entity and def register(t: T): Ref[T, T], so register(e) will return a Ref[Entity, Entity]. But there’s var ref: Ref[this.type, Entity], requiring a Ref[e, Entity], where e is a subtype of Entity that is only inhabited by the single value e, indicated as this.type in the declaration.

2 Likes

Sorry, I’m still not sure what is going on. So register is returning an Entity, but the ref variable is looking for a specific instance e of Entity?

I think I understand the problem now, thank you. Entity is too general to go into the ref variable, which expects a specific Entity.