FPS: Chapter 40
Chapter 40: A Functional Game
This is an example of writing a game with immutable state, so It’s going to be a meh chapter. Just going to get through it - had to open up the code on the book’s recommendation. Looking at the code it’s pretty simple - there’s a case class for game state that he’s copying and overwriting fields on.
He’s not going to handle I/O in a functional way with monads so this chapter is going to be very boring.
The main game loop is recursive with a @tailrec annotation which is interesting. Also the game extends App which I thought was an aka library thing but must be basically a Scala primitive. He encouraged us to write it ourselves which usually I would do, but in this case I really don’t think is worthwhile.
Yeah, this chapter was pretty useless other than the fact that I get to see a recursive game loop which is interesting. Funny the game was a heads/tail predictor.
Chapter 41: Case Classes
A case class generates a lot of code for you:
- An
applymethod so you don’t need to use thenewkeyword on creation. This is also why you still need to usenewwhen instantiating a Java class - Accessor methods for each constructor parameter, because they are
public valby default so they get accessor’s - An
unapplymethod is generated which makes it easy to use case classes inmatchexpressions. This is a huge FP win apparently. copymethod which you can use to make a new val of your variable with fields changed.equalsandhashCodeso you can use your objects as keys in a map or set, and also compare objects. Really with Java had this auto-comparison, I used to hate generating that code! I’ve heard of nasty bugs from hashCode methods that were missing a field.- A default
toStringmethod is generated which is useful for debugging. Also great, really hated generating that code in the past.
Code Examples
No need for the new keyword:
case class Person(name: String)
val chris = Person("Chris")
Unapply method allows pattern matching and to expand the inner properties:
chris match {
case Person(name) => println(name)
}
Normal Scala classes do not compile in a match, only case classes. Maybe if you had an unapply on the class and you extended a trait you could make it work however - I’m not sure.
Copy Method:
val chris = Person("Chris")
val jeff = chris.copy(name = "Jeff")
Useless here with one field in a case class, but normally allows you to update only one field on an object
Equals and hashCode:
val chris = Person("Chris")
val jeff = Person("Jeff")
if(chris == jeff) println("This will never happen")
toString method:
val chris = Person("Chris")
println(chris)
This will print helpful information.
So overall case classes are amazing - they reduce a ton of Java boilerplate that I used to have to write, which removes a bunch of code and potential avenue for bugs. Also pattern matching is great, you always love to use it. It’s just pretty.
Next chapter is on copying case classes, which should be great.