4 ms·
> why would you try to do a mathematical operation between a customer's name and it's account balance that's a straw man to js typing, and never a problem in p
by maaaats 8y ago
> why would you try to do a mathematical operation between a customer's name and it's account balance
that's a straw man to js typing, and never a problem in practice. What's more often happening, is that you change the structure of some object in your store somewhere, that's passed around a lot. And you forget to update the usage one of those places and stuff break runtime.
- vidarh 8y agoMy experience in going from being very insistent on static typing and moving to Ruby (after lots of hesitation) is that you run into lots of type errors, chances are you also have uncaught logic errors in code your test suite isn't exercising. E.g. the above example would presumable be caught if you actually tested all the code acting on the account balance, even without a single test to explicitly test the types. That goes irrespective of if those type errors are caught at compile time or runtime - if those errors aren't caught by your test suite, odds are you have a problem that static typing will not fix but writing more tests will. In either case my response to type errors these days is to consider it a bug in the test coverage. (I'm sure some will argue that typing in languages like Haskell avoids this more than others, and that might be true, but languages like Haskell are too hard to work with for most people to ever get mainstream traction; I'd love to see more experimentation in making more advanced type systems more accessible, though)
- wsy 8y agoIt is true that all type errors can also be caught by additional tests. But is this the most efficient strategy? I would think that letting the compiler find certain classes of errors should be cheaper than writing and maintaining tests for these error classes.
- dahauns 8y agoIndeed, as these are error classes unit tests aren't even very good at. It can't be repeated enough: Types are universal quantifiers, tests are existential quantifiers, you'll realistically never get even close to the guarantees of a type system with tests alone. If your unit tests are on a level with your static type system, you have basically rebuilt the static type system in your unit tests. (And pitting unit tests against a static type system is a false dichotomy, it's good to have both.)
- vidarh 8y agoMy point was that you rarely need to write test to catch type errors. You write tests to determine if a unit of code works as expected. In doing so you tend to exercise the conditions that cause type errors as a side effect. Let's say foo() internally calls bar(). If I pass a given valid input to foo() it passes the wrong type to bar(). If I pass another valid input to foo() it passes the wrong value but of the right type to bar(). If you ensure full test coverage of foo() you will catch both. Type checking in your compiler will only cover the first case, so you still need the same test coverage anyway to have confidence in the code.
- glennpratt 8y agoFull test coverage of foo() is hard to prove. Have you exercised every argument possibility, every exception that could be thrown and every global/class/instance var reference? Working with Ruby most of my career, my experience is probably not. A good type system is much more thourough and let's your tests focus on behavior.
- vidarh 8y agoThat's what you have coverage checkers for. And you don't need full coverage. Aiming for full coverage is a folly - you aim to cover the API surfaces you're actually using. If you still get lots of runtime errors something is very wrong with how you test your code. > A good type system is much more thourough and let's your tests focus on behavior. The problem is no languages I'd be willing to use have a good type system that actually covers much.
- glennpratt 8y ago> The problem is no languages I'd be willing to use have a good type system that actually covers much. This is basically down to opinion, and I can't argue with it. I've collaborated on Ruby projects for about 10 years, I love the language, but my experience says a large code base, with test coverage, regularly breaks on things that most type systems wouldn't allow. Dependencies often cause subtle breaks like this, even in big, common ones. On top of that, this requires paranoia to avoid breaking callers. With a good type system, you can largely discard that paranoia.
- jerf 8y ago"What's more often happening, is that you change the structure of some object in your store somewhere, that's passed around a lot. And you forget to update the usage one of those places and stuff break runtime." This is the big reason I tend to even prototype a system with a statically typed language, if it's going to take more than about a week. Dynamically typed languages have the characteristic where they seize up after a week or so of development, it becomes impossible to fit the full graph of who is calling who in your head anymore, and from that point on, you tend very strongly to do defensive code changes rather than good ones, e.g. "this function used to take a string, but now it takes a dict with three parameters, but I'll still keep the code for if it gets passed a string because maybe something is still doing that". Then when the time finally comes to do a big refactor, you're often darned near rewriting from scratch. I've lost track of the number of times I've refactored something successfully in a static code base of several months age by just continually running the compiler until it's done complaining, and how often I start a refactoring that seems to be going really well until the compiler points me at some bit of code and I realize that what I'm doing right now is actually fundamentally flawed in some way I'd forgotten about. In a dynamic language you tend to just power through those and put in sub-optimal solutions. Plus, at least in my experience, if you do this consistently, it often is practical, feasible, and correct to just "ship the prototype", because whereas with dynamic code I would have a messy prototype with half the methods taking an unclear combination of values, with the static type-based process I've written something quite production-ready, with cleanly-defined interfaces.