...at least that's when i'm planning to finally learn frontend development
Try again.
All languages have type systems. Including ES5, ES6 and CoffeeScript. They might be weak and dynamic but they are type systems none the less.
> I think his point was that the type theorists weren't fans of JS
I'm fairly sure that's the case (no data though)
> or he's making a different point.
My point was (a bit toungue in cheek) that seeing how many alternatives that keep popping up for avoiding JS (the language), it seems that a lot of people who like programming languages to the point where they can create one, do not like JS.
shrug
Is it really so hard to believe? Imagine if the browser's scripting language didn't have closures or prototypical inheritance. It was possible.
JS was a pretty good compromise between power and simplicity.
fan of JS as a whole package (Language, ecosystem, ...) or JS only as a language? The whole package is very attractive, and I can see how people accept ES5 (the language) for the opportunity to work with JS the ecosystem.
JS the language I think has some cool features and with ES6 it's even an acceptable language to work with, but I just fail to come to terms with some of the smaller warts. The feeling I'm looking for in a language is "this is carefully designed to be consistent, simple and free of idiosyncraces and suprises". With equality, scoping, coercions etc in ES5 that realy is NOT the feeling. ES6 is so much better, but once you pick an ES5 alternative there are so many other choices.
> JS was a pretty good compromise between power and simplicity.
I really don't get why people think JS is "simple" though. It's fantastically complicated. Mostly accidentally though., because of the little warts in scoping/equality/coercion etc. Again, ES6 is a lot better - but still very very not simple compared to e.g. Java.
That's why it seems fair to say that JS is much simpler than Java.
https://www.ecma-international.org/publications/files/ECMA-S...
I understand; I was speaking colloquially. No need to be pedantic.
> My point was (a bit toungue in cheek) that seeing how many alternatives that keep popping up for avoiding JS (the language), it seems that a lot of people who like programming languages to the point where they can create one, do not like JS.
Your original post focused on type systems specifically. It seemed something like "type theorists dislike JS, as evidenced by <languages>". This is different than "programmers generally dislike JS, as evidenced by <languages>"; however, to focus on your latter claim, I don't think your claim follows the evidence--the most we can say is that many programmers dislike JS; however, I don't think this is a particularly useful observation, since every domain has many candidate languages, and relatively few domains are trending toward consensus. It seems like the most meaningful conclusion is "programmers have diverse tastes, projects have diverse priorities, and many of those tastes/priorities are mutually exclusive (there are no languages that are good for learning curve and maximizing performance, for example). This conclusion is not necessarily surprising, but I think it's the most interesting claim we can derive from the stated evidence.
I remember reporting this bug years ago, and they said it was "by design, since JS programmers prefer to think of functions as covariant in their input". Well, I prefer to think of 2+2 as equalling 5.
TS tends to make pragmatic tradeoffs between sound typing, and the way JS developers tend to architect code. I'm glad they do.
Contravariant: A variable needs to have a function that accepts Animals. You can't put a function that accepts only Cats, or it will crash on other kinds of animal. But you can put a function that accepts all LivingThings.
So when something is covariant you can use a more specific type, and when it's contravariant you can use a more generic type.
When it comes to function parameters, typescript lets you use either. You can replace any type with any related type, even if you're going in the wrong direction. They did this to make certain use cases simpler, at the cost of weaker typing.
In usual Javascript patterns, this intuition works, but it's not sound, since arrays are mutable; the function could write to the array, appending a Dog or a Potoo or a Jellyfish- valid for an Animal[] argument, but not sound for a Cat[].
In practice, in most JS code I've seen, arrays are constructed once and then are passed around as immutable collections, so Typescript's unsoundness saves a lot more casting than it introduces errors.
At one point long ago I did some experiments with this, and found that the most of the unique method signatures necessary to represent the data structures we are familiar with are concentrated in the mutators.
That is, the interface differences between read only data structures are pretty small. So you don’t double the surface area by splitting read from write. It’s more like 25%, and this might be partially offset by simplifications in code that has to scan multiple types of collections.
The example seems like a valid case. The type of event is expressed in a separate parameter, so being strict here requires pointless casting and doesn't actually make things safer.
Whether you think this type weakness is worth the downsides is up to you.
Can you explain the naming? What sort of variance is the second case contra?
Now, say you have a function that takes a Cat as an argument and returns a Cat. What types can you use instead of the Cats and still remain type safe? Well, you could pass in a Tabby or return a Tabby and everything would be fine. This is a subtype rule that the compiler can check.
What about something a little trickier? Say you have a map function that maps from a list of Cats to another list of Cats. The map function takes two arguments: a list of Cats and an arbitrary function that takes a Cat and returns a Cat. For each item in the input list, the function is called on it and the returned Cat is added to the output list.
Now, can we replace the Cat to Cat input function with a function that has different types and still have the types make sense?
Let's try a function that takes a Tabby as an argument and returns a Cat (usually denoted Tabby->Cat). This won't work as we could have something that isn't a Tabby in the input list. What about a function Animal->Cat? This would work OK as every Cat in the input list is also an Animal.
Similarly, what if we try a Cat->Tabby function? This would work too as a Tabby is always a Cat. What about Cat->Animal? No, as it might produce a Dog and we only want Cats.
Notice the difference between the arguments and return types? For arguments we can replace a Cat with an Animal but, for returns, we can only go the other way. We say that we are contravariant in the argument type but covariant in the return type.
There are other forms. We say we are invariant if we can't change the type from the original stated type. We say we are bivariant if we can replace Cat with either Animal or Tabby.
So, what did Typescript do wrong? As I understand it, Typescript was (is?) bivariant in both argument and return types. This means that the type system would, say, accept a Tabby->Cat function for a Cat->Cat function argument and then fail at runtime.
Is this a heinous crime? A matter of opinion I guess. It's definitely wrong from a type system perspective but plenty of type systems let this sort of thing pass and are successful.
BTW this subtyping complexity isn't just for function arguments. It's also an issue with collection types e.g. what can yuo replace a list of Cats with? But this comment is way too long already.