开发者

Objects being "turned" to null randomly

开发者 https://www.devze.com 2023-02-23 01:48 出处:网络
Hey guys, im working on a project in scala and i encountered very weird problem. This is a part of the code :

Hey guys, im working on a project in scala and i encountered very weird problem. This is a part of the code :

class Entity(val id:String){
  override def toString = id
}

class RequirementType
case class DependsEither(t:List[(Entity,Int)]) extends RequirementType
case class Depends(t:(Entity,Int)) extends RequirementType

class BuildableEntity(override val id:String,
               val mineralCost:Int,
               val gasCost:Int,
               val buildTime:Int,
               val buildCount:Int,
               val supplyCount:Int,
               val req:List[RequirementType],
               val onBuildStart: GameState => GameState,       
               val onBuildFinish: GameState => GameState
            )extends Entity(id)

class SimpleBuilding(id:String,
       mineralCost:Int,
       gasCost:Int,
       buildTime:Int,
       req:List[RequirementType]
) extends BuildableEntity(id,mineralCost,gasCost,buildTime,1,0,req:::List(ConsumesOnStart((Drone,1))),{s=>s},{x=>x})
object SpawningPool extends SimpleBuilding("spawningPool",200,0,65,List(DependsEither(List((Hatchery,1),(Lair,1),(Hive,1)))))
object Lair extends SimpleBuilding("lair"开发者_StackOverflow社区,150,100,80,List(ConsumesOnFinish(Hatchery,1),Depends(SpawningPool,1)))
object InfestationPit extends SimpleBuilding("infestationPit",100,100,50,List(DependsEither(List((Lair,1),(Hive,1)))))

Now, when i call println(Lair.req), it sometimes prints as

List(ConsumesOnFinish((hatchery,1)), Depends((null,2)), ConsumesOnStart((drone,1)))

and sometimes as

List(ConsumesOnFinish((hatchery,1)), Depends((spawningPool,2)), ConsumesOnStart((drone,1)))

Please, if anyone has any idea about what could be going wrong, i would love you for ever. I have no clue why is it act as it does. I have more extensions of SimpleBuilding but they seem to be working properly

EDIT: I should also mention that the outcome changes after compilation. I mean that when i run unit test it sometimes appear as null and sometimes as proper instance.


This is indeed a case of circular dependency and initialization. Here is a shorter version of your issue:

class X(val x: List[X])
object A extends X(List(B))
object B extends X(List(A))

object Main {
  def main(args:Array[String]) {
    println("A.x: " + A.x)
    println("B.x: " + B.x)
  }
}

This will print this:

$ scala -cp classes Main
A.x: List(B$@143c8b3)
B.x: List(null)

You can use by names parameter to allow object construction to finish before you use it:

class X(x0: => List[X]) {
  lazy val x = x0
}
object A extends X(List(B))
object B extends X(List(A))

The fix works on the small test case:

$ scala -cp classes Main
A.x: List(B$@1feca64)
B.x: List(A$@6d084b)

Based on this you may want to change req:List[RequirementType] to req0: => List[RequirementType] and add a lazy val req = req0.

If that works for you, we should retitle the question to mention object initialization and circular dependencies. Note this is very similar to this question/answer.


Lair use SpawningPool in its constructor and reciprocally. But at that time, the other doesn't exists.


You've got recursive definitions in constructors, and although I believe that is supported, it looks like something's going wrong. Can you try lazy vals instead and see if the problem goes away? That is,

object X extends C("this",that,1) { /* code */ }

becomes

lazy val X = new C("this",that,1) { /* code */ }
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号