5 ms·
The problem I find with static typing is that it so easily leads you over-specifying the requirements / constraints. In fact, it makes such a virtue out of that
by zmmmmm 5y ago
The problem I find with static typing is that it so easily leads you over-specifying the requirements / constraints. In fact, it makes such a virtue out of that over-specification that many people would consider it a best practice to do so.
For example, perhaps my `calculate_price` function only depends on 2 attributes of the order which has 65 attributes. Am I creating a 2-element data type for that function to process? no! I'm specifying that it processes an Order data type, with all its 65 elements. But implicitly then I'm saying the function has 65 input parameters of all these specific types and nobody can call it now without providing them all. What a pain! Huge amount of extra code, refactoring, unit testing, because of this.
So either you end up with a cambrian explosion of micro-types or you have these way overspecified interfaces everywhere.
Compare with dynamic languages (or structural typing, Go etc) that only care that things "quack like a duck". The calculate_price function doesn't care what object you give it, as long as it has the two attributes it needs. Now I can unit test `calculate_price` with a 2-element object rather than needlessly creating the 23 irrelevant required elements of a valid Order.
I think a lot could be solved with culture shift. Where data types are really known and locked in, use the crap out of them. As soon as things get ambiguous or flexible, go right ahead and specify that your function takes a Map<String,Object>. If a useful concrete interface emerges at some point factor it out then. The problem is that this is really frowned upon in a lot of places.
- mdoms 5y agoOr you could just take the two parameters you're actually using on your function. No new type, no need to pass your mega-object, just take two nice strongly typed arguments.
- brundolf 5y agoYou’re putting structural types in the same boat as dynamic types, which I don’t think is fair. Some of the most popular static type systems out there have structural typing, including Go (as you mentioned) and TypeScript. And that’s not even getting into languages that do extensive type-inference, including TypeScript Haskell and ReScript (which also saves you from locking into over-broad contracts).
- yen223 5y agoOne works with the type system they have, not the one they want. Out of the top 20 most popular languages according to Stack Overflow [0], TypeScript and Go are the only statically-typed languages that also have structural types support. [0] https://insights.stackoverflow.com/survey/2021#technology-most-popular-technologies https://insights.stackoverflow.com/survey/2021#technology-mo...
- deleted 5y ago[deleted]
- bqmjjx0kac 5y ago> As soon as things get ambiguous or flexible, go right ahead and specify that your function takes a Map<String,Object>. Dear god, please don't. Some of the worst spaghetti code I have disentangled used this pattern. Typos in the string literals used as keys, object type mismatches, etc. If you only want some of the fields from another struct, you have a few options * Define another struct `FooArgs`. This is easy, and I (respectfully) reject the claim that nobody does it. * Just define your function to take those two fields directly.
- deleted 5y ago[deleted]
- mountainriver 5y ago> The calculate_price function doesn't care what object you give it, as long as it has the two attributes it needs The issue with this is it makes it difficult to understand code. If anything works potentially anywhere then the flip side is you have no idea what works anywhere without running the code. Running code is slower iteration cycles than a type checker. Also you don’t actually know what it returned. So it was able to produce an output, was it what you expected? Or was it subtly different in ways that will break your code downstream. I work at a company with a large untyped code base and the product is constantly breaking in these ways.
- arc776 5y ago> Compare with dynamic languages (or structural typing, Go etc) that only care that things "quack like a duck". Go is a statically typed language. Unless you're referring to interfaces at run time? > I'm saying the function has 65 input parameters of all these specific types and nobody can call it now without providing them all. What a pain! Huge amount of extra code, refactoring, unit testing, because of this. I've seen this "cambrian explosion of micro-types" argument before on HN but I think it comes from a misunderstanding about what you actually do in a static language. No one's creating types for every combination of parameters. Either you'd pass the two arguments directly (`a, b: int` or whatnot), or you'd pass the Order type and just use the bits you need. If you have multiple Order types, you'd use generics or something like it to get duck typing. If you used a field that wasn't there, you'd get a compile error. The reality is the code would look pretty much the same in both static or dynamic languages.
- jim-jim-jim 5y agoIn addition to what others have said about just passing two parameters, there also row types, where the signature of `calculate_price` can be specified to accept any record that has the two required fields.
- mratsim 5y agoIsn't that duck type?
- jim-jim-jim 5y agoI don't write Python, but I think row level typing is stricter. Both the names and types of the record fields would have to satisfy the function signature, so the quacking is only honored on field names. Where dynamic languages will of course accept floats where ints are called for, etc, quacking all the way down. The point of my original comment was to suggest that some of the flexibility offered by duck typing can be achieved in FP, so they should seem similar. I would still just pass the fields as two parameters.
- Too 5y agoTypescript can do exactly what you ask for, “static duck typing”. Just define the input argument to be a interface with the 2 relevant attributes, any struct having at least these 2 attributes are now allowed, even if there is no explicit inheritance to it. This can be done inline in the function signature so doesn’t contribute to bloat. Python can do the same using what they call Protocol. Here protocols need to be defined upfront. This is usually called Structural typing, as opposed to nominal typing where classes inherit from a base.