6 ms·
I'd rather have tests than types. Unless your type-system is sound; most of them are very, very far from it. You can specify the domain of values with types, b
by jeremiep 10y ago
I'd rather have tests than types. Unless your type-system is sound; most of them are very, very far from it.
You can specify the domain of values with types, but not their ranges. Side-effects fall through unaffected by types as well.
I've done plenty of refactorings in huge statically typed codebases; types are a very, very superficial help there. Everything compiles fine but now you're passing 20 to a function whose range is 1-10. Or you're now generating the wrong filenames.
To me the overhead of using types outweighs the advantages they bring to the table. If I can help it I'd even choose to have a spec I can enforce at runtime using custom predicates than some vague predefined types with weak semantics or unit tests I have to maintain manually.
- lloyd-christmas 10y ago> I'd rather have tests than types. They aren't mutually exclusive. I'd rather have both.
- jeremiep 10y agoOh I know, but my opinion and experience in half a dozen statically typed languages over a decade is that most type systems add much more overhead to development than agility. I do want types when building native software, because these sit directly on the CPU and have to match the hardware. Other than that I feel they at best give you the illusion of robustness - unless the type-system is actually sound but very, very few are.
- wvenable 10y agoType inference makes all the difference in my opinion. Once you have even simple (C# level) type inference than the overhead of static typing is so low there isn't much reason to use dynamic typing.
- jeremiep 10y agoYes I agree type inference is wonderful! But when the underlying type-system is just C# I feel like I'm given a half-assed solution. What good is having a int type if you can't limit its range? I'm not going to maintain BOTH static types and tests. The ROI is way too low on that and won't even come close to guarantee robustness. Assertions over composable predicates gives me much more out of the time invested to write it. They are right there in the code at runtime, not separate like unit tests or in a different phase like static types.
- wvenable 10y ago> What good is having a int type if you can't limit its range? Well then you don't have to test what happens when someone passes a string, an object, or a boolean. Most dynamic languages will silently convert many of these values into an int and produce incorrect results. > I'm not going to maintain BOTH static types and tests. You have to maintain documentation and you have to maintain tests and you have to maintain assertions for the implied types of your functions anyway so you might as well make them explicit in the code.
- jeremiep 10y ago> Well then you don't have to test what happens when someone passes a string, an object, or a boolean. That's useless, I still need to test the value's range which implicitly checks the type. > You have to maintain documentation and you have to maintain tests and you have to maintain assertions Not if I can generate most of it from the specification data.
- wvenable 10y ago> What good is having a int type if you can't limit its range? Most types in the program aren't ints anyway; they're interfaces. If I want to have a range-limited value, I could just create a new type for it.
- coldtea 10y ago>Oh I know, but my opinion and experience in half a dozen statically typed languages over a decade is that most type systems add much more overhead to development than agility. In what sense? With type inference you don't have to manually specify them. With a variant type, you don't have to confirm to a specific type, but can accept all, if you want it. And you still need to conform to an interface in a dynamic language, if your function is x.indexOf(x) you still need to make sure to use it on two strings, if it's a math function on some numbers (and depending on the function, on a range), etc (1). So you are not even spared that -- instead, you just lose the help from the compiler when it comes to it. (1) You could e.g. let a numeric type string autocoerce of course, but auto-coercion can also happen in static languages, is orthogonal to static vs dynamic typing, and is also generally to be avoided).
- lloyd-christmas 10y ago> most type systems add much more overhead to development than agility I think this is true to a certain extent, but with a language like JS, there is a lot more composition of generics than there is inheritance. I see: add5toStuff<T extends {stuff: number}>(item: T): T; drastically more than: class X {} class Y extends X {} class Z extends Y {} The latter is always a nightmare of fighting the compiler. The former is a breeze to deal with. Your type casting will be limited almost completely to IO.
- jeremiep 10y agoBoth styles still encourage a lot of mutability and complexity throughout the codebase. The vast majority of typed web codebases I've seen were exercises in Java Enterprise development of various degrees. Generics or not the time spent typing everything is not matched by the advantages of static typing. You'd get more robustness by managing complexity and state; I've spent far more time hunting down bugs that passed through the type-system and tests than fixing typos in dynamically typed languages.
- lloyd-christmas 10y ago> Both styles still encourage a lot of mutability and complexity throughout the codebase. > You'd get more robustness by managing complexity and state; The top function has a return value of T. That's not encouraging mutability. It's only mutable because JS pass by reference, which is irrelevant to static/dynamic. If you use the return value instead of the passed value, it's "effectively" immutable and is a great way of managing state.
- copperx 10y ago> Or you're now generating the wrong filenames. Having a no-overhead Filename type would make this impossible.
- jeremiep 10y agoHow so? That type would be a glorified string at best. Types can't check the ranges of their values in most languages. And definitely can't do so at runtime.
- rpeden 10y agoI can see it working in a statically types language with macros - maybe Scala or Template Haskell? I'm not 100% sure if their metaprogramming is capable of this. Ideally, you could define a type like FileNameString to be a string that has to match a certain regex. Though if you wanted to use the new type throughout your program, I suppose you'd need a String -> FileNameString function somewhere to handle instance of file names generated at runtime. I agree that the type systems in most mainstream languages fall somewhere short of awesome. I was putting together a small web app in Elm last week, and it was nice to work with a type system that felt like it was helping me design and write better code. That, plus it has the most helpful errors message I've ever seen from a compiler.
- Too 10y agoActually it's quite common. For example in .net you have a Uri class and a DirectoryInfo class which are basically just wrappers on top of strings with some validation and helper functions.
- wvenable 10y agoIf I do heavy enough refactoring where even the tests break then static typing is wonderful. You literally know exactly what needs to be fixed because it won't compile (and usually you know well in advance of that in the IDE). Heck then I can even fix the statically typed tests that might be broken.
- coldtea 10y ago>I'd rather have tests than types. Unless your type-system is sound; most of them are very, very far from it. As I wrote, static type systems are a superset of dynamic type systems. So they can have both. Besides, static types are, among other things, automated tests for the trivial stuff -- which the computer automatically tests/ensures them instead of a human writing them as busywork (and potentially getting them wrong). The "sound" type system requirement doesn't make sense either. A non sound type system can still catch the majority of parameter/variable misuses automatically. With dynamic type systems you don't even have that, so essentially what you wrote means "I want it all or nothing". Cool when it comes to personal ambition, doesn't make sense when what you get still protects you from all kinds of errors and helps you refactor and self-document your code. >I've done plenty of refactorings in huge statically typed codebases; types are a very, very superficial help there. Everything compiles fine but now you're passing 20 to a function whose range is 1-10. Or you're now generating the wrong filenames. That would matter if static types somehow prevented unit/functional testing, which they do not. And, depending on the language, the help of static types can be far from superficial. Even in Ada, back in the 80s, you could define the 1-10 range as a constrain on the type/input parameter. Yeah, they don't catch all problems -- but that's good too, else we would not have jobs.
- jeremiep 10y ago> but that's good too, else we would not have jobs. Given how mediocre the average software out there is, I'd much much rather have an industry focus on actual engineering. Its a lot more profitable to find new problems to solve rather than continuously fix your own mess. I used to write very well documented statically typed code, and then watching people without domain knowledge butcher the hell out of it after I left. At the end of the day knowing what you're doing is priceless. Just like having guard rails is no excuse to not learn how to drive. Alls I'm saying is that types are very overrated when it comes to actual robustness and correctness. You can get it without types and you can miss it with types.
- Too 10y agoOverhead? What overhead? Overhead is having to keep the implicit type in my brain instead of having it written on the screen right in front of me.