Sunday, December 24, 2017

Exploring Type class in Scala: Conclusion

I remember watching Dan Rosen's excellent video tutorial on Type class in Scala, earlier this year. And I remember understanding what he was saying, but yet, I was not sure If I grokked the concept he was trying to explain.

I understood all the code snippets, I could follow along with the examples but yet I was not sure I was getting it. I could not really appreciate the rationale, it felt as if I was rote learning and after watching that video tutorial, I was not sure if I could think in type classes.

Moreover, the whole machinery he was describing just felt way too verbose. And this feeling was not just exclusive to the video, it was how I felt about almost every blog post on type class in Scala back then.

I have since then realized why I felt this way: I was working with the wrong mental model.


There were other minor things that I could identify that deterred a quicker grokking of the concept: things like the fact that it is not a native language feature but a pattern, and as all programming patterns go, it usually takes a trained eye to spot them. Also the fact that some Scala syntax I was not familiar always gets thrown in the picture.  But these are all trivial compared to the main determent: which was, I was approaching the subject with the wrong worldview, a wrong assumption of certain aspects of code construction and I was trying to apply a wrong mental model to learn a concept that was totally orthogonal to what I already knew.

If you have read the post in this series, you will realize that I spent quite some time in articulating some of the flawed assumptions and mental models that deterred a quicker understanding of type classes. In fact, the first 3 posts in the series were totally dedicated to laying the groundwork before the machinery of encoding type classes in Scala was laid out.

Doing this is very important because I do not think a new concept can be truly understood when one is still limited by wrong assumptions, wrong mental models and is still using inaccurate analogies as thinking tools.

In that spirit, I would like to conclude this series with another limiting mental model, that I had to let go off before I could start appreciating type classes. And this is the fact that it is totally okay to have behavior separated from data.

Data and Behaviour Can Be Separate, and that is Fine

Before now, I have always had a view that data and behavior had to be part of one and the same thing...

I can blame this mental model on years of only working with programming languages that bundles data (or state when such data is mutable) together with behavior. The most recent programming language I had work with, which is Java, almost treats this as a law of nature, as if it is some sort of natural order to things.

Your objects must contain your properties or data together with its functionalities or behaviors, which are exposed via methods,  and because you do not want the outside world to be privy to the internal states of your objects, you encapsulate all the things.

No. It is possible to have data on one hand and to have functionality and behavior on another...and...this...is..perfectly...fine.

I can make a guess that attempting such a switch might not come easy and your OOP mindset will scream at you for considering such a blasphemy. At least for me, that switch did not come easy. It took having to be confronted by a different worldview in Haskell, where, by default data is separate from behavior, to fully embrace such a proposition.

And if you think about it, type classes are just one extension of having a situation where behavior cannot cohabit, directly, together with data.

The code that is written as part of the type class instances is the code that would have been lumped together with objects in the typical Java set up. Lumped together with the object and perhaps implemented as part of an interface to allow for polymorphic use.

With type classes, you have a mechanism that allows you to have this code live somewhere else (aka type class instances) and have your data still separated but still be able to link the two together when needed.

Accepting this as another valid way to code construction was very helpful, and it goes without saying that these kinds of paradigm shift are needed in other to be able to fully appreciate not just type class in Scala but the other side of Scala that is not OOP.

If you are a Java developer and you still struggle with this proposition of having data separate from behavior, think about the numerous POJO's you have written that contains only fields together with getters and setters, and ask yourself if such level of indirection is actually needed? where obviously you have plain data but still had to wrap the data in this whole ceremony of getters/setters in other to access them.

Once you start convincing yourself that this is indeed too much of a ceremony, and these plain old Java objects can be left alone as a mechanism to capture data, without attaching getters/setters unto them, then taking the next step of having a different mechanism to host their behavior, instead of running to these anaemic objects to fortify them with behaviour, should start feeling plausible.

Recommended Resources
Based on my own experience, here are some few learning resources that I can easily recommend:
So this concludes the series: Exploring Type class in Scala: A knowledge pack. I really do hope it helps in making learning about type classes in Scala a lot easier.

If you have any feedback, any thoughts, comments about your own learning experience, about how this series helped out or about what you still find confusing, please do not hesitate to use the comment section! :)

2 comments:

Anonymous said...

Really useful series. Thank you!

Anonymous said...

Super super useful, after this series I have better understanding about the type class pattern and implicit scope