Expression F of a restricted type as an element of an abstract type

I want to convert F bounded polymorphism to abstract type members.

trait FBoundedMovable[Self <: FBoundedMovable[Self]] { def moveTo(pos: Vect2): Self } 

to

 trait Movable { self => type Self <: (Movable { type Self = self.Self }) def moveTo(pos: Vect2): Self } 

So far so good.

Defines an instance:

 case class Ship(pos: Vect2) extends Movable { type Self = Ship def moveTo(pos: Vect2) = copy(pos = pos) } 

And try using it:

 // [error] found : a.Self // [error] required: A def move[A <: Movable](a: A, to: Vect2): A = a.moveTo(to) 

The limited version of F works fine.

def moveF[A <: FBoundedMovable[A]](a: A, to: Vect2): A = a.moveTo(to)

I know that you can add type constraints to a method definition site:

def move2[A <: Movable { type Self = A }](a: A, to: Vect2): A = a.moveTo(to)

But is it possible to indicate a connection in the declaration with a moving attribute? If not, why?

Change 1

I realized what the problem is.

Suppose we want to declare that something is a unit in our world.

trait WorldUnit extends Movable with Damageable

All units are movable and may be damaged.

Our material for calculating the battle only cares that the material is Movable with Damagable . He does not care if it is a unit or a building.

However, we can have this code:

 def doCombat(obj: Movable with Damagable) = obj.moveTo(...).takeDamage(...) def doStuffWithUnit(obj: WorldUnit): WorldUnit = doCombat(obj) // and the type is lost here. 

Am I Doomed To F Limited Types?

Edit 2:

The question does not answer The attempt to model the F-bounded polymorphism as a type member in Scala - I have tried this before, and this does not affect the return type in the least, it is still itself.

Edit 3:

I found http://blog.jessitron.com/2014/02/when-oo-and-fp-meet-mytype-problem.html but the problem is still not resolved.

Basically, whenever you have a collection and you want to select it:

(collection: Seq[Movable]).collectFirst { m: Movable if m.someCondition => m } - you have no way to specify a type constraint, so the compiler cannot prove that A # Self =: = A?

+6
source share
1 answer

Type projections in scala are path dependent. Quick example

 scala> trait A{ | type T | } defined trait A scala> val a = new A{type T = String} a: A{type T = String} = $anon$1@31198ceb scala> val b = new A{type T = String} b: A{type T = String} = $anon$1@236ab296 scala> def f(implicit evidence: A =:= bT) = null f: (implicit evidence: =:=[A,bT])Null scala> f("asdf":aT) <console>:12: error: type mismatch; found : aT (which expands to) String required: =:=[A,bT] (which expands to) =:=[A,String] f("asdf":aT) ^ 

In your case, it throws an error due to the return type. He rightly expects a.type , but you return A And they are not the same.

The reason they should not be the same is this: a.type returns type <: Movable . For imagination, some number x less than 100. The move method returns A , and for imagination, some other number y less than 100. It is not necessary that x be the same as y.

+3
source

Source: https://habr.com/ru/post/981884/


All Articles