I’ve been doing a lot of Scala programming lately. Scala is a statically typed language that compiles to the JVM. Scala doesn’t break away from object oriented programming but has a lot of functional programming features.
One of my favorite features of Scala is its case classes. Case classes are a lot like regular classes but they’re easier to setup and usually used to model immutable data. They also allow for easy pattern matching.
case class Person(
name: String,
age: Int
)
val bob = Person(name="bob", age=20)
Values in a case class are publicly accessible and immutable by default. Note there is no new keyword when instantiating a case class.
Case classes can be compared:
val bob2 = Person(name="bob", age=20)
println(bob == bob2) // true
Since case classes are usually used to model immutable data, Scala gives you a copy function where you can override certain fields. Copy returns a new instance
val youngBob = bob.copy(age=15)
Scala also allows for matching.
bob match {
case Person("bob", _) => println("hi bob!")
case _ => println("I don't know you")
}
If you are interested in learning more about Scala, I recommend Scala for the Impatient. If you want to just play around, check out ScalaFiddle.
I like Scala case classes so I thought it would be fun to build them out in Python. Case Classes in Python
See full code below and skip down for discussion and examples:
CaseClass is not actually a class, but a function that returns a class. The function takes in any number of named parameters and their types (Scala is strongly typed after-all). The function raises a ValueError if your parameter value is not a type.
Initializing a CaseClass can be seen below. Remember, the function returns the class.
Person = CaseClass("Person", name=str, age=int)
Now that we have a Person case class, we can create a few Person instances:
bob = Person(name="bob", age=20)
Our case class enforces the right parameters are passed and even the right types:
Person(name="bob") # ValueError: Missing values {'age'}
Person(name="bob", age=20, weight=170) # ValueError: Extra values {'weight'}
Person(name="bob", age=20.5) # ValueError: age is of <class 'float'>, must be of <class 'int'>
And case classes are meant to model immutable data, our values are immutable:
bob.name = "jimmy" # AttributeError: Reassignment to val
bob.zip_code = 90210 # AttributeError: Value zip_code
We also have some useful features, like equality:
bob2 = Person(name="bob", age=20)
young_bob = Person(name="bob", age=15)
bob == bob2 # True
bob == young_bob # False
and copy:
big_bob = bob.copy(name="big bob")
and of course match:
bob.match(
({"name": "alice"}, "Its alice!"),
({"name": "bob"}, "Hi bob!"),
(None, "I don't know you")
)
bob.match(
({"name": "bob", "age": 15}, "Hi young bob!"),
({"name": "bob", "age": 20}, "Hi older bob!"),
(None, "I don't know you")
)
Sure, it’s not as nice as Scala, but pattern matching is long overdue in Python. Scala has some other features that I didn’t build out like guards on matching (conditional statements), but I’ll leave that to the reader.