At least to me, the big advantage of static typing is not that it (allegedly) reduces bugs, but that it aids my understanding and helps in navigating the program. It's a tool for thinking and communicating.
I'm not against studies and research - I have a computer science degree myself - but I'm a little tired of being told my personal anecdotal evidence is not sufficient to conclude that water is wet.
As a professional software developer of 30+ years, the doubts on static types puzzle me.
8 years ago, I started dabbling more in javascript, for one of my continuous pet projects. I had it running and grew it to a considerable size, but after a year or two, I lost patience with debugging runtime issues, hunting for where I had forgot to update or initialize or remove stuff, during refactoring. I swore an oath never to use raw javascript again, and rewrote it from scratch in typescript. I am still working on it to this day, and I don't remember being angry at typescript a single day in the intervening 7 years.
My working day jobs have been mostly C++, and these days C#.
Periodically, I will temporarily inherit some of my younger colleagues' projects, if they move on to greener pastures in different companies, with the charter of "can you do something about the long-running issues this software has been having?"
My go-to solution is to go through their typescript and add return types to their functions, and replace their anys with interfaces.
After having done that, I fix the bugs that revealed,
and then I'm usually done.
Recently when I did that, I came across a central class/data structure, which turned out to exist in no less than 5 slightly different variants. i.e. different parts of their code adhered to 5 different assumptions about what fields would exist and be populated (but all expressed on the blank canvas of 'any').
I think we need to be careful with trusting even our own anecdotal evidence because it's simply riddled with biases and bugs. 30+ years of experience is certainly impressive but I'd say you probably never worked in a senior team on a larger Clojure codebase for example which would give you quite the opposite impression. You should read the anecdotal evidence in that community, it's very different.
> [...] I'm a little tired of being told my personal anecdotal evidence is not sufficient to conclude that water is wet.
The problem is, other people with just as many credentials as you have the opposite experience. From an outsider's perspective, two people with equal authority say opposite things, what can they possibly do except an independent study?
Also, note that there's a reason anecdotal evidence is not always reliable. E.g. the famous story about fighter pilots and the "regression to the mean" hypothesis.
I suppose what they can do is write some code and figure out where their specific situation lands them on the Static Typing is good/bad spectrum.
In this scenario, I honestly don't think it matters whose objectively right. Software is not a clean, normalized and organized set of use cases after all, maybe static typing works for person X and doesn't for person Y because of their background, or preferences, or codebase requirements, and so on.
Maybe one day we can conclusively prove that on aggregate static-typing/{insertThingHere} is overall less buggy, but even if we did, it'll still change depending on circumstances.
I have far less experience than you and I've definitely experienced drowning in runtime issues when working with a large project in a dynamic language.
On the other hand, though: have you worked with large, thoroughly tested projects in a dynamic language? Personally, I find that good tests catch 99% of the bugs that static types do, plus quite a lot of other bugs as well. Arguably, you ought to write tests anyway to find those other bugs. Since they also find your typos etc, you get to enjoy the ergonomics boost of dynamic typing almost for free.
That's my (also anecdotal) argument for doubting static types.
JavaScript is a fantastic language once you understand how it really works. If you do truly understand the language then maybe you should use something that compiles to JS.
It’s basically self-evident that static analysis reduces bugs. It’s trivial to construct an example of where type information would catch a bug. Unless there is some reason that including type information increases bugs, the existence of a single example where type information catches a bug would prove that overall type information reduces total bug count.
This reminds me of the studies done related to traffic lights and stop signs.
Removing traffic lights and stop signs actually reduces accidents because drivers are more careful when driving through intersections which reduces speeds and drivers become more alert.
Developers will adapt to their toolset. If you have a statically typed language, you trust it will deal with type related issues and you become more lax with testing things related to types. When you develop in non-typed languages like Ruby, you tend to write more tests and not trust your compiler (because you don't have one). This is why you will find most Ruby developers are really good at writing tests and embracing TDD.
You're point is valid, but you really quickly move past just how slowly drivers have to be when there aren't traffic lights. As with everything they're a helpful tool for efficient traffic, just like static compilation.
I can't speak for all Ruby developers but I found that I could read a pull request from just about anyone I worked with a and find a spot where they hadn't covered a possible nil with a test. And yes, we had coverage checks.
A type system can keep you from having to write those tests.
Those languages don't have null safety, but plenty of languages do. Rust, Kotlin, Swift, Haskell, etc.
The claim is true: a type system _can_ prevent null-related issues and eliminate the need to account for them in tests. That's not the same as saying every type system does.
That's a good analogy, because just like when an intersection gets enough throughput, relying on drivers to navigate their way through becomes unrealistic. Once a codebase reaches a certain size or complexity, it starts becoming really time consuming to follow untyped logic all over the place and you run the risk of a rockstar developer putting a scooter object into the side door of your minivan object.
Static typing gives you assurances and tools with which to test your assumptions in the code, for those times when reading the whole stack is cumbersome, and you need to defend against less careful developers. It also transfers a bit of knowledge between developers in a trivial way that would otherwise be a pain to communicate.
I think this analog is close to the dynamic vs static debate. However, there are probably more factors to consider, such as competence of the driver (will the driver even care to slow down?), location of the intersection (an intersection just around a shallow corner) and value of the driver's car (does the driver care about a little damage?).
In my experience similar arguments hold for software developers. Especially caring can be a big factor; i.e. the "move fast, break things" mentality.
I've been back and forth between typed and untyped languages (somewhere in the range of haskell and tcl) and personally prefer less typing when hacking things together and more typing for high quality software. I'm currently working an infra job where we use both ansible and terraform. They're not direct competitors, but I tend to prefer terraform over ansible when possible, as terraform gives me more "static" guarantees, which translates to more confidence when we apply our code.
One could argue that dynamically typed code is often shorter, and therefore both easier to reason about, and possessed of fewer bugs on a bugs-per-line basis. Not really keen to push that line of reasoning myself, just helping picture one possible argument.
This is true in a local context, but entirely breaks down when a codebase becomes larger than a single person can fit into their brain-RAM. Not arguing or saying you're wrong - just presenting the very quickly reached boundary where the argument breaks down.
It's not just local context. Reading a dense book is still more difficult than reading a less dense book, given a fairly similar amount of information and style in conveying that information. Larger codebases suffer the same problem you mention in a different way, and cargocults in most static languages tend to advocate very verbose writing styles.
Where this falls apart, the more verbose writing style hasn't been proven to convey more information or in a better way. That's an assumption still tossed around.
I would even argue that shorter can do the opposite. You can squeeze an awful lot of information into a tight space in dynamically typed languages that allow functional programming and especially with terse syntax for often used constructs.
This can make it much harder to actually reason about the code, while making it seem easier to reason about. Most people would agree w/ your reasoning on a short piece of logic, which then at runtime spectacularly fails because the inputs don't adhere to the types you expected. In a statically typed language you would not even have gotten it to compile and while it might not feel like a bug is being prevented and actually feel tedious, every time your IDE (or compiler) tells you that the type on something is wrong, you've prevented a potential bug.
Easy, right? Well, does param actually have `property`? No idea. What type is `property`? Does the function `doSomethingWith` take that kind of input? No idea. Now I have to check that function, which might be coming from I don't know where, I might not even have an IDE that can reliably determine where `doSomethingWith` is coming from exactly. Even if I can navigate there now I have to check that piece of code and any other code it calls with `property`. Maybe `property` itself is an object and `doSomethingWith` assumes it has yet another property. This can easily go quite deep and I will not be able to easily reason about this at all. You can't tell me that someone can have all possible runtime combinations of this in his head for any reasonably sized program.
Now let's take something that is almost equal but slightly longer to read and write, same thing in Typescript. I've had to define the types of these things somewhere once. Big deal.
Notice how this is really not much of a difference. Just a type declaration and it gives me a lot of safety. Let's assume SomeType defined `property` as non-null, so no `?` needed, I know my inputs have already been checked. `doSomethingWith` also defines its parameter type correctly and we know what `property` is or isn't. No need to know anything from the top of my head or spend time digging through code myself. The compiler knows that I am passing the correct type of object along and I won't get a runtime error (well, OK, it's Typescript, so let's also assume I'm not in a mixed TS/JS code base where I might very easily get `any` kind of object.
Now syntax will be a little bit different, but I would argue the exact same thing in say Java or Kotlin is equivalently short and readable (yes even in Java!) while benefiting from even more type safety:
public myFunc(SomeType param) {
doSomethingWith(param.getProperty());
}
Didn't really hurt much, did it?
But these are super simple example. It get can arbitrarily complex.
As a Haskell programmer, this argument does not resonate with me. I find most dynamically typed languages (e.g., JavaScript) verbose compared to what I'm used to. Of course, plenty of statically typed languages are verbose too. But static typing is not a sufficient condition for a language to be verbose.
I associate verbosity with object-oriented programming, whether statically typed or not.
As a clojure programmer, I'd say the same of Haskell. Oop is less expressive than FP, and static typing is less expressive than dynamic typing. These are usually just tradeoffs people choose for their problem domain
> static typing is less expressive than dynamic typing
Here's something I can express with static typing that I can't express with dynamic typing: "this function returns a function which returns an integer for every input". There's no test you could write to verify this property. So I'm inclined to say that static typing is more expressive, since it gives me a way to express and verify properties like this.
Shorter how? The typing can often be implicit in many languages like Scala which makes it pretty short compared to something like Java. While there is a bit of explicit typing, I think it’s well into diminishing returns to force even shorter code.
Because the studies are constructed by equally fallible humans, and almost always badly.
Cold shower attempted, but the plumbing was busted?
Such studies invariably wholly miss the point: when you have a language with powerful type support, error checking is the least valuable work you get out of them. Types do serious heavy lifting expressing semantics.
As a general rule for dev work, trying to make evidence based decisions is fairly difficult. There's just not that much evidence around yet that can make it obvious as to if in your particular situation what the best choice might be.
And at the end of the day you have to contend with being in a work environment where politics and personalities rule, not science (or engineering).
That said I do wish more devs would take an interest in the available quality literature. Unfortunately I'm far more likely at work to run into an Uncle Bob recommendation at work, than a recommendation of ACM's Digital Library.
It is not evident to me. Having used both statically typed and dynamically typed languages my experience is that I can't remember ever seeing a bug in our fairly large rails app that a type system would catch. Nobody's passing strings where hashes are expected, or Widget instances where User instances are expected. The thing to pass to the function is nearly always self evident. If you did it would immediately be caught when a test runs anyway.
However, refactoring code in C# is much easier than refactoring ruby because you can lean on the type system there. However writing new code in C# is often much harder to do in C# because of the constraints of the type system. So really, it ends up being a wash for me.
Even trivial things like a typo in the method name in a method call are not detected at compile time by languages like JavaScript or Ruby (since their "method calls" are in fact just lookups in a runtime hash table...).
If you have not seen them, the reason is probably that the code was tested well enough before you looked for the bugs.
> If you did it would immediately be caught when a test runs anyway.
That's the point though. With dynamic typing you would only (hopefully) catch this with manually written tests. With static typing you get that feedback for free at build time.
Not true because anyone can implement just part of an interface and throw "method undefined" for the methods they can't figure out how to implement. This happens all the time.
> Not true because anyone can implement just part of an interface and throw "method undefined" for the methods they can't figure out how to implement. This happens all the time.
How would that pass any code review, regardless of static or dynamic typing?
The only time I have ever seen something like this is using `todo!()` while initially writing code. I have never seen someone check in code like this.
What kind of clown show of a programming org are you working at?
This is morally equivalent to "There's no point to having a safety on a gun, because the safety won't stop you from bashing someone in the face with the gun." If you really want to, you can throw exceptions or crash the process or call exit() or call system("shutdown -h now") anywhere in your codebase. That has nothing to do with a type system.
>Nobody's passing strings where hashes are expected
See, When I'm throwing together apps to clean up configurations, I am Pythonifying XML often. And when handling different return values, reshaping it into the useful components I need and trying to analyze data (and dealing with different return formats depending on number of results, aka a dict if there is one value, or a list(dict) if there are more) I have to constantly remember if I am going to be getting a list(dict(dict(dict(str)))) or just a dict(dict(string)), and so on. But that's me cobbling together scripts and not understanding the API by heart well enough.
Yes - in every case it is calling a method on a null reference. And no commonly used statically typed language helps here because they all allow null references. And languages that disallow nulls, if you are one of the 10 programmers on earth working in one of those languages, don't help you because you are dealing with real world data where inputs to your system can be null or not so you end up using some type system escape hatch anyway.
> no commonly used statically typed language helps here because they all allow null references
This is false.
TypeScript, Swift, and Rust are commonly used and support non-nullable references.
> those languages, don't help you because you are dealing with real world data where inputs to your system can be null or not so you end up using some type system escape hatch anyway.
You don't need escape hatches to deal with "real world data" that may be missing some values. This blog post is my favorite detailed comparison of handling "real world data" in static vs dynamic languages: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ...
The only requirement for working with "real world data" in a static non-nullable language is to choose whatever kind of behaviour you want when working with the data. Everything you can do with null references, you can do better with option types; there is nothing that null references uniquely permit.
Dunno what to tell you dude; my imagination stretches there just fine. Maybe consider going to imaginary yoga class.
There have been people writing at least two of those languages everywhere I've worked for a while. Most of my professional colleagues can write at least one of these comfortably. I'm extremely confident in being able to hire programmers for all of these. They're all in use at every major tech company.
If you really want to stick your head in the sand and cry about how nothing can be better until they're literally top of the charts, I can't stop you, but they're certainly not rare. There's good stuff out there. Lots of people are using it. You can too.
If you'd rather trade links to charts, I trust Stack Overflow's developer survey's methodology a lot more than TIOBE's. 30% of respondents said they've worked with TypeScript, and that jumps to 36% in the professional developer subset. Rust is 7%/6%. That's a hell of a lot more than 10 developers.
My country has about 15% black people about about 7% asian people. My country has about 4% LGBT people, and my city has about 15% LGBT. It would be really weird to hear someone say that black, asian, and LGBT people are not common, especially after knowing and working with plenty of them.
> don't help you because you are dealing with real world data where inputs to your system can be null or not so you end up using some type system escape hatch anyway.
You clearly have little experience with such languages, then.
Python (with mypy) has strict optional on as default and is the most widely used language, according to the latest stackoverflow ranking. Assuming you use mypy of course, which probably takes the usage rate down a factor of 100x but still.. ;)
It makes you actually have to consider scenarios where a variable can be none or not and try to push the validation up closer to where it entered the system.
Static typing doesn't mean type information being available. Most statically typed language allow some version of `let x = 5`. Similarly static types doesn't mean unsafe casting are not performed.
Also in the opposite direction, many dynamically typed language allows specifying types if you want to including python.
x still has static type, the compiler just infers it based on the assignment, the type information is still there. Agree that implicit/unsafe casting is still and issue in some languages though.
Allegedly? Have you ever written code in a dynamically typed language? I'm forever fixing TypeErrors and AttributeErrors and the like.
I suppose it's not even necessary to argue about experience fixing them or not, just the fact that those are runtime errors rather than compile-time (and so we presume not shipped) shows it reduces bugs doesn't it?
I always notate my functions with JSDocs and my DTOs as jsdoc types which in any modern IDE gives you the same advantages that you would get out of the explicit typescript interface/type.
And Unlike typescript my code doesn't need to be transpiled at all since it is already vanilla JS.
The presence or absence of a compilation stage has nothing to do with static typing. Flow.js is static typing. MyPy is static typing. It sounds like your JSDoc comments are static typing, if your IDE ends up passing them through the TypeScript type checker in JS mode.
It may not be very comprehensive static typing but it is static typing none-the-less.
Reduces bugs in size, or only leaves smaller bugs behind?
These are two very different outcomes.
If the remaining bugs are unrelated to the class of bugs that were eliminated entirely, then the difficulty in finding them has little bearing on the outcome, since we’re now talking about an entirely different class of bugs.
This is conjecture, but in my experience you'd get the following:
- in JS, your code will run with the bug then do something catastrophic during runtime that you can then notice and trace to the core issue
- in Java it won't compile, so you fix it so it compiles and runs, then it'll hit you in like 2 hours of runtime with a NPE or something and you'll have no idea what caused it
Maybe Kotlin, Rust, and the like solve that sort of thing better but I've yet to be convinced.
But is there any evidence that the NPE would have blown up catastrophically without type checking? Is the NPE even related to type checking?
It seems you're describing an orthogonal issue, and it's unclear why type checking is a Bad Thing or even related to the NPE at all.
Let's say I work on an assembly line, and must place physical parts into a machine that assembles a larger part. There are many ways this machine can break down - I could put the wrong parts in, leading to a complete failure, or some part of the machine could malfunction independently.
- We could implement part validation on the assembly machine to make sure it's impossible to insert the wrong parts. This eliminates failures related to incorrect part insertion.
- Unrelated to this, a drive belt starts to wear out and slips every so often, leading to a slight slowdown in a conveyor belt, which ultimately leads to a botched item.
The way I read your argument, you would say that part validation is bad, because it's easier to diagnose a meltdown when incorrect parts are inserted by the operator than it is to determine that the drive belt is slipping.
Except the drive belt slipping is not related to operator error, and would have happened whether part validation was happening or not.
This is hopefully obviously nonsensical - better to reduce the overall error rate by implementing part validation than to leave two avenues for error. Before part validation, the machine could fail because of operator error (common) or drive belt failure (uncommon). After part validation, only the uncommon error occurs.
This is better than no validation at all, even if drive belt failure is harder to identify than the machine screeching to a halt when the wrong parts are inserted.
Static typing has an undisputed benefit, performance. If i need to add dynamic thing a and thing b, I’ll always have the overhead of figuring out what add means first in this context, an overhead i dont have when asked to add some ints.
All the other claims from readability to understandability to refactoring to less bugs, all come with an “it depends” caveat. Sometimes the claims are true, sometimes they’re not. It’s also not possible to say “but in most cases claim X holds”.
The thing I’ve never understood yet in this debate is in my experience, the people who have argued about correctness have universally been below par at getting to the bottom of requirements. Which leads to “great, you correctly built the wrong thing. And you took forever to do it.” Which isn’t doing our profession any good in the eyes of other professions who depend on us.
Not necessarily. This increased ease of understanding could also simply result in faster development speed - so same number of bugs, but more features in less time.
I agree. At least for JavaScript I would always use TypeScript now. The main reason is understanding of code as well as tooling, which means communication in the end.
I remember working 2012 on a SaaS app, and I wasn't the only guy anymore doing frontend stuff with JS. I knew my objects, but my colleagues did not. How to you document object APIs? TypeScript really shines in large projects with lots of devs.
What is an item in the second declaration? That it has type "Item" doesn't help you unless you have contextual information. And if you have contextual information you can probably figure out what an item is in the first declaration too.
An item is an IItem, as it says in the definition. You can always ‘figure out what an item is’ in a dynamic typing system, that’s not the problem. There’s an incredible amount of mental overhead in any non-trivial project which employs dynamic typing. Engineers who can work around this have my respect, but I find static typing to be the easiest solution to this problem by far.
That fact is useless without any context. An "item" could have been an "Ifdkjsj" and you'd be none the wiser. "incredible amount of mental overhead" needs a citation and, as shown in TFA, no citation exists.
Maybe I’m not understanding where you’re coming from because as far as I can tell a ‘lfdkjsj’ and a ‘skfjwb’ which are both an IItem, or both a IWhcjwp, is easier to work with than the dynamic alternative. Regardless of how poorly named a variable is, in a static ruling system what you see is what you get, where as in a dynamic typing system what you see could be anything at runtime.
The only citation I have is the tenuous grip I have on my own sanity - I could have more correctly talked about the incredible amount of mental overhead this has _for me_, but read the rest of the thread and you’ll see that this isn’t an uncommon experience. As I said, if you can work around this then you have my respect.
> in a static ruling system what you see is what you get, where as in a dynamic typing system what you see could be anything at runtime.
What you see in a statically typed language: IBlaha blah. What could blah be? An IBlaha. What could IBlaha be? Anything! The type has not gained you anything.
> The only citation I have is the tenuous grip I have on my own sanity
That's an argument from authority where you are the authority. It doesn't work on HN since we are all skilled developers. I've also been a software developer for decades and I can count on one hand the times static types has provided a tangible benefits.
Now we are just talking about using a sane naming convention for your types. Depending on the paradigm you are working in your instance of IBlaha has a consistent definition - in a trait or a class or whatever else you like. It also likely makes simple work for your IDE during refactoring as others have observed. You don’t get this from dynamic typing.
Of course you could say the same thing about sane naming dynamic naming conventions for your declarations in a dynamically typed language - and you wouldn’t be wrong, but a compiler won’t help you in the case of human error. All I’m interested in is offloading as much complexity onto the tools at my disposal, so I can focus on what’s important.
On my citation … that was tongue in cheek and I thought it was obvious. I don’t have a citation, this is all my own experience. For the third time, if you can work your way around this you have my respect.
Sure, the type IBlaha is defined somewhere just as the object(s) passed to add_item_to_cart are also defined somewhere. Again: "That it has type "Item" doesn't help you unless you have contextual information." It has nothing to do with naming conventions. Whatever simplistic tools does is irrelevant since this sub thread was about the meaning of two declarations in HN comment.
Dynamically typed languages are very popular so it seems that many developers can work their way around dynamic typing.
- Sure, the type IBlaha is defined somewhere just as the object(s) passed to add_item_to_cart are also defined somewhere.
That definition is rarely as accessible as an explicit type though. For example take an API response or any third party library. Determining the data type isn't as quick as simply scanning a function for the object definition.
- Dynamically typed languages are very popular so it seems that many developers can work their way around dynamic typing.
As someone who has spent a fairly even mix of their career using typed/untyped languages, I think this is due to a few reasons:
- Lower initial learning curve.
- Lower barrier to entry.
Those are real benefits, but I would argue most projects quickly hit a point where they benefit from static analysis.
Having worked with 100s of devs at this point, I'm yet to meet one that after learning a typed language and using it for a sufficient period of time (more than a few months) wants to use an untyped language for anything outside of small scripts.
>What could IBlaha be? Anything! The type has not gained you anything.
You're confusing Java-type extreme (and also mostly strawmanned) application of OOP with static typing.
Not every type in your program has to be AbstractFactoryProxyBeanInterface, and if you don't write code like that it's either obvious or some kind of extension interface for non-core code.
If it were an item id the argument would be item_id. It is an object. What type of object? The type that can be added to a cart. You don't just drop a programmer into the code and have them call a function in a vacuum. Nobody just throws random objects at a function. They are familiar with the code in general and they know what to do.
- If it were an item id the argument would be item_id. It is an object.
You've never worked with vaguely named variables? What you are suggesting is guessing the data type based off the name.
-
What type of object? The type that can be added to a cart.
Okay sure, but what precisely is that?
-
Nobody just throws random objects at a function.
I couldn't agree more - so the follow up question is what is the fastest way to get familiar with what type of input or output this function returns?
-
They are familiar with the code in general and they know what to do.
For very small projects with very small teams after some onboarding time perhaps, but outside of this I would disagree.
Code changes over time, parts that you use to know intimately get changed subtley and erode knowledge away. Having types in place highlights these changes if your assumptions are incorrect.
If you're working with badly named variables you have more problems than a type system can help with.
It doesn't matter "what precisely" is the the thing that you are adding to the chart, and a static type system won't tell you that either. There could be be any of 1000 things that implement IItem. And probably half those things just throw exceptions for methods they aren't actually able to implement.
If you only use trivial examples, types seem silly. But in real examples they become more useful. In this case looking at the function signature give you immediate information about the implementation that is missing from the untyped version.
EDIT: please excuse formatting, I'm on mobile and cannot get it to add spaces before the last code block
Depends on the specifics, but i'm betting if `IITem` is close by i know how to interact with it. I have no clue what the hell fields or methods may or may not be on `item`. Nor will i, ever. At best i have to enforce method/fields myself, at worst i subscribe entirely to duck typing and let the gods sort it out.
> I don't need tests to check what methods or fields are on my types though.
You do though, because invariably people violate the LSP and just "throw Unimplemented" in the methods required by the interface they can't figure out how to implement. In other words all system are duck typed in reality.
I don't, though. If it compiles, it exists. Saying that a method might actually be a nuke is a bit besides the point. It could also contain a virus.
Not sure what typing system you're referring to, but it sounds very half-baked at best. I'm using Rust fwiw.
I cannot access any field or method that does not exist. Even dynamic traits are compile time enforced, but i think we can largely have this discussion around static dispatch.
But suppose you were unfamiliar with the code, the 2nd tells you what fields/methods are available for "item", and furthermore most IDEs will use that info to populate autocomplete suggestions and such.
How would a "language engine" know what you can do with `item` if it has no type information?
You can do that with Python (sometimes) because many libraries have type hints today, so even if you don't use types yourself, the type checker can infer them in your code and help you out.
I still don't see how you can determine an object's attributes without type information. If you're inside the function, all you know is there's a parameter named item. How can you provide autocomplete there?
All of the examples you gave are from static languages, where the information is known at compile time (except for valgrind, which requires a runtime). The parent to my original post was claiming that you can have the same tooling for Ruby.
Also, you're wrong about Rust. Lifetimes are part of the type system.
What about return types? Do you generally deal with voids in your line of work? Having code that could return different types depending on branching is pretty self-evidently worth preventing.
Static typing does not imply type annotation. For example in C++:
void add_item_to_cart(auto item)
will still statically verify that item has the required syntax; C++ is very poor on this aspect on only doing the verification at instantiation time, languages with more sophisticate typing systems can infer the correct type from tome add_time_to_cart definition alone.
And when we understand this, we can weigh it up with alternative tools for thinking and communicating!
Would this 10 line shell script be better in a statically typed language? Well maybe not because I can hold all of 10 lines in my head, there's nothing else to communicate.
Would this CRUD app using Django/Rails be better with static types? Well the framework has defined a structure that communicates properties of the code to me, I don't need types written down because I already know them.
Would this complex parsing process of untrusted data into a trusted and verified format benefit from static types? Yeah probably, testing will be tricky and code review for security is hard, types will help reason about the possible states of the system.
There are lots of alternatives to static types: documentation, testing, frameworks, design patterns, code review, pair programming, error messages, and so much more. I'm generally a fan of static types and find them very useful in a lot of development, but they are a tool in a big toolbox.
This is the major one. I work on a 10 year old rails app and it has got to the point where we are terrified of making any change that has the potential to affect areas outside of the visible git diff. It's easy enough to manually verify regular changes by looking at the code. But something like a library update is impossible to verify and we constantly end up with production issues because of something changing in a library that wasn't mentioned in the upgrade guide and would be impossible to have considered beforehand. But that a type system would catch.
Sounds exactly like every dynamically typed code base I’ve ever worked on. Even if it’s not big. If you can’t grow out all the parts that matter (which is a lot of the time), you are screwed.
I find that is a far less common problem than the documentation being wrong. Even if someone doesn't add documentation for some library, static types provide a lot more insight into how it works than dynamic languages (Racket style contracts are even better since they can check way more than static types while still working in a first class way with docs).
They can be consumed by static analysis tooling, which assuming properly configured etc. makes it sort of 'dynamically typed language with the guarantees of a statically typed one', at least so far as the hints are complete.
Most statically typed languages compile down to object code which runs in one of the most dynamic runtime environments imaginable. What are the types in the source code but “comments”?
At least to me, the big advantage of static typing is not that it (allegedly) reduces bugs, but that it aids my understanding and helps in navigating the program. It's a tool for thinking and communicating.