Thursday, 21 June 2012

Scala: Polymorphism rework

As dude came from C# and Java to Function Programming I'm thinking on polymorphism in therms of OOP only. I was believing in: Polymorphism is coming only as a monolithic bundle based on Inheritance. But look into this:
This is the method that is accepting ... type T, which should be any type, and this is good example of ... Polymorphism. Method second is getting a list of T and should return extracted T (we can try to guess that the best fit logic here is returning second element). Doesn't matter which T is inside - method declared to work with All types: Int, String, List[List[String]], AnyRef, whatever. This part for OOP world dudes is unnatural, then let's move to a new: Ad-hoc Polymorphism.

Ad-hoc polymorphism.

Here we have a restriction on return type, not all T are Int. When any restriction on typing is coming we can start thinking on Ad-hoc polymorphism. In example above we have a method implements some business: counts something, and returns Int. As we told not all T are Int, even not all T can be somehow presented or linked with T. Well here we were always using OOP inheritance, class hierarchy and other "sweats" to 1. Restrict inputs 2 Help to implement business. Bellow is simple example of count method, that requires T to be a child of Countable.
This version is doing more than just stricting list of parameters, but allows to determine which methods are allowed to be used inside method body on type T. Moving close to ad-hoc way. Imagine situation when we compare any objects in the system. Doesn't depend - are real instances implement equals?, even worse - we don't carre about source code of classes. Possible solution is: We are defining trait Eq, that wraps any type T, and returns boolean value that means: "are 2 instances of T are equaled?". Additionally there is class EqOps that defines === and !== operations and is used to be implicitly added to any Type. All business it delegates to Eq, that is expected to be implicitly injected. Object ExtraImplicits is just a container for implicit method injections required to be imported when we want to use ad-hoc Equal functionality on our objects. Example of usage:
We are declaring class 'A' that incapsulates Int value, business of equality for 'A' is simple: if left and right has value less than 100 - they are the same - otherwise compare the values. With help of import ExtraImplicits._ we are adding === and !== to A (of course to all other types as well in case when implicit e: Eq[T] is provided). Eq[T] implicit injection must be implemented if we are going to use === and !== on other than A instances.
Looking carefully into example we can recognise the "shapes" of Type Classes. If we combine using "containers" with implicits, we get “ad-hoc” polymorphism: the ability to write generic functions over containers, and containers can be even hided via implicit methods injections.

No comments:

Post a Comment