18 ms·
A mix of Rich Hickey talks and my own experiences. Possibly just Rich Hickey. a) You're going to write unit tests anyway. Type errors are not especially likely
by closeparen 6y ago
A mix of Rich Hickey talks and my own experiences. Possibly just Rich Hickey.
a) You're going to write unit tests anyway. Type errors are not especially likely to slip through good testing, nor are they the most interesting kinds of bugs that can slip through good testing.
b) Null is a value of the wrong type, and most type systems let that one through.
c) Values have a habit of coming from outside the boundaries of the type system. Sockets, files, etc. You will always have to deal with (or reject) arbitrarily wacky inputs at runtime.
c) Static typing leads programmers to overspecify data and make programs unnecessarily brittle. Many struct/record types could be replaced with maps + runtime checking that the appropriate keys are present, while letting other keys pass through. Then our programs would not so often require modification to support new uses. (TBH I think Go's type system, of all things, takes a decent step toward this one with its implicitly satisfied interfaces).
- aszen 6y agoI think many of these points are valid for a type system like Java's but they hold less ground for other languages a. Yes tests are still needed but you need far less of them thanks to type you can focus testing on the critical logic instead of validating input and output types. b. Solved issue in modern pl, even php considers null a value of separate type. c. This is a good point, but with values coming from outside the system, I'm forced to do run time checking because of types which makes the whole program more less error prone. d. This is a very valid point for most mainstream typed programming languages, row polymorphism is one technique which helps here. Every function only specifies the key's it needs to work so it can receive arbitrary records. I believe this is also possible in python by typing out dict keys and values.
- closeparen 6y agoYes, I am looking forward to better type systems (and community habits/norms around those type systems) solving most of these problems. In particular, I would like to see the community gain enough faith in the safety guarantees of more advance type systems to back off of blind line coverage mandates. But today we have Go and Java's type systems, and the same coverage mandates as Python and Node. In particular I would like to see the compiler enforce that you either return a legitimate value or raise an exception, and that the caller does not go down a path that calls for a value if an exception was raised. I hate that a reference can get 10 miles away before you discover there's no data there, and it being wrapped in Option or ? or a technically-not-null zero value doesn't mitigate that.
- aszen 6y agoOn your point about compiler enforcing legitimate values, the way I see it is that if u don't get the right values from the outside world you should immediately exit the program with a nice error message. As the data moves further down into your core functions it should become more well defined and highly structured. Basically you should parse messy data into the types you need and then you don't need to validate the data in each of your functions. How to enforce this is a tricky problem for the compiler, maybe it's architectural pattern that can be enforced by libraries and frameworks.
- rualca 6y ago> a) You're going to write unit tests anyway. I fail to see the point of this remark. At best, you're arguing in favour of reinventing the wheel. With. Every. Single. Call. At worse, you're somehow arguing in favour of being far less productive by having to fill in boilerplate code to run your own hand-rolled and error prone and hard to maintain typing checks. Where's the value in this? > b) Null is a value of the wrong type, and most type systems let that one through. I really see no point in this assertion. So what if "most type systems" handle a specific type in a way you don't personally like? Are you writing your software based on Nond alone? Just specify your type and let the static type checker flag an error if it catches the possibility of a type seeping through an interface. Heck, Python's type hints system already support None, Optional, and even union types. You can also double-check with unit tests and runtime type checks. The TypeScript community considers this a solved problem. Why should this be of any concern to the Python community? > c) Values have a habit of coming from outside the boundaries of the type system. Sockets, files, etc. You will always have to deal with (or reject) arbitrarily wacky inputs at runtime. I fail to see the relevance of this point. With static type checks you specify the interface you're expected to support. You write and test your code based on that interface, and if the language enforces it then everyone, including your dependencies, also declare a contract that they comply with. How is that a problem? At all? > d) Static typing leads programmers to overspecify data and make programs unnecessarily brittle. This assertion is quite wrong. At best, you're complaining that there might be a programmer somewhere that over specified an interface. How is this a problem? At all? Meanwhile, let's look at the real world. Even if you intentionally turn a blind eye to what's already offered by Python's type hints, just look at how TypeSript handles interfaces. With it, you can quite literally specify that a function's input/output parameter is just an object that might have a key of acertain type. Then, to move the dial away from loose and into rigour, you can use type guards to infer more specific types. Why is this supposed to be a problem ?
- closeparen 6y agoIt's very clear that you have a rock-solid and passionately emotional commitment on this issue already. I'm sorry I mistook your question for good-faith interest in tradeoffs. I'm not going to engage deeply beyond this. I work in statically typed languages for a living. On the whole I think this is a sensible choice for my employer. Sometimes I don't like it. Sometimes when I have a choice (personal projects, or ancillary scripts/utilities) I'll reach for untyped Python. These are the reasons. a) The type checker is a lifeline that will save you from one kind of error in untested code. But there are lots of ways to screw up untested code. You need testing anyway. And what will be caught statically by the type checker, will be caught at runtime during an adequate test suite. b) Nullability invalidates the guarantee that a type system is supposed to provide: that values are the right type. The boilerplate, error prone check is necessary anyway to deal with the null. Yes, there are better type systems that don't have this problem. But static typing as actually practiced today (in general, I'm not talking about Python) has this problem very often. c) This is true only if you're a library. Your type system can't statically guarantee anything about the bytes that will arrive on a socket, which is your actual interface when you're a network service. Parsing and validation must be done at runtime. d) Over-specification of data is endemic to the culture of static typing. In the large, people think they need to map any values they receive to an internally defined struct or class, dropping any parts of the record they don't understand. Not doing this is seen as incorrect, irresponsible, or as you put it, less rigorous. But doing it leads to a lot of coding time wasted on mapping between representations and threading new fields through all the places a record is handled. Some static type systems offer facilities to help alleviate this problem. I'd argue that to the extent you're using those facilities, you're walking back down the spectrum towards dynamic typing.