I can't say I know all the intricacies, but my rule of thumb is to use projections when you want to
receive something where you don't care about its type parameters. You can't
create a type with a projection. e.g.
val foo = ArrayList<Any?>()
val baz: ArrayList<*> = foo
val bar = ArrayList<*>() // Not valid