F-bound over a generic type in Scala

In this article, I will be mentioning Comonads. If you know what they are, great, and if you don’t know, no worries, because this article’s main topic isn’t Comonads. It’s actually about Scala generics, about F-bound, about returning the “Current” Type in Scala.

In my odyssey to understand Comonads, the first thing I did after reading about them was to implement a series of tests that would make them a little bit clearer, and I did it using the NonEmptyList implementation of the scalaz library.

But obviously testing a specific implementation wouldn’t get me to the end of it, so I decided to implement an IdentityComonad by myself, a Comonad without added functionality.

If you are not very used to generics… right now you might be getting a strong migraine. This way, IComonad uses A, just like before, but now it also uses F[A], determining the type used in the implementation.

It may seem very confusing & messy, but to sum up, the implementation tells to its interface who it is, so that the interface can force the types.

Great, huh!? Now the return type must be exactly the type of the class that we are implementing (IdentityComonad), we no longer have the same problem we had before (being able to use sibling IdentityComonad types)

But… do you smell that? I smell it too… I am not being forced to tell IComonad that T is IdentityComonad.

I mean, IdentityComonad could extend IComonad [A, Something] (being Something another generic class that accepts [A]), and everything would work out (using Something as F)

It’s kind of hard to explain, so I’ll draw a picture to illustrate it:

See? Now I have a ListComonad, not bad huh? But this isn’t really a valid list Comonad, I am not returning a Comonad, so I can’t chain them either.

Also, the ListComonad parameter is not of type A, it is of type List[A], and this is a problem, because ListComonad should not depend of List (which is a monad).

But it doesn’t matter, let’s keep focus, the fact is that I just demonstrated that I can fool the interface to use types that I shouldn’t use (or do not want to use, it all depends on how you look at it).

And so we made it to the final implementation, the best I’ve arrived to until now (without using typeclasses).

Now we try to force F[A] in IComonad to be a subtype of IComonad (F[A] <: IComonad[A,F]), this makes more sense. Now List, wouldn’t be able to occupy the place of F.

However, it could be done by a FakeComonad or any other sibling type of IdentityComonad (which extends from IComonad), but at least we have limited the possibilities of “messing it up”:

Obviously there will be people saying: but if this is just an F-bound! You could have done it from the beginning! Well, it is true, it’s an F-bound, however it has a special difficulty: it is an F-bound in the presence of 2 type parameters (A and F), meaning it’s an F-Bound on a type that already is generic, that forces us to use a higher kinded type (F[A]). That’s what is great about this experiment, getting to the point where just an F-Bound doesn’t work, and we have to use higher kinded types!

Once you get to the end and if you understood everything, it is not much more complicated than a normal one, but in the beginning it can be lousy.

Hey, and wouldn’t a typeclass solve your life? Of course, with a typeclass we get rid of these problems, since they have the type explicitly defined for each typeclass. But what’s nice is to check how far we can get, right? How far can we get using only this set of tools?

To those of you who want to see how to do this kind of thing with a typeclass, here’s a good reference.

To conclude, throughout this flow of thought that we followed, we can see that the indiscriminate use of generics can give rise to curious holes.

This doesn’t mean that you should stop using them! It means that when creating very generic types, for libraries and others, special care must be taken, to monitor certain bugs that can be created.

If you found this article about Scala F-bound interesting, you might like…