This is extended and updated version that is inspired by A Complete Guide to Variance in Java and Scala