Polymorphic updates in an immutable class hierarchy

后端 未结 3 799
再見小時候
再見小時候 2021-01-01 15:23

I\'d like to be able to assemble domain objects from traits, according to various properties that the concrete classes might have. When my objects are mutable, this is prett

相关标签:
3条回答
  • 2021-01-01 15:30

    Sorry for the necromancy, but it is worth pointing that this is doable using F-bounded polymorphism:

      trait HasHitPoints[Self <: HasHitPoints[Self]] { 
        val hitPoints: Int 
        def updateHitpoints(f: Self => Int): Self
      }
      trait HasBearing { val bearing: Double }
    
      case class Ship(hitPoints: Int, bearing: Double)
          extends HasHitPoints[Ship]
          with HasBearing {
        override def updateHitpoints(f: Ship => Int): Ship = copy(hitPoints = f(this))
      }
      case class Base(hitPoints: Int) extends HasHitPoints[Base] {
        override def updateHitpoints(f: Base => Int): Base = copy(hitPoints = f(this))
      }
    
      val things = Ship(50, 0) :: Base(100) :: Nil
    
      val heal = things.map(_.updateHitpoints(_.hitPoints + 10))
    
      val totalHitPoints = heal.map(_.hitPoints).sum
    
    0 讨论(0)
  • 2021-01-01 15:32

    You are hoping to avoid the N update methods in M concrete classes. However painful I think this is just not possible. You will need access to the copy method or at least the constructor of every concrete class. Neither of them can be abstracted as is also discussed in: Case class copy() method abstraction So in the end you will always end up with the N x M 'boilerplate' code.

    0 讨论(0)
  • 2021-01-01 15:51

    You may have some luck with adding an e.g. abstract def withHitPoints(points: Int) method to your traits, which returns a copy of the container object with a different property value. This reduces the usage to something like:

    val damagedActors = actors map { actor => actor.withHitPoints( actor.hitPoints - 10 ) }
    

    But will otherwise require an extra method per property per concrete class, so I'm not sure it really solves your problem. This does not feel right for a static language like Scala (nor would I likely bother with immutability for this particular use-case); an immutable solution here may be a better candidate for a dynamic language.

    0 讨论(0)
提交回复
热议问题