News for hackers. Stuff that matters.
Re:Deno will stop using TypeScript by stickfigure on Sunday June 21, 2020 @01:01PM (#23593308)
Let's say you have a method that takes a thing:

    function doSomething(thing) { ... }
How many different possible representations of a 'thing' do you have? A json object? A class object with behaviors? A database id? Some sort of natural key like a SKU? A URL? Is it a metric or imperial thing?

You need integration-level tests around every method call to ensure that caller and callee agree what kind of 'thing' representation to use. Type systems can eliminate this class of bug entirely.

Re:Deno will stop using TypeScript by pmontra on Sunday June 21, 2020 @01:23PM (#23593497)
I never throw inputs of random types to my functions. Actually that could be a good idea, some fuzzying at the public API level could catch some bugs and attacks. But not at unit test level. If a function expects an integer argument I test it with integer values. That in Node, Ruby, Python and Elixir. I never saw anybody doing something different. Well, if we wanted to enforce types we could use any static typed language out there.
Re:Deno will stop using TypeScript by Yoric on Sunday June 21, 2020 @01:45PM (#23593703)
Let me offer you an example that comes from the Python world (I see these errors every few weeks and every single one of them means that some dependency of my code has somehow broken).

1. The library makes an assumption on a type (in the case of Python, that's typically "there's only one type of strings", "there's only one type of streams", sometimes "there's only one type of numbers", etc.). Since the language is loosely-typed, there's no API barrier that checks this, it's all duck-typing.

2. Tons of code is written based on this assumption.

3. Assumption changes. In this example, this happened with the Python 2 => Python 3 migration, but it also happens once in a while with smaller version increments of either Python itself or Python libraries.

4. Where is the assumption used in your code? Well, if you're lucky, you're going to find out once a piece of your code throws an error because it's attempting to use a method that doesn't exist anymore. If you're not lucky, the behavior of your code has changed subtly.

In the loosely-typed world, the only way to avoid this is to have very strict boundary checks. Which means basically manually implementing subpar type checking at the borders and unit tests and/or fuzzing just to ensure that your mock-type-checking actually does its jobs.

Of course, you can often get away without doing this as long as your code is for internal use only. But if you're writing a library and if you want your users to be able to troubleshoot problems without too many difficulties, you're doing manually what the compiler is doing for you in a statically-typed language.

Re:Deno will stop using TypeScript by stickfigure on Sunday June 21, 2020 @04:06PM (#23594968)
If a function expects an integer argument I test it with integer values.

Metric or imperial integers? Your unit tests failed to prevent this $300 million blunder:

https://www.wired.com/2010/11/1110mars-climate-observer-repo...

But more commonly what is going to happen is that someone (two years from now) is going to change a 'person' parameter from legacy SSN to database id and some users are going to get "you don't exist" when they show up at the hospital to get medical service.

You're right though, most folks in the JS/Ruby/Python ecosystems don't do this kind of testing. It's a recurring joke:

https://www.google.com/search?q=2+unit+tests+0+integration+t...

Re:Deno will stop using TypeScript by fulafel on Wednesday June 24, 2020 @01:12AM (#23624333)
I think the "metric or imperial integers" argument doesn't really work as an advertisement for static typing: A domain specific unit checking type would have worked just as well in Python as in any mainstream statically typed PL, but commonly people use just plain integers that would have failed the same way in a ST PL.
Re:Deno will stop using TypeScript by jkachmar on Sunday June 21, 2020 @01:40PM (#23593658)
The inputs shouldn’t be “random”, but the idea is that you should provide an input distribution that’s roughly representative of your expected distribution of real-world values (+ some perturbation to find edge cases).

As for frameworks in the languages you listed...

Ruby and Python: https://github.com/HypothesisWorks/hypothesis

Elixir and Erlang: https://github.com/proper-testing/proper

Node and JS: https://jsverify.github.io/

As for real world use-cases, imagine you’re writing a program that accepts timestamps as input and has to implement branching, requirements-defined business logic based off of them. When you’re writing your unit tests you can use the requirements to select timestamps that are “known good” and “known bad”, but it’s hard to explore this state space on your own.

Same thing goes for handling unexpected inputs to certain functions. You probably don’t want to check _every_ type of input for _every_ dynamic function, but it might make sense to make sure that certain “entry points” to your program fail in the expected manner when they get poorly typed input.

Re:Deno will stop using TypeScript by nsonha on Sunday June 21, 2020 @07:12PM (#23596104)
How about a map of options where some of them are mutually exclusive? Without union types you have to write test for that.
Re:Deno will stop using TypeScript by orangecat on Sunday June 21, 2020 @01:26PM (#23593521)
You need integration-level tests around every method call

Sure, but you need those tests anyway to verify that your code actually works. I agree that type systems reduce the occurrences of some classes of bugs; I'm only disagreeing with the claim that they reduce the amount of tests you need to write.

Re:Deno will stop using TypeScript by josephg on Sunday June 21, 2020 @06:58PM (#23596024)
I used to agree with you, and somewhere in my comment history on HN you’ll find similar comments to yours. But I think I was wrong.

I recently ported some (quite complex) code I wrote from JavaScript to Typescript. The code has about a 2:1 test to code ratio, and a fuzzer for correctness. While porting, I ended up adding a couple “useless” assert(typeof x === ...) calls to quieten the compiler, which felt useless because my code was correct. Lo and behold, the assertion tripped in my test suite - apparently I was sometimes treating a string as an object and didn’t notice. Which was a serious issue; and could end up being a security problem for some people. My fuzzer didn’t find it because it never occurred to me to add string method names in my random data generator.

Generally I find that the bugs that are easy to find with tests and the bugs that are easy to find with static types are different. You can eventually find all bugs with a sufficiently large test suite; and with enough PhDs you can apparently formally prove everything. But you get the best bang for buck with a little of each. A few tests is much better than no tests. But in the same spirit, I find no matter how big my test suite, there’s a good chance static types will improve my code.

Typescript is far from perfect, but I sleep better at night with a type checker checking my code.

Re:Deno will stop using TypeScript by orangecat on Sunday June 21, 2020 @09:42PM (#23596759)
Generally I find that the bugs that are easy to find with tests and the bugs that are easy to find with static types are different.

I don't think we disagree much. As your experience shows, trying to replicate type checking via unit tests is almost always impractical. Which means the tradeoff of not having static typing is not that you're writing more tests, but that there's an increased chance of bugs.

And I agree that once a JS project is large enough to have a build process, the benefits of TypeScript almost always outweigh the costs. I'd even like to see JS interpreters allow and ignore TypeScript types, so you could use it without a build step.

Re:Deno will stop using TypeScript by jondubois on Sunday June 21, 2020 @05:05PM (#23595395)
>> How many different possible representations of a 'thing' do you have? A json object?

Why would you design a function in such a way that one of the arguments can represent so many different things? The problem here has nothing to do with testing. The problem is that the function itself is poorly designed.

If anything, the difficulty of writing a test for such a function would in itself be an indication that the function needs a refactoring.

Re:Deno will stop using TypeScript by stickfigure on Tuesday June 23, 2020 @01:16AM (#23610153)
It's not the function parameter that has multiple representations, it's your app. The function takes one representation - let's say a numeric id. That doesn't help the client of your function, who could pass in a database id, a database record object, a json object, some sort of natural key, etc... all of which plausibly will match an untyped parameter named "thing". And your function may change its contract someday.