4 ms·
This is my question as well. I think about types even when I don't explicitly declare them. "Function x will return a list of a" "Function y will return an in
by geowwy 8y ago
This is my question as well. I think about types even when I don't explicitly declare them.
"Function x will return a list of a"
"Function y will return an instance of b or null"
"Function z will return an instance of c or throw an error"
How much time am I losing by putting that information in the function declaration? I doubt it's more than the time I lose when a function returns or throws something it wasn't supposed to.
- Guthur 8y agoYou do this because that's how you have trained yourself to think about code. It's a little self centered too assume this for everyone else.
- int_19h 8y agoThinking about data contracts for inputs and outputs is pretty basic stuff. If you don't do that, how do you know what your code actually does?
- carlmr 8y agoThey don't, but they're fast and fail often.
- regularfry 8y agoThere's a gap between things it might make sense to consider as data contracts, and things that can be expressed in practical type systems in common use. One example: a function which, when given a single element, returns a single transform of that element. When passed a list of elements, returns a map of that transform over the list. You can argue as to whether that's a good idea or not, but I've seen JS functions that make sense in context which do that. This might just be my lack of type system expressivity knowledge, but how would one annotate the type of that function? I get that you could use a union type on the param and the return value, but not how you link the two.
- hombre_fatal 8y ago> how would one annotate the type of that function Some languages support function overloads like Swift and Kotlin. fn foo(input: A, xform: A -> B) -> B fn foo(input: [A], xform: A -> B) -> [B] Hmm, maybe we can generalize that into a Functor.
- int_19h 8y agoYes, this is very common in JS, and somewhat common in other popular dynamic languages. In TypeScript, for example, you'd implement this by defining several overloaded signatures. Note that this isn't C++ or Java, so you still have a single function implementing all of them - the various overloads just specify what happens depending on the arguments you pass. https://www.typescriptlang.org/docs/handbook/functions.html#overloads https://www.typescriptlang.org/docs/handbook/functions.html#... This is a limited approach, because the overloads aren't a part of a function type - i.e. you can't have an anonymous function value that is overload-typed, it must be a named function. In principle, a similar mechanism could be used for types as well, it just doesn't usually come up in that context (e.g. callbacks typically don't return different things), which is probably why they didn't do it.
- cjs_2 8y agoHow could one think about functions differently than about what their input and output is?
- zimablue 8y agoYour statement is just a tiny bit too general and that's where you're missing. "What about their input and output is" => "what type their input/output is" The next question is what does the type of the input/output actually tell you about the input/output? In the most popular languages (using interfaces), it basically tells you that the input/output might have a, b and c set (or they might be null), and it could also have anything else set. So the actual information you have is that you might or might not have (a,b,c) and also might or might not have (anything). Not as foolproof as you think. The natural objection is that aha! I defined this class to require (a,b,c) in the constructor and do a nullity check, so I know much more than this! But this is back to having "types in your head", that constructor signature and nullity check isn't compiler enforced (as in if you change it, nothing will fail in the typesystem at the point of the function that we're checking, as long as those fields remain on the class). So the useful part of the static typing is actually living in your head either way.
- crumpets 8y agoRight, you’re treating the code as statically typed even when it’s not. In that case you never gain the advantage of dynamic languages. Thinking so strictly about what types a function will receive rules out making use of things like decorators in python that operate on function arguments regardless of type. Or generic validation utils that take many types and return the passed in type after performing internal validation logic relevant to the type.
- DCoder 8y ago"Takes many types" ≠ "cannot be typed". TypeScript supports decorators, union types, and `any`/`unknown` types. Those generic use cases are good examples of flexible types, but I have a hard time seeing how * "I don't know whether the `getMyReplies()` function returns a list of items, an iterator, a non-rewindable generator whose results I need to cache, or a closure with/without memoization" and * "I don't know whether the singular Reply entity has a field called pid, parent_id, parentId, ParentID, ParentGUID, or parent_message_identifier" are advantageous to rendering a list of replies.
- z3t4 8y agoFor code written in JavaScript you check the source code to see what arguments it takes and what it returns. If it's not written in JavaScript, for example a Browser API's or NodeJS built in module, you read the documentation and use console.log's. Then you rely of good naming, for example (nrA, nrB) => sum vs (a:Number, b:Number) => c:Number where the one without static types is more clear of what the function does and what it returns.
- untog 8y agoHaving to search through source for the argument types of a function is usually an example given in favour of strong typing, not against it.
- z3t4 8y agoThere are not many reasons to read the code of your dependencies, you will learn a lot doing so. One issue when you work with the compiled code is that the type annotations have been removed, and that type annotations leads to more terse code as it would otherwise become too verbose eg. number:number tends to become n:number and when the type is removed it just becomes n, so you kinda become dependent of your tooling and can't easily just stop using it in favor of something better.