Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ericpony/ce10e601cf289a75b441 to your computer and use it in GitHub Desktop.
Save ericpony/ce10e601cf289a75b441 to your computer and use it in GitHub Desktop.
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)
}
}
@ericpony
Copy link
Author

ericpony commented May 9, 2014

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment