Created
May 9, 2014 05:52
-
-
Save ericpony/ce10e601cf289a75b441 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait RationalNumberTrait { | |
val numerator: Int | |
val denominator: Int | |
protected def gcd(a: Int, b: Int): Int = | |
if (a == 0) b | |
else if (a == 1) 1 | |
else gcd(b % a, a) | |
println("Superclass constructor: " + this.numerator + "/" + this.denominator) | |
} | |
trait LazyRationalNumber extends RationalNumberTrait { | |
lazy val n = numerator / g | |
lazy val d = denominator / g | |
lazy val g = { | |
require(denominator != 0); | |
println("Fraction is reduced."); | |
gcd(numerator, denominator); | |
} | |
override def toString = | |
if (n == 0) "0" else if (d == 1) n.toString else n + "/" + d | |
println("Subclass constructor") | |
} | |
trait HastyRationalNumber extends RationalNumberTrait { | |
val n = numerator / g // !! Will cause divided-by-zero exception !! | |
val d = denominator / g | |
// Use "lazy val g" to avoid above error | |
val g = { | |
require(denominator != 0); | |
println("Fraction is reduced."); | |
gcd(numerator, denominator); | |
} | |
override def toString = | |
if (n == 0) "0" else if (d == 1) n.toString else n + "/" + d | |
println("Subclass constructor") | |
} | |
class RationalNumber(numerator0: => Int, denominator0: => Int) extends RationalNumberTrait { | |
val numerator = numerator0 // You have to pass parameters to abstract fields in RationalNumberTrait | |
val denominator = denominator0 // Otherwise this class would become a abstract class | |
val g = { | |
require(denominator != 0); | |
println("Fraction is reduced."); | |
gcd(numerator, denominator); | |
} | |
val n = numerator / g | |
val d = denominator / g | |
override def toString = | |
if (n == 0) "0" else if (d == 1) n.toString else n + "/" + d | |
println("Subclass constructor") | |
} | |
class RationalNumberV2(numerator0: => Int, denominator0: => Int) extends { | |
val numerator = numerator0 | |
val denominator = denominator0 | |
val msg = { println("Pre-Initialization: " + numerator + "/" + denominator) } | |
} with RationalNumberTrait { | |
val g = { | |
require(denominator != 0); | |
println("Fraction is reduced."); | |
gcd(numerator, denominator); | |
} | |
val n = numerator / g | |
val d = denominator / g | |
override def toString = | |
if (n == 0) "0" else if (d == 1) n.toString else n + "/" + d | |
println("Subclass constructor") | |
} | |
object Main { | |
def main(args: Array[String]) { | |
println("======= Creating object from trait -- Lazy vals") | |
/** | |
* Initialization order: Superclass -> Class -> Initialization | |
*/ | |
val a = new LazyRationalNumber { | |
val numerator = 2 | |
val denominator = 10 | |
println("Initialization: " + this.numerator + "/" + this.denominator) | |
} | |
println("Evaluation: " + a) | |
println("\n======= Creating object from trait -- Pre-initialization") | |
/** | |
* Initialization order: Pre-Initialization -> Superclass -> Class | |
*/ | |
val c = new { | |
val numerator = 10 | |
val denominator = 2 | |
val msg = { println("Pre-Initialization: " + numerator + "/" + denominator) } | |
} with LazyRationalNumber | |
println("Evaluation: " + c) | |
println("\n======= Creating object from trait -- Naive initialization") | |
try { | |
/** | |
* Initialization order: Superclass -> Class -> Initialization | |
*/ | |
val c = new HastyRationalNumber { | |
val numerator = 10 | |
val denominator = 2 | |
println("Initialization: " + this.numerator + "/" + this.denominator) | |
} | |
} catch { | |
case ex: Exception => println("Error: " + ex) | |
} | |
println("\n======= Creating object from class -- normal") | |
/** | |
* Initialization order: Superclass -> Parameter -> Class | |
*/ | |
val b = new RationalNumber({ println("Numerator=21"); 21 }, { println("Denominator=49"); 49 }) | |
println("Evaluation: " + b) | |
println("\n======= Creating object from class -- with pre-initialization") | |
/** | |
* Initialization order: Parameter -> Pre-Initialization -> Superclass -> Class | |
*/ | |
val d = new RationalNumberV2({ println("Numerator=21"); 21 }, { println("Denominator=49"); 49 }) | |
println("Evaluation: " + d) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Results:
======= Creating object from trait -- Lazy vals
Superclass constructor: 0/0
Subclass constructor
Initialization: 2/10
Fraction is reduced.
Evaluation: 1/5
======= Creating object from trait -- Pre-initialization
Pre-Initialization: 10/2
Superclass constructor: 10/2
Subclass constructor
Fraction is reduced.
Evaluation: 5
======= Creating object from trait -- Without lazy vals
Superclass constructor: 0/0
Error: java.lang.ArithmeticException: / by zero
======= Creating object from class -- normal
Superclass constructor: 0/0
Numerator=21
Denominator=49
Fraction is reduced.
Subclass constructor
Evaluation: 3/7
======= Creating object from class -- Pre-initialization
Numerator=21
Denominator=49
Pre-Initialization: 21/49
Superclass constructor: 21/49
Fraction is reduced.
Subclass constructor
Evaluation: 3/7