Hacker News new | ask | show | jobs
by IshKebab 789 days ago
It sounds like you have simply not experienced the problems that loosy goosy types cause. They tend to be biggest when you're working on large projects and on other people's code.

If you've only done small projects or projects where you are the primary author then you may not run into the issues. You essentially end up doing what Typescript does but in your head without writing anything down.

The problems it solves are:

* Bugs! It catches lots of bugs.

* Navigating code efficiently. You can just click stuff to go to its definition or uses.

* Refactoring code reliably. You can now rename variables without making mistakes.

* Reading code. It can be extremely difficult to understand code without static types because you don't know what anything is or where anything goes unless you run it (which can be very difficult).

Not Typescript, but as an example I was trying to understand some code in Gitlab like `auto_cancel_from_rules.merge(auto_cancel_from_config)`. "what does `merge` do?" I wondered.

Literally could not find it. You can't search for `merge`, way too many results. I don't know what the types of the variables are so I can't look it up. I spent about 15 minutes looking around and eventually gave up.

With static types you can literally just click it and it will take you to the definition.

2 comments

If I never again in my career have to encounter the God Function that everything in the system calls one way or another and takes 9 arguments, all of which are something like "either a string identifying an ID, or a function yielding a string, or a function that yields a list or an iterator of strings, or an object with a GetID method, or if the third parameter was falsy, a function to be called if the user is not authenticated", I will be pleased. Or the function that has literally 40 parameters, 36 of them optional, and while each of them may be individually reasonably well defined you will never work out what all combinations of them do, and you can also know there is no test and no spec for all possible combinations. (Unlike the former which is characteristic of local codebases and bad discipline, the latter is the basis of major dynamic scripting language libraries.)

Dynamic typing doesn't have to get that messy, but it takes discipline that is very hard to enforce at scale. Static typing can sort of approximate that level of mess but it takes a lot more work, and perhaps even more importantly, it's a lot safer to fix. But every significantly-sized dynamic scripting code base I've encountered has certainly had at least one of those two issues deeply, deeply ground into it.

> Bugs! It catches lots of bugs.*

Unlikely. Maybe if you are using a language with a complete type system (let's face it, you are not), but otherwise you are necessarily going to have to encode all the type information into your tests anyway, so you haven't gained anything on this front. A partial type system cannot replace these tests.

Your other points are the real wins, though.

I didn't say it catches all bugs. I said it catches lots of bugs, which it absolutely does.

It's literally impossible to write tests to find all bugs. Most tests don't come remotely close to that, so there's always going to be bugs that static type checks find that tests don't.

There's a great paper that shows that even after tests, Typescript would catch 15% of Javascript bugs: https://earlbarr.com/publications/typestudy.pdf

Also the fact static typing eliminates entire classes of bugs means you need to write far fewer tests. I've seen Python tests that literally fed different types into functions and verified that they accepted them. What a misguided waste of effort!

> I didn't say it catches all bugs.

It is always telling when someone starts getting worked up about something, especially when that something wasn't even said or implied.

> Also the fact static typing eliminates entire classes of bugs means you need to write far fewer tests.

You don't need to write any more tests in the absence of static types. The purpose of testing is not to act as a replacement for static types and if you find yourself writing tests just for the sake of testing types, you know you're doing something horribly wrong. But, you necessarily have to encode type information into the tests in order of them to execute. After all, if that wasn't the case, you wouldn't even be able to catch bugs with a type system. As such, you gain that indirectly.

> I've seen Python tests that literally fed different types into functions and verified that they accepted them. What a misguided waste of effort!

Sure, I've seen developers do all kinds of stupid things too. In fact, give them Typescript and they will just litter the code with `any` everywhere – something I've witnessed far too often. There is no technical solution to bad developers. Was there supposed to be some meaningful takeaway here?

> You don't need to write any more tests in the absence of types.

To achieve the same level of quality, yes you absolutely do. This is actually a fairly fundamental fact about static typing. Static typing is a weak form of formal verification, or equivalently formal verification is just really really strong static typing. Clearly you don't need to write as many tests for formally verified code. The same is true (to a lesser extent) for "ordinary" static typing.

> Sure, I've seen developers do all kinds of stupid things too.

It's not stupid if you have a static typing system available! The stupidity was relying on tests to verify types, instead of ... you know, the thing whose whole purpose is to verify types.

> This is actually a fairly fundamental fact about static typing.

If you have a complete type system. But as we are specifically talking about partial type systems, you have to already cover all your bases for where the type system is lacking, and by virtue of that you are going to overlap with what the type system also covers.

> It's not stupid if you have a static typing system available!

There is no reason for it, static type system or not.

> If you have a complete type system.

Nope. You don't need a Turing complete type system.

it catches them before writing tests, which is a clear win
Except you need to write the test first, else there is no way to ensure that your tests actually work and aren't passing because your tests have bugs. So what have you won, exactly?
It's much faster to find bugs because an IDE instantly underlines the exact line where the mistake is as you write it, than it is to write a load of code and then debug failing tests.

And as I said in the other comment, tests won't catch all of the mistakes that static typing will catch anyway.

If you have a complete type system, sure. Then you have constraint on the subtle mistakes one is likely to make.

The partial type systems found in languages people actually use, though, only constrain the most glaring of mistakes that you are almost never going to make. Not impossible that you could make one, but highly unlikely. Certainly not on the order of "lots". More like once in a blue moon.

Refactoring is a different story. Having an editor that lights up like a Christmas tree when code changes breaks existing relationships is a huge boon, and with good refactoring tools you almost never have to break the relationships in the first place. This is where (partial) static typing truly shines.

> the most glaring of mistakes that you are almost never going to make. Not impossible that you could make one, but highly unlikely. Certainly not on the order of "lots".

Not true. People make these mistakes all the time.

I was literally reviewing code today where someone write Python code to write a field that didn't exist. They didn't realise because they hadn't written a test. They asked me to check if it fixed my issue, which wasted 5 minutes of my time checking, when an IDE with static types would have told them their mistake instantly.

You can pull the "well I don't make mistakes" classic, but it doesn't matter. People do make these mistakes.

I linked an empirical study showing that 15% of bugs are precisely these mistakes. If you don't think it's worth eliminating 15% of bugs then frankly I just think you have crazy priorities and I can't really fix that.

Write a little bit of code and debug one failing test? TDD?
I don't "need" to write test firsts. TDD is one good way of writing software, but not the only one and not a requirement to write good software.