News for hackers. Stuff that matters.
Re:TypeScript support in Electron by bad_user on Saturday June 03, 2017 @07:00AM (#14475818)
Reading from the comments here, I believe that people don't realize how bad the unsoundness is in Typescript:

    class Dog { name: String }
    class Engine { name: String }

    function start(ref: Engine) {
      if (!(ref instanceof Engine)) 
        throw Error("oops")
    }

    // Typescript does not complain
    start(new Dog())
This sample is due to Typescript doing "structural typing". According to its rules, if Engine and Dog both have the "name" property, then they must have the same behaviour as well. This is also inconsistent with the behaviour of classes in Javascript (e.g. see the behaviour of `instanceof`).

The biggest problem is that generics are what they call "bivariant", which is lingo for "completely fucked up". Here's a classic gotcha that caught people by surprise with Java's array since forever:

    class Animal { isAnimal: Boolean = true }
    class Dog extends Animal { isDog: Boolean = true}
    class Cat extends Animal { isCat: Boolean = true }

    const dogs: Dog[] = [ new Dog() ]
    const animals: Animal[] = dogs
    animals.push(new Cat)

    for (const dog of dogs) console.log(dog.isDog)
    //=> true
    //=> undefined
Well, it's unfair to pick on this, since they give a similar example in their own documentation, right? But this extends to inheritance as well, because input parameters in functions are not contravariant in Typescript:

    abstract class FlatMap<A> {
      abstract flatMap<B>(f: (a:A) => FlatMap<B>): FlatMap<B>
    }

    class Box<A> extends FlatMap<A> {
      flatMap<B>(f: (a: A) => Box<B>): Box<B> {
        throw new Error("Not implemented!")
      }
    }
It should be obvious to everybody why this is wrong:

    class AnotherBox<A> extends FlatMap<A> { ... }

    const box: FlatMap<number> = new Box<number>()
    box.flatMap(x => new AnotherBox<number>())
In case you're wondering, that interface is the beginning of the Monad pattern and the problem here is that monads are incompatible with each other. So in order to compose instances together, you do rely on the compiler to protect you. Think Promises being combined with Arrays, both of which are monadic types. Not going to work, is it?

In less expressive static language lacking higher kinded types, which you need to express such interfaces, there's a current trick that people do to work around it: https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-ki... ; This has been used in Elm and it's being used in Kotlin as well, see for example: https://github.com/FineCinnamon/Katz

But Typescript is on a whole new level of wrong, because you can't trust the compiler for correctness, so you can't trust it for protection, at all. You see, this is not pie in the sky academics, but actual code that can happen in your app, mistakes that the compiler should have prevented you from making. In the above case Typescript really is just documentation and just like documentation in many cases, it can be wrong documentation. To make this even more frustrating, Microsoft's other language, C#, does not have the problems that I enumerated.

And I know what people say - oh, this is still useful. Well, guess what, writing JSDoc + having Google Closure to validate is actually more useful, while not being non-standard ;-)

Re:TypeScript support in Electron by bcherny on Saturday June 03, 2017 @07:16AM (#14475866)
You're treating this specific case as a fundamental issue, when it's a specific and superficial one that can be reasonably addressed in a future TS release:

See for example:

- Nominal types proposal https://github.com/Microsoft/TypeScript/issues/202

- Co/contravariance annotations proposal https://github.com/Microsoft/TypeScript/issues/10717

Re:TypeScript support in Electron by bad_user on Saturday June 03, 2017 @07:26AM (#14475894)
These choices are fundamental to the language as it was designed. There's nothing more fundamental than how variance works.

Want to bet that in 2 years from now we are still going to talk about the same language with the same issues, and that those two proposals are going to be rejected?

Re:TypeScript support in Electron by bcherny on Saturday June 03, 2017 @07:31AM (#14475908)
I'm not sure I understand why you think that. TypeScript explicitly prefers real world usability to theoretical soundness, so if the community is vocal about the need for these features, I don't see why TS would turn them down.
Re:TypeScript support in Electron by bad_user on Saturday June 03, 2017 @07:36AM (#14475938)
> real world usability to theoretical soundness

The soundness we are talking about in this case isn't theoretical at all and in fact such an argument is anti-intellectual. This is anti-intellectualism.

As for the "community", we are talking about one where the majority has never worked in sane static languages.

Re:TypeScript support in Electron by bcherny on Saturday June 03, 2017 @07:46AM (#14475968)
You are misunderstanding what I said.

Either one of the 2 issues I linked would fix the specific problems you outlined. You don't need a globally sound type system, H-M inference, or anything like that to fix those specific problems; local inference and opt-in nominal typing would work just as well.

Having used TS daily for a few years, I can vouch that your cases are pathological, and don't come up in practice often, if at all.

Re:TypeScript support in Electron by shados on Saturday June 03, 2017 @09:53AM (#14476378)
Even if they enable it, it might be through a switch like strict nulls (which was a huge mistake to implement so late).

That's not great.

Re:TypeScript support in Electron by bcherny on Saturday June 03, 2017 @11:57AM (#14476954)
I agree they waited too long for strict nulls!

However, both features I linked at currently proposed seem to be backwards compatible, so hopefully no switch.

Re:TypeScript support in Electron by shados on Saturday June 03, 2017 @01:22PM (#14477363)
For sure that's great. The issue are still:

- it's not there today - it still has to be bolted on (eg: adding new keywords, as opposed to, let say, Flow automatically doing nominal typing for Classes, which was the right move). - The ecosystem did not get to take advantage of it for years, so existing types, libraries, etc, are not written that way. That's a lot of tech debt.

That's why new languages keep popping up all the time. The later you bring in critical features, the more bloated you force the system to be.

I will admit TypeScript has been doing a decent job at containing the bloat (most of the crap features were actually what they implemented super early on, like the namespaces, enums, etc...the new stuff is really cool). But I think having proper competition enabled that: see the original strict null issue, where people were all but saying it was not possible/practical. Good thing we had Flow as a counterargument. Now with Flow dying a slow death, we'll have less fragmentation (great!), but less competition (possibly stagnating language. Boo!)

Re:TypeScript support in Electron by bcherny on Saturday June 03, 2017 @02:58PM (#14477866)
I agree on both points. An interesting facet of your 1st point is Stroustrup's Rule [0], which gives more context for an explicit `nominal` keyword.

[0] https://thefeedbackloop.xyz/stroustrups-rule-and-layering-ov...

Re:TypeScript support in Electron by shados on Saturday June 03, 2017 @03:14PM (#14477942)
Yeah I can totally see that. I liked the classes are nominal, plain objects are structural because its close to what people expect without even knowing the difference.

But yes, TypeScript was very much designed for a target audience (all of the C#/Java-style class features and namespace stuff early on, which less and less people want as time go and people learn about better ways of doing things).

It seems inevitable to me that eventually (might take decades), Haskell-level type systems will be the norm and people will learn them in highschool. The world is just not ready (and neither am I)

Re:TypeScript support in Electron by bcherny on Sunday June 04, 2017 @05:26AM (#14480517)
> It seems inevitable to me that eventually (might take decades), Haskell-level type systems will be the norm

That would be exciting, but I can't help but wonder if FP is just a matter of taste. We had Smalltalk and ML in the 70s, C++ and Erlang in the 80s, Java and Haskell in the 90s, and now it feels like all the best languages at least nod to a multi-paradigm approach: Scala, Swift, Python, JavaScript, C#, Rust, etc. The right tool for the right job, you know?

> and people will learn them in highschool

I'm actually working on a book along these lines! Look for it on HN in a few months :)