> Advocates of dynamic typing may argue that rather than spend a lot of time correcting annoying static type errors arising from sound, conservative static type checking algorithms in compilers, it’s better to rely on strong dynamic typing to catch errors as and when they arise.
Why is that a strange statement?
Edit: Of course it is a perfectly valid statement, advocates of dynamic typing may indeed argue that. "It's better" depends on your context, of course. If you have 100 mediocre programmers taking turns on the same code, it's probably not better. One of the great things about TypeScript is that you can decide on the spot when "it's better": Usually it's better when you otherwise have to make a hand stand in the type system to express what you want.
The later you detect a bug in the development process, the more expensive it is to fix.
If every type mismatch causes a program crash then you still have real problems with a production crash. Your user has a degraded experience. Somebody gets alerted about the crash. Somebody needs to investigate it. In a language like python, you are often just stuck with a message that says that your variable doesn't have the right function so you've got no idea what wrong type it is and where it came from. You track it down, diagnose the issue, and push a fix.
It can be worse in a duck typed world, where you aren't even guaranteed to crash. Your program might just fly off and do completely wrong things. Or you might be working in a domain where crashing is unacceptable.
In a statically typed world, your compiler yells at you and says "you are passing an X here when it expects a Y" and you fix the issue before the code ever runs.
There are downsides of the latter approach, of course. "Ugh, I've got a FooMap and I need to pass it to a BarMap and these types are incompatible" is aggravating. Attempts to fix this have not always been great and we've got mountains of Java code where nobody has any clue where the real code is because everything is typed as an interface, for example.
I think in this case it's probably true for run of the mill bugs, but not for architecture and system design.
But I just want to object to "we don't have any good evidence". This is the sort of thing that it's really hard to get scientific evidence for, but that doesn't mean we can't learn about it.
I mean the problem is that we have quite good evidence of how to handle architecture and system designs problems. And it is not by finding them earlier.
But by reducing their costs through looser coupling and incremental work. That is where all kind of agile and DevOps research showed.
> we have quite good evidence of how to handle architecture and system designs problems
We do? I seriously doubt that. New good and bad architectures are popping up all the time. And there are plenty of architectures that people totally disagree about, e.g. microservices.
> But by reducing their costs through looser coupling
In my experience loose coupling is something to be generally avoided where possible. It leads to spaghetti systems and unknown data flows. Pretty much the dynamic typing of architecture design.
I'm not exactly sure what point you're trying to make though so I may have misunderstood...
They may not cost more for us devs, but does it factor in the time our customers are not doing what they need to do because of that bug?
I mean I fixed a trivial-to-fix bug the other day that probably Rust would have caught. Between the time it took for them to report it, support doing their thing and a new build was out it took an hour. An hour that our customer couldn't do what they needed to do for their work.
So I'd say it's almost trivially true that a bug caught before release costs less to fix.
This is a very strange statement on a site designed by and for engineers. We’ve all worked on large projects. It can take an annoying few minutes to get a static type check error fixed. We’ve all spent days or even weeks tracking down weird random runtime errors due to type mismatching.
The plural of anecdote is not data, but this is not a science website either. You don’t need a study to establish engineering common sense.
I've grown to dislike this statement. The worst case cost of fixing a problem late is bad. The vast majority of bugs are not that, though. Some are cheap no matter when you find them.
That said, I suspect many people were used to static types that required a lot of support to name everything. In those, it was common for changes to be rather extensive in what had to change. Just look at early Java EE stuff with tons of interfaces and text config for what is commonly a single "pojo" for a while now.
Now, I don't think this is an argument against static tools. Tools are tools. If you have a specification that you can encode into types easily, do so. If the type already exists, use it. If you are exploring, take care not to encode into the type a runtime feature of the data.
Dynamic typing aka type inferencing (like in Python, but also in Java and C# when you use "var") can get you in trouble quickly. Consider this code:
var fireable = someMethod();
firable.fire();
The programmer intended this code to fire an employee. Let's say this code is in a military application, and another programmer modified the someMethod() function to return a missile. As long as the missile object has a fire() method this code will compile just fine... and do something the code didn't intend to do, i.e., fire a missile!
How likely are you to have employee firing and missile firing in the same program? Not very likely, but the principle is valid, nonetheless. You need to express your intention more clearly like this:
Employee fireable = someMethod();
Now if someMethod() is modified to return a missile you get a compilation error, and the world will be a lot safer. You don't want missiles being fired by accident!
"Dynamic typing" refers to types which can be determined only at runtime, not at compile time.
"Type inference" is what you're referring to, and is an optional feature of static type checkers. For instance, C has static types but no type inference, while C++ has static types with type inference. The concept of "type inference" doesn't make sense for dynamic typing.
Maybe don't name your methods as vaguely as "someMethod()", name it something like "Employee()", or "Missile()" depending on what is needed in the program. That way the vagueness of "someMethod()" doesn't cause unintended consequences.
Fireable already implies that the result of somemethod() is something fireable. That is why op uses somemethod(). Maybe a better name would be getSomethingThatCanBeFired() but that would not really explain OPs point better.
Naming doesn’t fix unintended consequences. If you are the only person to ever work in the codebase and you never hire anyone new and you have a perfect memory… sure i guess it works than.
static typing also doesn't fix unintended consequences. In the example given above, naming things descriptively and applying the smallest bit of common sense would achieve practically the same thing as static typing.
Sure but it finds compile time errors a whole lot easier. And when modifying code i can say from experience it’s much smoother to modify large statically typed projects than large dynamically typed ones.
Actually anyone arguing against that i don’t even think it’s worth my breath since you likely just don’t have much experience and really like whatever your pet language is
>Actually anyone arguing against that i don’t even think it’s worth my breath since you likely just don’t have much experience and really like whatever your pet language is
Thanks for the ad hominem attack, but I've been coding in C, C++, C#, python, javascript, php and a dozen other languages, as well as assembly language which doesn't even have types at all, for 40+ years. Maybe your ad hominem attacks work on other social media sites, but not here kiddo.
Better yet, avoid methods and classes when possible in favor of functions that act on data structures, which live in contextual directories and can be renamed so as to avoid confusion.
I see this being downvoted over the difference between dynamic typing and type inference.
I feel this is unjustified. The example shows what can go wrong with type inference, which is in fact a feature of dynamicly typed languages (even though it is not explitly called type inference in that context).
Type inference isn't really a feature of dynamically typed languages any more than emergency stop is a feature of hand saws.
It isn't applicable because there are no static types to infer.
Type inference can in some cases lead to type confusion in a way that can also happen with dynamic types. In my experience it is extraordinarily rare, especially in languages with only limited or local type inference like Rust or C++.
Type introspection is another thing entirely! That's basically reflection, which is nothing to do with anything mentioned so far. To be clear:
* Dynamic typing: types are not known at compile time
* Static typing: types are known at compile time and written down in the source code.
* Static typing with type inference: types are known at compile time and inferred rather than being explicitly written down
* Dynamic typing with type inference: nonsensical; not a thing
* Type introspection: types can be inspected by code at runtime. Unrelated to any of the above. Can be found (or not found) in both dynamically typed and statically typed languages.
Thanks for the overview. I agree with all, except for the "has nothing to do with" claim.
> Dynamic typing: types are not known at compile time.
That is just a top level description of a feature, the tip of the iceberg. What is needed for a language to support dynamic typing? The answer is not "has nothing to do with x"
where x is any of the above features.
Also a lot of types are known at compile time even if your language supports dynamic typing.
Also "compile time" is a vague term for an interpreted language, as the machine compatible code is generated at run time.
If you think a method called ‘someMethod()’ is a good idea, then it will probably return a type called ‘Something’ and you are back to the same problem.
I can understand what you are getting at. However, a more real world example should clear this up slightly. Both the variable name and method name are not conveying meaning in the above example.
val underperformingEmployee = selectLowestPerformingEmployee();
But there are already a lot of strange state management issues with this code style. I would expect something more like this in the wild
terminateWorstEmployee(){
var employee = hrService.lookupEmployeeByLowestPerformanceReview();
employeeTerminationService.initiateTermination(employee.id);
}
When things are named and abstracted properly, it should be very clear what is happening. var conventions won't save you here.
Assignment from method calls seems to be the most likely place where this could POSSIBLY cause confusion. Maybe we can compromise on variable assignment directly from constructors? That seems to be the clearest example where the extra text is purely noise. It also causes a lot of line wrapping which indirectly causes even more noise.
Why is that a strange statement?
Edit: Of course it is a perfectly valid statement, advocates of dynamic typing may indeed argue that. "It's better" depends on your context, of course. If you have 100 mediocre programmers taking turns on the same code, it's probably not better. One of the great things about TypeScript is that you can decide on the spot when "it's better": Usually it's better when you otherwise have to make a hand stand in the type system to express what you want.