Scala Case Classes vs Enumeration

After my previous post which was received quite nicely, I wanted to write a little bit more about the topic of designing Typesafe Domain objects, this time I’ll focus on the problem of how to model a deck of cards in Scala. I’ll go over 2 different approaches you might take when designing a solution to the problem of card games in Scala. I’ll try to show how this can be done with Case Classes (Sealed Case Objects) and Enumerations.

I’ll go over those two approaches and after showing each one, I’ll provide a brief summary with listing possible pros and cons, also I’ll share my thoughts how choosing one approach will affect project in the future. At the end of this post I’ll try to pick one approach and justify my decision.

I’ll be happy to see your comments with thoughts and your own reasoning why you would pick one and not the other.

Defining the scope of the problem

But before we start, let’s first describe the scope of the problem:

For my current playground project I want to be able to process card games in a fully type-safe manner. This will allow me to offload a lot of processing and validation to the compiler. For example I want to define orderings between Ranks and Cards, also I would like to have a way to easily compare, order and shuffle cards and decks. I would also like to have a reasonably easy way to ensure that the deck is always valid (for example no duplicated cards). Ideally I would like to have an easy way to map those entities to and from JSON.

First Approach: Case Objects

In this approach I have decided to create separate sealed case objects for both Suits and Ranks, then for each of them, I have listed all possible options, each extending Suit or Rank respectively.

This gave a quite nice interface for creating more complex objects like Card or Deck which where composed out of them. Only problem I had was the ordering of the Ranks, which is not easy to address when defining type system.

Take a look at following piece of code and analyze it yourself, below it you will find my observations:


File is also available here: https://github.com/wlk/game-arena/blob/master/app/models/v1/cardsCaseObjects.scala

In my opinion, the biggest problem here is the duplication between lines 20-33 where we define all Ranks for the cards, and lines 15-18 when we have to put all of them in to a list (so later in the code, on line 41, we’ll be using that list for ordering of the cards)

The same, but to the lesser extend happens in the Suit object and the trait, we have to explicitly list all Suits so we will be able to iterate over them.

Summary of this approach:

Pros:

  • Overall it’s very convenient approach. In the Playground object, I have defined few operations you can execute (play around with it in the Scala REPL)
  • Using sealed traits will allow to offload work related to pattern matching to the compiler

Cons: 

  • We had to split enumerating Ranks and actually ranking them into 2 separate places

My guess how this approach would affect project in the further stages:

In the real project probably we will be able to leverage pattern matching a lot which here will not be a problem, also it should be quite easy to use some JSON library to map objects. Keeping a list of Ranks and their ordering in sync is not a problem because it won’t change.

Second Approach: Enumerations

Working with Enumerations in Scala can be a little cumbersome, they seem to be added to the language a little bit on the site, outside of the mainstream.

Nonetheless they are very useful as a solution to my problem, thanks to them I was able to write 15 lines of code less and have a more consistent model


File is also available here: https://github.com/wlk/game-arena/blob/master/app/models/v2/cardsEnumeration.scala

I’ll analyze this approach in contrast to the first one. First thing that is most obvious to see is that here instead of using case classes we use enumerations 🙂 Suits are defined in lines 5-7 and Ranks are defined in lines 9-11. By defining them in this order, we automatically get an Ordering which means we don’t have to explicitly list all of them and put them into a List like we had to do in the first case.

If you take a look further, you will actually see very little differences, only Card class definition is different – we are accepting Values as parameters, instead of object. Also creating a full deck is a little bit different.

The Playground object is exactly the same!

Let’s take a look at this approach from the pros and cons perspective:

Pros:

  • Less code to write
  • No need to define Rank ordering outside of the Rank definition

Cons:

  • Enumerations are a little bit clumsy
  • No compile-time checking of match exhaustiveness
  • This results in less type safety

My guess how this approach would affect project in the further stages:

I think even though this approach at the moment seems like a more natural fit to our domain, it’s also potentially more risky. We are abandoning compile time checking (which is a problem, especially when the rest of our code relies on it and we got used to that), also I suspect that this will require more code to integrate with JSON libraries, some of them do not have a natural interface to Enumerations

Summary

As project moves forward, at some point we have to make a decision which road to take: Should I design this functionality as Sealed Case Objects or Enumerations?

Good news is that, when designing it carefully you wouldn’t need to choose, at least for some more time. If you analyzed 2 examples I have shown, especially the code that uses our simple library (the Playground object) you will see that there is no difference in the code. This is a good indicator that we should be able to either continue developing both solutions until it will be clear which approach doesn’t scale anymore. Or focus on one approach, but with keeping in mind that we can always switch to the other one if you find some problem with it.

In my case I find the approach of Sealed Case Objects a more flexible one and also I get compile time checks, this is why I decided to go that route. I’m not worried about additional 15 lines of code because I value type safety and other advantages like better support for JSON marshalling more.

References:

BTW. Did you know that I’m available for hire?

Typesafe Domain Objects in Scala

Today I’d like to cover the topic of how to approach type safety in Scala in case of the simple domain of players in free to play games – this is a real example from a past project of mine. If you have played any of the free to play online games, you are already aware that these games every often have 2 kinds of currencies:

  • In game cash or points that can be earned and spent during the game play
  • In game gold / premium points that can be purchased only for a real currency via the in-app purchase, they can be spent to buy special equipment or power ups that are not available for purchase with regular in-game cash

For simplicity I’ll call them GameCash and GameCoins. The most important thing for us right now is that they are completely separate currencies, they cannot be exchanged, compared, added, etc.

First Implementation

Let’s take a look at simple and very naive example of how you could write down a class definition of a Player in a game like ours:

This is a very simple piece of code, and the main problem here is a ubiquitous lack of type safety. Which means that you are free to add and compare all Int values here, you could easily write:

As you can see, a code like that is very likely to occur in your application, if you followed TDD or had a comprehensive test suite, it probably would have caught that, but we didn’t have any tests here.

Let’s look at the less artificial situation, in which not enough type safety could hit us:

If later in the code you would have a method that allows a player to purchase additional in-game resources (for example some imaginary “Energy”), it would look something like this:

As you can see I have made a mistake on line 4 – I’m subtracting “100” from gameCoins and assigning it to gameCash this is of course wrong.

You could leverage your test suite for this purpose, but in Scala you could approach this type of problem in a different manner – introduce new types, and leverage compiler to guard us and drive the implementation.

Introducing Types

Following piece of code is the redesigned version of the Player class:

I have defined custom types for all properties of the player that previously where Ints and I have used those new types in the declaration of the Player case class.

When creating case classes that wrap exactly one parameter you should add extends AnyVal to allow Scala compiler to run more optimizations – basically type checking will be done only during compilation phase, but during runtime only objects of the underlying type will be created which leads to less memory overhead – more information here and in the Scala documentation (thanks to Paweł Jurczenko for pointing out my previous mistake in this paragraph)

Because I didn’t do anything else like defining operators to compare values, this makes all those types not comparable with each other, and any attempt to do so will result in compilation error, let’s take a look:

And in the case of buyEnergy function, you at first get code completion in your IDE, so this is how the fixed version looks like:

Taking It Further

In the last code sample on lines 4 and 5 in order to do any mathematical operations I had to “unwrap” my own types and access it’s internals using .value, this is also error prone, this is why I suggest to implement few opeartors that will make everything more pleasant.

This is how we want our buyEnergy function to look like:

This makes the method much less error prone and more readable, those are required changes to our domain model:

You could of course implement more operators as they are needed.

I have decided not to implement all mathematical operations, primary because in my case I didn’t want all of them to be available – only addition and subtraction make sense for this use case. But it’s possible that in your case this will make sense, then possibly you could define all of them in the parent class and reuse them.

Benefits Of Type Safety

As you saw during this tutorial, adding custom types in the specific points in our code not only improved readability but also allowed us to make less errors – offload some of the checking that otherwise would have to be done in tests (or not done at all) to the compiler. You can also immediately see errors in your IDE or editor.

Because now each component in the Player class is itself a separate type, it’s also very easy to add new operators that otherwise probably would have to be added implicitly which would pollute larger scope.

What are the disadvantages here? Personally, only negative side here is that sometimes you have to write a little more code to define your class. In my opinion is very good price to pay.

This post has an followup: Scala Case Classes vs Enumeration

My Entry to “Daj Się Poznać” Competition

In this blog post I intent to give a brief overview of “Daj się poznać” competition and some reasoning why I decided to join it.

Few words about “Daj Się Poznać”

“Daj się poznać” (in English: “Let yourself known”) is a competition aimed at Polish programming community and it’s idea is to help programmers to be more involved in both blogging and open source work.

Currently it’s aimed only at the polish market, so all content on the official website is in Polish, most of the participants are blogging in Polish, only few in English.

The rules are quite simple. Over the course of 10 weeks (until the end of May 2016) you are supposed to work on your side project (Open Source), and keep a active blog where you will be blogging about this project. You need to write at least 2 posts per week. There are some prizes for the winners, which is nice, but for me this is not the most important here.

All my posts will be tagged with “dajsiepoznac” so you can see all of them here: http://www.wlangiewicz.com/tag/dajsiepoznac

This is actually the second edition of this competition, but the previous one took place 5 or 6 years ago, so I couldn’t miss this one.

My Project – Game Arena

My project is inspired by the Lean Poker event, in which I participated during ChamberConf a week ago.

I intent to create a game arena, where you, as a programmer could write your own bot which will play a Poker game (Texas Hold’em). The bots will compete against each other. The idea is that you could setup this session for a weekend and treat it like a code retreat or something similar.

Technical aspectS

This is a overview of what I have to create in next 10 weeks:

  • Texas Hold’em game engine
  • Communication API to talk to the bots
  • Bot process encapsulation + management (probably achieved via docker)
  • Basic UI so you will see how your bot plays the game
  • Page with the ranking for the turnament

I’ll be using Play framework for the application base + akka for communicating with the bots.

Simplifications

Because of very limited time (both for the competition and my own free time), I have to make few very important simplifications

  • Only implement one game (Texas Hold’em)
  • Initially focus only on the bots written in Scala/Java/JVM
  • Initially ignore UI
  • I wanted to implement Blackjack, but it’s not easy to create a meaningful global ranking for this game

BTW: Did you know that I’m available for hire?