/* * Copyright (C) 2007-2019 Artima, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Automatically generated Scala interpreter transcript from: * * Programming in Scala (Fourth Edition) * by Martin Odersky, Lex Spoon, Bill Venners * * http://booksites.artima.com/programming_in_scala_4ed */ scala> trait RationalTrait { val numerArg: Int val denomArg: Int require(denomArg != 0) private val g = gcd(numerArg, denomArg) val numer = numerArg / g val denom = denomArg / g private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) override def toString = s"$numer/$denom" } defined trait RationalTrait scala> val x = 2 x: Int = 2 scala> new RationalTrait { val numerArg = 1 * x val denomArg = 2 * x } java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:327) at RationalTrait.$init$(:4) ... 27 elided scala> new { val numerArg = 1 * x val denomArg = 2 * x } with RationalTrait ^ warning: early initializers are deprecated; they will be replaced by trait parameters in 2.14, see the migration guide on avoiding var/val in traits. res1: RationalTrait = 1/2 scala> new { val numerArg = 1 val denomArg = this.numerArg * 2 } with RationalTrait ^ warning: early initializers are deprecated; they will be replaced by trait parameters in 2.14, see the migration guide on avoiding var/val in traits. val denomArg = this.numerArg * 2 ^ On line 3: error: value numerArg is not a member of object $iw scala> object Demo { val x = { println("initializing x"); "done" } } defined object Demo scala> Demo initializing x res3: Demo.type = Demo$@36cf6377 scala> Demo.x res4: String = done scala> object Demo { lazy val x = { println("initializing x"); "done" } } defined object Demo scala> Demo res5: Demo.type = Demo$@4518497e scala> Demo.x initializing x res6: String = done scala> trait LazyRationalTrait { val numerArg: Int val denomArg: Int lazy val numer = numerArg / g lazy val denom = denomArg / g override def toString = s"$numer/$denom" private lazy val g = { require(denomArg != 0) gcd(numerArg, denomArg) } private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) } defined trait LazyRationalTrait scala> val x = 2 x: Int = 2 scala> new LazyRationalTrait { val numerArg = 1 * x val denomArg = 2 * x } res7: LazyRationalTrait = 1/2 scala> class Food abstract class Animal { type SuitableFood <: Food def eat(food: SuitableFood): Unit } class Grass extends Food class Cow extends Animal { type SuitableFood = Grass override def eat(food: Grass) = {} } defined class Food defined class Animal defined class Grass defined class Cow scala> class Fish extends Food defined class Fish scala> val bessy: Animal = new Cow bessy: Animal = Cow@5f7cc6fd scala> bessy eat (new Fish) ^ error: type mismatch; found : Fish required: bessy.SuitableFood scala> class DogFood extends Food class Dog extends Animal { type SuitableFood = DogFood override def eat(food: DogFood) = {} } defined class DogFood defined class Dog scala> val bessy = new Cow bessy: Cow = Cow@5af535ff scala> val lassie = new Dog lassie: Dog = Dog@29d578de scala> lassie eat (new bessy.SuitableFood) ^ error: type mismatch; found : Grass required: DogFood scala> val bootsie = new Dog bootsie: Dog = Dog@2fba0d7a scala> class Outer { class Inner } defined class Outer scala> val o1 = new Outer val o2 = new Outer o1: Outer = Outer@3296b4ba o2: Outer = Outer@26fddb3f scala> new o1.Inner res11: o1.Inner = Outer$Inner@3b3bd5fe scala> new Outer#Inner ^ error: Outer is not a legal prefix for a constructor scala> object Direction extends Enumeration { val North = Value("North") val East = Value("East") val South = Value("South") val West = Value("West") } defined object Direction scala> for (d <- Direction.values) print(d + " ") ^ warning: method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call + North East South West scala> Direction.East.id res14: Int = 1 scala> Direction(1) res15: Direction.Value = East scala> abstract class CurrencyZone { type Currency <: AbstractCurrency def make(x: Long): Currency abstract class AbstractCurrency { val amount: Long def designation: String def + (that: Currency): Currency = make(this.amount + that.amount) def * (x: Double): Currency = make((this.amount * x).toLong) def from(other: CurrencyZone#AbstractCurrency): Currency = make(math.round( other.amount.toDouble * Converter.exchangeRate (other.designation)(this.designation))) private def decimals(n: Long): Int = if (n == 1) 0 else 1 + decimals(n / 10) override def toString = ((amount.toDouble / CurrencyUnit.amount.toDouble) formatted ("%." + decimals(CurrencyUnit.amount) + "f") + " " + designation) } val CurrencyUnit: Currency } object US extends CurrencyZone { abstract class Dollar extends AbstractCurrency { def designation = "USD" } type Currency = Dollar def make(cents: Long) = new Dollar { val amount = cents } val Cent = make(1) val Dollar = make(100) val CurrencyUnit = Dollar } object Europe extends CurrencyZone { abstract class Euro extends AbstractCurrency { def designation = "EUR" } type Currency = Euro def make(cents: Long) = new Euro { val amount = cents } val Cent = make(1) val Euro = make(100) val CurrencyUnit = Euro } object Japan extends CurrencyZone { abstract class Yen extends AbstractCurrency { def designation = "JPY" } type Currency = Yen def make(yen: Long) = new Yen { val amount = yen } val Yen = make(1) val CurrencyUnit = Yen } object Converter { var exchangeRate = Map( "USD" -> Map("USD" -> 1.0 , "EUR" -> 0.7596, "JPY" -> 1.211 , "CHF" -> 1.223), "EUR" -> Map("USD" -> 1.316 , "EUR" -> 1.0 , "JPY" -> 1.594 , "CHF" -> 1.623), "JPY" -> Map("USD" -> 0.8257, "EUR" -> 0.6272, "JPY" -> 1.0 , "CHF" -> 1.018), "CHF" -> Map("USD" -> 0.8108, "EUR" -> 0.6160, "JPY" -> 0.982 , "CHF" -> 1.0 ) ) } defined class CurrencyZone defined object US defined object Europe defined object Japan defined object Converter scala> Japan.Yen from US.Dollar * 100 res16: Japan.Currency = 12110 JPY scala> Europe.Euro from res16 res17: Europe.Currency = 75.95 EUR scala> US.Dollar from res17 res18: US.Currency = 99.95 USD scala> US.Dollar * 100 + res18 res19: US.Currency = 199.95 USD scala> US.Dollar + Europe.Euro ^ error: type mismatch; found : Europe.Euro required: US.Currency (which expands to) US.Dollar