EDIT 2:
I managed to achieve the type security that I wanted in my exercise with RomanNumerals, using a combination of mixins and type parameters with the code below. In essence, this is what he does after importing everything into RomanNumeralsI can write L X V I, but not L Lor X L X, so I get a compiler error like mismatch (since these would be illegal combinations of Roman numerals). Now I'm wondering if this way of using signs, mixins, and type parameters is considered normal, or if I abuse the language so that I can speak :) Is there a better way to achieve the same type of security with a simpler / cleaner code?
object RomanNumerals {
trait Numeral {
def num:Int
}
trait NumeralI[N<:Numeral] extends Numeral
trait NumeralV[N<:Numeral] extends NumeralI[N] {
def I = new RomanNumeral[Numeral](1 + this.num) with Numeral
def II = new RomanNumeral[Numeral](2 + this.num) with Numeral
def III = new RomanNumeral[Numeral](3 + this.num) with Numeral
}
trait NumeralX[N<:Numeral] extends NumeralV[N] {
def IV = new RomanNumeral[Numeral](4
+ this.num) with Numeral
def V = new RomanNumeral[NumeralI[Numeral]](5
+ this.num) with NumeralV[NumeralI[Numeral]]
def IX = new RomanNumeral[Numeral](9
+ this.num) with Numeral
}
trait NumeralL[N<:Numeral] extends NumeralX[N] {
def X = new RomanNumeral[NumeralV[Numeral]](10
+ this.num) with NumeralX[NumeralV[Numeral]]
def XX = new RomanNumeral[NumeralV[Numeral]](20
+ this.num) with NumeralX[NumeralV[Numeral]]
def XXX = new RomanNumeral[NumeralV[Numeral]](30
+ this.num) with NumeralX[NumeralV[Numeral]]
}
class RomanNumeral[T <: Numeral](val num:Int) {
override def toString = num toString
def apply[N >: T <: Numeral](rn:NumeralI[N]) =
new RomanNumeral[Numeral](rn.num + num) with Numeral
def apply[N >: T <: Numeral](rn:NumeralV[N]) =
new RomanNumeral[NumeralI[Numeral]](rn.num
+ num) with NumeralV[NumeralI[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralX[N]) =
new RomanNumeral[NumeralV[Numeral]](rn.num
+ num) with NumeralX[NumeralV[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralL[N]) =
new RomanNumeral[NumeralX[Numeral]](rn.num
+ num) with NumeralL[NumeralX[Numeral]]
}
val I = new RomanNumeral[NumeralI[Numeral]](1) with NumeralI[Numeral]
val II = new RomanNumeral[NumeralI[Numeral]](2) with NumeralI[Numeral]
val III = new RomanNumeral[NumeralI[Numeral]](3) with NumeralI[Numeral]
val IV = new RomanNumeral[NumeralI[Numeral]](4) with NumeralI[Numeral]
val V = new RomanNumeral[NumeralI[Numeral]](5) with NumeralV[NumeralV[Numeral]]
val IX = new RomanNumeral[NumeralI[Numeral]](9) with NumeralI[Numeral]
val X = new RomanNumeral[NumeralV[Numeral]](10) with NumeralX[NumeralX[Numeral]]
val XX = new RomanNumeral[NumeralV[Numeral]](20) with NumeralX[NumeralX[Numeral]]
val XXX = new RomanNumeral[NumeralV[Numeral]](30) with NumeralX[NumeralX[Numeral]]
val XL = new RomanNumeral[NumeralV[Numeral]](40) with NumeralX[NumeralX[Numeral]]
val L = new RomanNumeral[NumeralX[Numeral]](50) with NumeralL[NumeralL[Numeral]]
}
EDIT:
, . , , , B ? .
trait Bar
class Foo[T<:Bar](n:Int) {
def apply[B >: T <: Bar](f:Foo[B]) = {
new Foo[B](n + f.n) with B
}
}
, , B ? , , f , Foo[B] with B? mixin B ?
, , Scala:
class Foo(val num:Int) {
def withM[B](foo:Foo) = new Foo(foo.num) with B
}
:
error: class type required but B found
def withM[B](foo:Foo) = new Foo(foo.num) with B
^
:
class Foo(val num:Int) {
def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B]
}
:
error: not found: type classOf
def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B]
^
? withM Foo with B, B - , withM