14 ms·
> and then all the startups we saw write in their dynamic languages later ended up adding types, because maintainability Maybe because they weren't startups an
by tarsinge 8y ago
> and then all the startups we saw write in their dynamic languages later ended up adding types, because maintainability
Maybe because they weren't startups anymore?
Honestly I don't understand the deal with type errors in simple web apps : every input is a string which is parsed into the correct type. After this, with good naming and conventions operations should be obvious, e.g. why would you try to do a mathematical operation between a customer's name and it's account balance?
To me it looks like these days the hype is copying whatever big names are doing regarding maintainability without having nearly the same constraints (static typing, huge frameworks, ...).
- 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.
- 8y ago
- 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.
- Tehnix 8y ago> After this, with good naming and conventions operations should be obvious Why on earth rely on people for this when you have a machine available for you, that can automate all this? A good type system is invaluable for both on-boarding of new people, refactoring code, and maintaining a codebase. Why would you not want to make sure you could never call the wrong REST endpoint[0] for example? Etc, etc... [0] https://haskell-servant.github.io https://haskell-servant.github.io
- chriswarbo 8y ago> e.g. why would you try to do a mathematical operation between a customer's name and it's account balance? Types like `int`, `float` and `string` are rather impoverished. Much more common mistakes are: - One the numerical side, trying to perform arithmetic with different units of measure ( https://en.wikipedia.org/wiki/Mars_Climate_Orbiter https://en.wikipedia.org/wiki/Mars_Climate_Orbiter ) or with different representation sizes ( https://en.wikipedia.org/wiki/Cluster_(spacecraft)#Launch_failure https://en.wikipedia.org/wiki/Cluster_(spacecraft)#Launch_fa... ). These sorts of errors are trivial for machines to identify, if we let them (e.g. https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure https://docs.microsoft.com/en-us/dotnet/fsharp/language-refe... ) - On the textual side, type errors are widespread and cause a large proportion of security vulnerabilities ( https://www.owasp.org/index.php/Top_10_2007-Injection_Flaws https://www.owasp.org/index.php/Top_10_2007-Injection_Flaws ). Again, they're trivial for machines to identify, if we let them (e.g. http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-strings-problem.html http://blog.moertel.com/posts/2006-10-18-a-type-based-soluti... )