ericelliott / rtype

Intuitive structural type notation for JavaScript.
MIT License
1.13k stars 38 forks source link

declaration-site variance annotations of generic type arguments #81

Open maiermic opened 8 years ago

maiermic commented 8 years ago

Declaration-site variance annotations in other languages

C#, Kotlin, Ceylon:

Scala, OCaml, Flow:

What should we choose? (see discussion about generic types in #55 and #80)

Mouvedia commented 8 years ago

http://flowtype.org/docs/classes.html#polymorphism-and-type-parameter-variance

maiermic commented 8 years ago

@Mouvedia Thx, I added Flow.

Mouvedia commented 8 years ago

https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-function-parameters-bivariant

Could you provide a JS example or a link to a ressource?

ericelliott commented 8 years ago

We handle polymorphism with the ability to use multiple signatures. Do we need variance annotations as well? Can you show some example usage and compare with multiple signature annotation to more clearly point out advantages or disadvantages?

What do variant annotations give us that we don't already have?

maiermic commented 8 years ago

@Mouvedia This is the TypeScript example (of your link) that causes a runtime error:

function trainDog(d: Dog) { ... }
function cloneAnimal(source: Animal, done: (result: Animal) => void): void { ... }
let c = new Cat();
// Runtime error here occurs because we end up invoking 'trainDog' with a 'Cat'
cloneAnimal(c, trainDog);

As the author of the example states:

This is a unsoundness resulting from the lack of explicit covariant / contravariant annotations in the type system.

We shouldn't do the same fault as TypeScript. There are better ways. For example, this is the equivalent Scala code (run online):

abstract class Animal()
case class Dog() extends Animal
case class Cat() extends Animal

object Variance extends App {

  def cloneAnimal(source: Animal, done: (Animal) => Unit): Unit = {
    done(source)
  }

  def trainDog(dog: Dog): Unit = {}

  val cat = Cat()

  // causes compile error:
  cloneAnimal(cat, trainDog)
}

which results in a compile error

Error:(16, 20) type mismatch;
found   : Dog => Unit
required: Animal => Unit
cloneAnimal(cat, trainDog)
^

since Scala defines function parameters as contravariant: Function1[-T1, +R]. We should do the same to avoid runtime errors like in the TypeScript example, which is nothing else than JavaScript with type annotations that can be written in rtype.

Mouvedia commented 8 years ago

Ill give you a template for your straw-man proposal because for pure javascript developers it's really hard to grasp.

  1. signature with + and -
  2. signature with in and out (Microsoft/TypeScript#1394)
  3. usage example (desired outcome)
  4. PROS of bivariant