Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You may use abstract types in conjunction with type parameters to establish custom templates.</p> <p>Let's assume you need to establish a pattern with three connected traits:</p> <pre><code>trait AA[B,C] trait BB[C,A] trait CC[A,B] </code></pre> <p>in the way that arguments mentioned in type parameters are AA,BB,CC itself respectfully</p> <p>You may come with some kind of code:</p> <pre><code>trait AA[B&lt;:BB[C,AA[B,C]],C&lt;:CC[AA[B,C],B]] trait BB[C&lt;:CC[A,BB[C,A]],A&lt;:AA[BB[C,A],C]] trait CC[A&lt;:AA[B,CC[A,B]],B&lt;:BB[CC[A,B],A]] </code></pre> <p>which would not work in this simple way because of type parameter bonds. You need to made it covariant to inherit correctly</p> <pre><code>trait AA[+B&lt;:BB[C,AA[B,C]],+C&lt;:CC[AA[B,C],B]] trait BB[+C&lt;:CC[A,BB[C,A]],+A&lt;:AA[BB[C,A],C]] trait CC[+A&lt;:AA[B,CC[A,B]],+B&lt;:BB[CC[A,B],A]] </code></pre> <p>This one sample would compile but it sets strong requirements on variance rules and can not be used in some occasions</p> <pre><code>trait AA[+B&lt;:BB[C,AA[B,C]],+C&lt;:CC[AA[B,C],B]] { def forth(x:B):C def back(x:C):B } trait BB[+C&lt;:CC[A,BB[C,A]],+A&lt;:AA[BB[C,A],C]] { def forth(x:C):A def back(x:A):C } trait CC[+A&lt;:AA[B,CC[A,B]],+B&lt;:BB[CC[A,B],A]] { def forth(x:A):B def back(x:B):A } </code></pre> <p>The compiler will object with bunch of variance check errors</p> <p>In that case you may gather all type requirements in additional trait and parametrize other traits over it</p> <pre><code>//one trait to rule them all trait OO[O &lt;: OO[O]] { this : O =&gt; type A &lt;: AA[O] type B &lt;: BB[O] type C &lt;: CC[O] } trait AA[O &lt;: OO[O]] { this : O#A =&gt; type A = O#A type B = O#B type C = O#C def left(l:B):C def right(r:C):B = r.left(this) def join(l:B, r:C):A def double(l:B, r:C):A = this.join( l.join(r,this), r.join(this,l) ) } trait BB[O &lt;: OO[O]] { this : O#B =&gt; type A = O#A type B = O#B type C = O#C def left(l:C):A def right(r:A):C = r.left(this) def join(l:C, r:A):B def double(l:C, r:A):B = this.join( l.join(r,this), r.join(this,l) ) } trait CC[O &lt;: OO[O]] { this : O#C =&gt; type A = O#A type B = O#B type C = O#C def left(l:A):B def right(r:B):A = r.left(this) def join(l:A, r:B):C def double(l:A, r:B):C = this.join( l.join(r,this), r.join(this,l) ) } </code></pre> <p>Now we can write concrete representation for the described pattern, define left and join methods in all classes and get right and double for free</p> <pre><code>class ReprO extends OO[ReprO] { override type A = ReprA override type B = ReprB override type C = ReprC } case class ReprA(data : Int) extends AA[ReprO] { override def left(l:B):C = ReprC(data - l.data) override def join(l:B, r:C) = ReprA(l.data + r.data) } case class ReprB(data : Int) extends BB[ReprO] { override def left(l:C):A = ReprA(data - l.data) override def join(l:C, r:A):B = ReprB(l.data + r.data) } case class ReprC(data : Int) extends CC[ReprO] { override def left(l:A):B = ReprB(data - l.data) override def join(l:A, r:B):C = ReprC(l.data + r.data) } </code></pre> <p>So, both abstract types and type parameters are used for creating abstractions. They both have weak and strong point. Abstract types are more specific and capable to describe any type structure but is verbose and require to explicit specified. Type parameters can create bunch of types instantly but gives you additional worry about inheritance and type bounds.</p> <p>They give synergy to each other and can be used in conjunction for creating complex abstractions that can't be expressed with only one of them.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload