TS/Flow don't quite lose types "whenever" partial application or currying is involved, it's a bit more subtle than that and in many cases it works fine. But especially when using generics with currying you often have to rewrite in more verbose ways (or structure the functions in a particular way) to make the types check through.
No, that is exactly correct. The brunt of the argument applies to most popular languages- Java, Python, Ruby, and what have you- although the specifics vary.
You can get exhaustiveness checking in some cases in TS by adding a default statement to a switch and assigning the value to type 'never'. This is a bit cumbersome, of course, and the fact that it's opt in partly defeats the purpose. You typically want to check exhaustivity to get more safety, but there the safety only comes if you add it in manually so everywhere you forget you lose safety.
Naming closures or functions absolutely is a good substitute for a large class of comments. When you write a comment as a function name, that comment gets maintained when the code changes. It also encourages modularizing your code- often when you write a comment it's a sign that your code is trying to operate conceptually on more than one level and it would be more understandable to separate those levels.
I wouldn't say comments are an antipattern but they are a code smell and should be used sparingly and only where the same explanation can't be given through function/variable naming or refactoring.
Part of the issue is that legally in the U.S. a) privacy violations are usually punishable by law only if a specific non-privacy harm comes of it and b) privacy is treated as an individual right and not a societal good. If a company gets hacked and loses your credit card and bank information afaik it's punishable only if someone actually fraudulently uses the information. It's up to individuals to jointly complain about specific damages to effect changes, and for any given individual there's little incentive to make your own life difficult for vague potential benefits. Also in most cases the individual harm is quite small, even if in aggregate or viewed as a societal harm there is huge damage.
Which specific ones, for example? "Every one" could cover a lot of ground and doesn't have much information content. It's doubtful you have experience in every one, and it would be useful to know which specific ones have been tried and seem better.
This is what makes me wonder, is there actually a steep age bias and drop-off of older developers or are we just living a demographics change? I'm guessing there are far more developers today than ten or twenty years ago. When those developers age, will we see a more natural age distribution?
One area in which Flow may be "technically" sound but it feels illogical is how in how it infers certain types. TypeScript requires that a variable has one type that doesn't change, but Flow will infer multiple types for a variable at different points in the code depending on how it is used. Also because Flow infers types based on how they are used, there are some interesting situations where you would expect the type checker to complain but it doesn't. E.g. if you have an object with a field that is never used, Flow won't complain about the field even if it is not defined in the type of the object. Overall I feel like TypeScript enforces logical, opinionated defaults, while Flow is happier to go with the illogical structure of your own usage (while enforcing opinionated defaults in other areas like null-checking).
I actually found the opposite was true in our project - TypeScript was easier to add into the code than Flow. The biggest reason for this was that Flow demands null/undefined checking and null was used extensively throughout this code base. With TypeScript, on the other hand, the changes to make it work initially amounted to sprinkling a few "any" notations and making some explicit object interfaces at various points.
I admit the claim is overly grandiose, especially in this particular case where there's still a decent gap between core.async and CSPM. If one generated Haskell code directly from CSPM it might be a stronger claim for that, but I haven't had a chance to try this yet. It would be interesting to see if it would be possible to develop tools to prove correctness of e.g. core.async programs.
Having a stream of every unique action and making sure everyone gets the stream of actions and applies them in order was another approach I've thought about, if that's what you mean here. I may have to try rewriting in this style. What I think is interesting about the algorithm I was shooting for is that you can miss events and just diff with the current state. But it may be that this is just an overly complex approach. If you have any other pointers or links as to how you might implement it in your described style I would be interested.
The go blocks in here are really ugly, but to be honest I just found it difficult to refactor in this particular case. The issues were a) I wanted all the events in a single event loop to make timing issues clear and to fit the model semantics better b) core.async go blocks, because they are macros, can't be refactored like functions (>! and such need to be in a go block) and c) the sync logic otherwise was easier to reason about with all of the logic in one place. One better way to factor this would be to have a declarative format for what each action performs, but it ended up being more difficult to follow the logic when I refactored it this way. Types would help, and I think in general there is unexploited potential for types and CSP and FRP approaches. But if you have suggestions for how to make this better I'm all ears.