Inherited traits that preserve types

I am new to Scala and still a little confused with my complex type system.

I am trying to solve the following problem. I want to create classes that are members of mutable doubly linked lists (and more complex data structures such as heaps). My goal, of course, is to remove objects from data structures at a constant time.

I developed the following symptom:

trait DLLMember { var next: DLLMember = this var prev: DLLMember = this ... } 

with several additional methods for adding and removing an object from the list.

The problem is that when I am in my actual class, say:

 class IntInDL(val v: Int) extends DLLMember 

When parsing my list, IntInDL.next will return a DLLMember type instead of IntInDL, which I should use to extract the value: this is not nice ...

Is there a way to use the Scala type system to save my work?

+4
source share
1 answer

This is a little round, but the following should work:

 trait DLLMember[T >: Null <: DLLMember[T]] { self : T => var next: T = this var prev: T = this ... } class IntInDL(val v: Int) extends DLLMember[IntInDL] var i = new IntInDL(3) println(i.next.v) //prints 3 i.next = null //is valid i.next = new IntInDL(1) //is valid 

Essentially, here we say that with self : T => you indicate that a parameter of type T should be a superclass of the class to which this attribute applies. When you use a tag in IntInDL , it is now known that the next and prev variables must have some subtype of IntInDL , because you specified it as a type parameter. That way you can use your members directly, without use.

If you provided some other, arbitrary type that was not part of the hierarchy, for example, class IntInDL(val v: Int) extends DLLMember[String] , it simply could not compile.

+6
source

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


All Articles