-
-
Save parambirs/c7ec10306b1bedb7a7bd to your computer and use it in GitHub Desktop.
// 1. Improve the Counter class in Section 5.1, "Simple Classes and Parameterless | |
// Methods," on page 51 so that it doesn't turn negative at Int.MaxValue. | |
class Counter { | |
private var value = 0 | |
def increment() { if(value < Int.MaxValue) value += 1 } | |
def current = value | |
def isLess(other: Counter) = value < other.value // can access private field of other object | |
} | |
// 2. Write a class BankAccount with methods deposit and withdraw, and a read-only | |
// property balance. | |
class BankAccount { | |
private var _balance = 0 | |
def balance = _balance | |
def deposit(money: Int) = _balance += money | |
def withdraw(money: Int) = if(money < _balance) _balance -= money | |
} | |
// 3. Write a class Time with read-only properties hours and minutes and a method | |
// before(other: Time): Boolean that checks whether this time comes before the | |
// other. A Time object should be constructed as new Time(hrs, min), where hrs is in | |
// military time format (between 0 and 23). | |
class Time(val hrs: Int, val min: Int) { | |
def before(other: Time) = { | |
(hrs < other.hrs) || (hrs == other.hrs && min < other.min) | |
} | |
} | |
// 4. Reimplement the Time class from the preceding exercise so that the internal | |
// representation is the number of minutes since midnight (between 0 and | |
// 24 * 60 - 1). Do not change the public interface. That is, client code should be | |
// unaffected by your change. | |
class Time(hrs: Int, min: Int) { | |
private val _time = hrs * 60 + min | |
def before(other: Time) = _time < other._time | |
} | |
// 5. Make a class Student with read-write JavaBeans properties name (of type String) | |
// and id (of type Long). What methods are generated? (Use javap to check.) Can | |
// you call the JavaBeans getters and setters in Scala? Should you? | |
class Student (@BeanProperty var name: String, @BeanProperty var id: Long) { | |
} | |
/* | |
What methods are generated? (Use javap to check.) | |
//Compiled from "Student.scala" | |
public class Student implements scala.ScalaObject { | |
public java.lang.String name(); | |
public void name_$eq(java.lang.String); | |
public void setName(java.lang.String); | |
public long id(); | |
public void id_$eq(long); | |
public void setId(long); | |
public long getId(); | |
public java.lang.String getName(); | |
public Student(java.lang.String, long); | |
} | |
Can you call the JavaBeans getters and setters in Scala? => Yes | |
Should you? => No because they are verbose and not as intuitive as scala's methods | |
*/ | |
// 6. In the Person class of Section 5.1, "Simple Classes and Parameterless Methods," | |
// on page 51, provide a primary constructor that turns negative ages to 0. | |
class Person(var name: String = "", var age: Int = 0) { | |
if(age < 0) age = 0 | |
} | |
// 7. Write a class Person with a primary constructor that accepts a string containing | |
// a first name, a space, and a last name, such as new Person("Fred Smith"). Supply | |
// read-only properties firstName and lastName. Should the primary constructor | |
// parameter be a var, a val, or a plain parameter? Why? | |
class Person(name: String) { | |
private val fnln = name.split(' ') | |
val firstName = fnln(0) | |
val lastName = fnln(1) | |
} | |
// Should the primary constructor | |
// parameter be a var, a val, or a plain parameter? Why? | |
// => It should be a plain parameter as it's not used in any of the methods | |
//8. Make a class Car with read-only properties for manufacturer, model name, | |
//and model year, and a read-write property for the license plate. Supply four | |
//constructors. All require the manufacturer and model name. Optionally, | |
//model year and license plate can also be specified in the constructor. If not, | |
//the model year is set to -1 and the license plate to the empty string. Which | |
//constructor are you choosing as the primary constructor? Why? | |
class Car(val manufacturer: String, val modelName: String, val modelYear: Int, var licensePlate: String) { | |
def this(manufacturer: String, modelName: String, licensePlate: String) = { | |
this(manufacturer, modelName, -1, licensePlate) | |
} | |
def this(manufacturer: String, modelName: String, modelYear: Int) = { | |
this(manufacturer, modelName, modelYear, "") | |
} | |
def this(manufacturer: String, modelName: String) = { | |
this(manufacturer, modelName, -1, "") | |
} | |
override def toString = { | |
"[" + manufacturer + ", " + modelName + ", " + modelYear + ", '" + licensePlate + "']" | |
} | |
} | |
// Using default values for constructor parameters, this class can be simplified to the following | |
class Car(val manufacturer: String, val modelName: String, val modelYear: Int = -1, var licensePlate: String = "") { | |
def this(manufacturer: String, modelName: String, licensePlate: String) = { | |
this(manufacturer, modelName, -1, licensePlate) | |
} | |
override def toString = { | |
"[" + manufacturer + ", " + modelName + ", " + modelYear + ", '" + licensePlate + "']" | |
} | |
} | |
// Which constructor are you choosing as the primary constructor? Why? | |
// => The constructor that takes all 4 values was chosen as the primary constructor. It's easy to define the other | |
// constructors that simply need to call the primary constructor with some default values | |
//9. Reimplement the class of the preceding exercise in Java, C#, or C++ (your | |
//choice). How much shorter is the Scala class? | |
public class JCar { | |
private String manufacturer; | |
private String modelName; | |
private int modelYear = -1; | |
private String licensePlate = ""; | |
public JCar(String manufacturer, String modelName, int modelYear, String licensePlate) { | |
this.manufacturer = manufacturer; | |
this.modelName = modelName; | |
this.modelYear = modelYear; | |
this.licensePlate = licensePlate; | |
} | |
public JCar(String manufacturer, String modelName, int modelYear) { | |
this.manufacturer = manufacturer; | |
this.modelName = modelName; | |
this.modelYear = modelYear; | |
} | |
public JCar(String manufacturer, String modelName, String licensePlate) { | |
this.manufacturer = manufacturer; | |
this.modelName = modelName; | |
this.licensePlate = licensePlate; | |
} | |
public JCar(String manufacturer, String modelName) { | |
this.manufacturer = manufacturer; | |
this.modelName = modelName; | |
} | |
public String getLicensePlate() { | |
return licensePlate; | |
} | |
public void setLicensePlate(String licensePlate) { | |
this.licensePlate = licensePlate; | |
} | |
public String getManufacturer() { | |
return manufacturer; | |
} | |
public String getModelName() { | |
return modelName; | |
} | |
public int getModelYear() { | |
return modelYear; | |
} | |
@Override | |
public String toString() { | |
return "[" + manufacturer + ", " + modelName + ", " + modelYear + ", '" + licensePlate + "']"; | |
} | |
} | |
//10. Consider the class | |
//class Employee(val name: String, var salary: Double) { | |
// def this() { this("John Q. Public", 0.0) } | |
//} | |
//Rewrite it to use explicit fields and a default primary constructor. Which form | |
//do you prefer? Why? | |
class Employee() { | |
private var _name: String = "John Q. Public" | |
var salary: Double = 0.0 | |
def this(n: String, s: Double) { | |
this() | |
_name = n | |
salary = s | |
} | |
def name = _name | |
} |
thanks a lot for your solutions. Compared with mine and found a couple of interesting things. Though p.10 seems to be not quite right. It states:
Rewrite it to use explicit fields and a default primary constructor.
while you used auxiliary constructor.
Pay attention at chapter
5.7 THE PRIMARY CONSTRUCTOR
In Scala, every class has a primary constructor. The primary constructor is not defined with a this method. Instead, it is interwoven with the class definition
- The parameters of the primary constructor are placed immediately after the class name.
class Person(val name: String, val age: Int) {
// Parameters of primary constructor in (...)
...
}
Can anyone help me understand the underscore before the var name (_balance) in p.2 ?
@InnaValentino the underscore is just a common scala convention to signal a private field in the class. I like the underscore, but you could rename _balance to privateBalance if that makes more sense to you. That's how the book does it on page 58
That's kind of you sharing these exercises. I have a chance to compare and learn things that didn't come to my mind. Here are my 2 cents:
L19: money <= _balance
L81-83: val Array(firstName, lastName) = name.split(" ")
L96-112: I used 2 param (manifacturer, modelName) default primary constructor. Then wrote 3 additional constructors with manifacturer, modelName by default + ([modelYear], [licencePlate], [modelYear, licencePlate]) for the three. I don't know which one was intended.
L110 - 122: s"$manufacturer $modelName ($modelYear) <$licencePlate>"