Hacker News new | ask | show | jobs
by wangchow 3612 days ago
Although, dynamic languages force extra incentive to unit-test the shit out of the codebase. Compilers certainly catch a lot of syntax mistakes and whatnot, but it also relaxes the requirement to add extra code coverage. The onus is more on the developer with dynamic typing but I'd take more-accurate code coverage over static types any day!

EDIT:

If you have static-typing and good unit-test coverage it's the best of both worlds I suppose. I tend to prefer duck-typing though which is sort of wedged in-between dynamic and static-typing in a sense. This however then becomes not a question of static vs. dynamic typing but of the language implementation of the type system.

In C++ for instance, the over-object-orientation is a pet peeve of mine when people define so many types and interfaces for this-and-that. I tend to prefer the "looseness" of template functions since you can pass whatever type in there so long as it contains the appropriate methods on the passed-in object. Such is static typing though so I'm digging myself into a hole from my original post :)

Now, a good static-analysis tool could catch issues on a dynamically-typed language in the same sense. Then I suppose the dynamic language becomes a pseudo-static language since a static-analysis algorithm is executed on the codebase. Since most build systems are set up to do: compile codebase; run static analysis to detect issues; run unit tests; run integration tests, it could theoretically be redundant step at compile-time doing static analysis when it's also done by an external tool. Just some stream-of-consciousness thoughts :)

3 comments

The only tests you have to discard when using a statically typed language are some of the tests validating your input data. I don't see how static typing leads to less test coverage...
These are a lot of tedious to write tests in a frontend codebase that mainly renders a lot of state into HTML.

Additionally, these are tests that you will have to tediously adjust every refactor since HTML frontends and it's data APIs behind it tend to change often over the lifecycle of a product.

From my experience, "only those tests" save you hours and hours of programming time.

> The only tests you have to discard (...) are some of the tests validating your input data.

That's not true. You can safely discard anything that tests something you've proven. A good type system doesn't only prove things for you - it also makes it easier to manually prove what the type system can't prove.

A good type system, yes. Something like TypeScript though? Only checks that variable types match. We're a far cry from ML/Elm/Scala/Haskell here.

So the only thing it helps is get rid of bad tests (eg: tests that check a function return any string...tests you shouldn't write even in a purely dynamic language).

> Something like TypeScript though? Only checks that variable types match.

TypeScript's type system is unsound, so you can't rely on the type checker alone to prove anything useful. However, manually proving things about TypeScript programs is still easier than doing so with JavaScript programs.

I don't believe it's practical to rely on type checkers to prove absolutely everything. There are mathematically proven upper bounds on how much you can automate reasoning. For instance, global type inference only works with first-order type languages. Higher-order anything flies out of the window, yet higher-order properties of programs need to be proven!

What we ought to do is find the optimal division of labor between automated and manual proving, always keeping in mind that the optimal case isn't being able to prove something. The optimal case is not having to prove it because it's obviously true. How do we design a programming language so that more interesting things are obviously true?

Sound type systems help you prove things. In other words, a type system is a tool that partially discharges part of the programmer's proof obligation. Of course, what you can't prove, you still need to test. This isn't news to anyone.

The problem is when the programmer doesn't know how much of his proof obligation is actually discharged by his use of the type system. (Hint: Not all of it!) And the solution is educating programmers, not replacing types with tests.

And that's why I prefer static typing. All those trivial unit tests get in the way.
You really shouldn't have a "trivial" test that a type system like TypeScript makes redundant, when doing pure JavaScript either.

If you have a function, eg: (a, b) => a + b The only thing TypeScript will help you enforce here is that a and b should be numbers, and the function should return a number.

Except, the test for this will be something such: "given 10 and 21, return 31". So you're testing the return type already. TypeScript will ensure that you never pass a string to a or b, for sure, but you should not have a test for that (unless you literred your code with type guards and wanted to test those. Don't do that).

Now, unless the function above is your final, public API (where TypeScript/Flow will have the biggest bang for the buck and have the most value add), you're probably calling that function somewhere. That somewhere will be tested too, and the full test harness will make sure strings never end up there.

You'll never actually need to write a test: "Make sure this is a string", and the only vulnerable area is the top level API, and that is a responsibility of the caller.