3 ms·
type inference is that it makes reading code harder I find the opposite to be the case. My syntax isn't polluted with all manner of superfluous syntactic n
by YorkshireSeason 8y ago
type inference is that it
makes reading code harder
I find the opposite to be the case. My syntax isn't polluted with all manner of superfluous syntactic noise like
A a = new A
How is that more readable than something like the following?
a = new A
There are edge cases, but type-inferred languages do allow you to add type annotations.
Especially wrt generics
Why is this a problem? The very essence of parametric polymorphism is that the do "the same thing" at all types. This was first shown with Reynolds' famous Abstraction Theorem [1], which has in the mean time, been generalised in many ways.
[1] J. C. Reynolds, Types, abstraction, and parametric polymorphism.
- Klathmon 8y agoSure, in that simple case explicit types aren't helping, but take a look at this simple function (it's plain javascript): export const mergeItems = (keyExtractor, oldItems, newItems) => uniqBy(oldItems.concat(newItems), keyExtractor) What is keyExtractor? What are old and new items? You can probably guess that oldItems and newItems are an array of something, and you can probably infer from names and stuff that keyExtractor should extract a key from the items somehow, but aside from that you don't have much. If you didn't know what the lodash function "uniqBy" does, you wouldn't know how to use this without research. Contrast that with this below (Javascript with Flow type annotations): export const mergeItems = <Item> ( keyExtractor: (value: Item) => string, oldItems: Array<Item>, newItems: Array<Item>, ): Array<Item> => uniqBy(oldItems.concat(newItems), keyExtractor) With types it is a lot more explicit. Key extractor is given the item in the array, and should return a string key. Now you don't need to know or care about how "uniqBy" works, or the exact details of how you should or shouldn't use it, and if you try to pass 2 arrays with different items, it will yell at you because that's not right, something that type inference can't determine (at least not with Flow's typesystem)
- tetrep 8y agoIf types are specified in function definitions, then you'll find them in the docs, which you need to be reading in order to properly use a function in the first place. Finding out type definitions is made massively easier with an IDE, but even without one there's an extremely high chance any library you're using is going to at least have autogenerated docs sitting on disk somewhere or mirrored on a crappy website. Maybe you need to clone their repo and build the docs yourself, but even that's pretty unlikely as most language ecosystems have a package manager + docs website or man pages. I don't really develop anything without at least a third of my screen real estate dedicated to documentation and I don't see "RTFM" as a meaningful or undesirable barrier to programming correctly. > Now you don't need to know or care about how "uniqBy" works, or the exact details of how you should or shouldn't use it... I don't follow you. What if "uniqBy" only works properly on sorted lists? You'd never know that based on the type (unless you've got dependent types) and if you're not reading docs on how the function works (the types check/it compiles!) you're going to be in a world of hurt at runtime. Intuitive programming may be easier but it's a heck of a lot more dangerous unless your compiler is intuitive too (i.e. makes the same intuitive assumptions that you do). > ... and if you try to pass 2 arrays with different items, it will yell at you because that's not right, something that type inference can't determine (at least not with Flow's typesystem) That's entirely Flow's fault. There's no reason a "proper" type system couldn't deduce that the same type would be needed for both arrays, the `oldItems.concat()` call should have a type definition something like (functional for brevity): concat(Array<T>, Array<T>). Nothing ambiguous about T being the same type.
- Klathmon 8y agoI'm in complete agreement that RTFM is something that you'll have to do, but us humans aren't good at being constantly vigilant. Types are an additional layer on top, that can help provide context and information which is often difficult to get across in "plain english" in documentation, and they have the added benefit of being machine readable and verifiable so that a mistake that us humans make or an instance where we forget an edge case is more likely to be caught. Before I used Flow, the documentation above a function like that would probably look something like this: /** * [normal docs here about what it does and where it's used] * * keyExtractor is a function that will be called for each element in both the * new and old array, and it should return a string key that will uniquely * identify the element so that the combined array can be de-duplicated. */ It's not impossible to write out, and to be honest it probably wouldn't hurt to still add some of that into the function even if it's typed, but it's a lot more writing to get the point across, and it can be ambiguous, can easily become "desynced" with the code itself, and won't show up in IDE tooling when going to use the function (or if it does, it won't be easily parsable like a small type would be). I'm not saying types let you use a function without knowing anything about what it does or how it's written, but that it makes it easier to just remember the basic ideas and it lets the type system catch some mistakes or problems, while also providing some additional "documentation". >That's entirely Flow's fault. Don't worry, I was wrong anyway! Even without typedefs it will error if you pass in arrays of 2 different types. But I believe some type systems will try to infer that the function is generic and can take either, and without explicitly defining the type constraints, will over-genericise (is that a word?) the function to allow it to allow more than the user expected it to. A good type system in programming is both an additional safety net as well as a guiding hand. It doesn't replace documentation, but augments it, and makes it better, and can bail you out if you get it wrong (sometimes). I once heard types referred to as a "checksum" for your function. It can feel like you are just re-stating the obvious, but the compiler will verify that the implementation and the types are in agreement, and that helps prevent some kinds of bugs.
- YorkshireSeason 8y agolook at this simple function As I said, type-inferred languages do allow you to add type annotations when they are helpful. Note that your example has two arguments of the same type Array<Item>. In this case your even explicit typing doesn't prevent mixing up oldItems and newItems. In this case you want named parameters ...