I used to think several years ago, that the main benefit of strong static typing was code safety / eliminating a whole class of bugs. But I've changed my opinion. I now think the biggest benefit is that it makes the code a lot easier for other people to read and understand.
I mean I have multiple personal projects where I've used Python (which is a dynamically typed language), but these are small one-off projects. But I think when working in a team, especially a large team, having types becomes a huge thing. Having types for objects is especially useful. Having types forces you to think more clearly about the structure of your data.
It's really sad when I see `foo(bar)`, and I have no idea what the type of `bar` is, and if it's an object, I have no idea what fields `bar` has. I have to simply guess the structure of the various implicit types by looking at the code (sigh). It makes the code difficult to read, and rather unpleasant to work on. Not to mention, all the multitude of bugs that come from duck/dynamic typing.
I don't think good statically typed languages are hard to use at all. Type inference has spread everywhere that the old argument of having to repeat your types doesn't hold anymore. TypeScript, Flow (JavaScrpt), Haskell, languages from the ML family are really good at type inference. Even the `auto` type inference in C++17 was better than I'd expected.
You can see typed examples here: http://mypy-lang.org/examples.html
Well no, since the compiler isn't checking types and you need a third party tool for that. So it's not optional typing.
PHP does have run-time optional typing and was successful at retrofitting a static type system in a completely dynamic language.
Mypy is just a static analysis tool.
Indeed. I find one of the most elegant recent examples is this snippet in Kotlin (yes, this is fully and statically typed): https://kotlinlang.org/docs/reference/type-safe-builders.htm...
import com.example.html.*
fun result(args: Array<String>) =
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
// an element with attributes and text content
a(href = "http://kotlinlang.org") {+"Kotlin"}
// mixed content
p {
+"This is some"
b {+"mixed"}
+"text. For more see the"
a(href = "http://kotlinlang.org") {+"Kotlin"}
+"project"
}
p {+"some text"}
// content generated by
p {
for (arg in args)
+arg
}
}
}Obfuscated spaghetti code and write-only programs can be written in any language. I've seen plenty of convoluted OCaml programs, with tons of one-letter variable names and no comments. And don't get me started on Haskell's propensity for using dozens of non-alphabetic operators that make it read more like line noise than Perl, not to mention its famous easy to understand monads or easy to reason about lazyness, on top of the community propensity for one-letter variable names, same as with OCaml. Static typing does not save badly written programs in either of these languages.
Besides, you can add type annotations to your Python programs, and even have them checked by mypy. Those programs might even wind up being easier to read than programs written in a statically-typed language where the programmer relied on type inference. But they won't necessarily be any more readable, as readability has less to do with types than it does with the programmer and the reader.
As he makes a pretty good case for, there’s a lot to like about dynamically typed languages. But, everywhere I look in Clojure, I feel like the language is more principled than Python. There’s also Spec, which allows developers to exercise even more rigor without jumping to static types.
Going even further, Racket lets you move to a type system as you want to, but not before.
I’d like to imagine that there’ll be more of these middle ground approaches over time, without having to commit to either the freewheeling status quo of Python or the rigidity of Haskell.
EDIT: I should note that even Python is moving that way as there are now optional type annotations.
With a statically typed language, you still have to look through the code to find the definition of an object. I believe that can be avoided by having easy to access to documentation which would also apply to dynamically typed languages like Python.
staring at five year old project, started as a one-off quick'n'dirty prototype, having gone through many hands doing one-off quick'n'dirty additions since then
What documentation?
But seriously - I don't have to "look through the code". It's a few keystrokes at most and it's always there and correct.
I use Python every day, and the sad (but improving!) state of typing is one of my biggest grievances. Documentation doesn't close the gap because it is often incorrect or outdated; I've added more than a couple production bugs because I trusted the documentation. A type checker is necessary to keep the type annotations in line with the source code.
Static typing (or, more to the point, compile time structure that doesn't require running the code to get right, but the two are closely linked) makes tooling to avoid manual lookups easier to implement and more reliable.
I haven't done this in the last 10 years. I typically use IDEs, and every IDE I've used has had a "Go To Definition/Declaration" feature, and let you set a key binding for it. On JetBrains' IDEs, I've gotten quite used to pressing Ctrl+B to jump to a type definition's, and then pressing Alt+← to jump back to where I was originally in the code.
This is also available in some dynamically typed languages, working just fine.
No, not even close to the same level.
Shudder.
get_product(id)
Now, have fun figuring whether the id is a string or an integer. Without knowing anything about the method, it's pretty sure that it will only work with only one or the other.Let's say you get the id from a HTML form as a string, and want to pass it to the library. Do you need to first convert it to an int? A uuid.UUID object? A custom ID class in the library? Is passing None allowed?
A type declaration on the get_product() function would tell you, and let the compiler to check your code for mistakes.
You look at code and you have no idea what is what. You have to be on your toes ALL THE TIME!
Even when you are editing a method on a class you cannot safely assume that all the properties will exist because someone can come along and create an instance of the class in a non-standard way such that a property you expect to always exist will not exist in that one situation.
shrug just document the interface and stick to it.
If you want to keep things simple, create data structures using namedtuple. You get really sane objects that are definitely POLA [1] compliant.
> You look at code and you have no idea what is what.
You should consider type hints [2] and/or docstrings [2].
[1] https://en.wikipedia.org/wiki/Principle_of_least_astonishmen...
I always use type hints when I write new code. Because 3.4 has no type hints for class member declarations I end up writing constructors that take parameters then assign them to self. This way PyCharm will properly detect the type of class members.
I understand the comment about type inference allowing less typing.
However, I don't understand the OP's statement that type inference provides more flexibility. Any program that type checks under type inference will also type check if the inferred types are made explicit via annotations, so I'm not sure what the OP means by inference providing flexibility, unless they just mean trivial flexibility of surface syntax.
I think the OP may be conflating type inference and gradual/optional typing, but it's hard to be sure from such terse comments.
* Safety: Each data carries it's type at run-time, there are no overflow or NULL ptr problems as in statically typed languages. E.g. arithmetic is exact. Memory Safety.
* Easier to develop and debug: You don't have to get right at the first, time, you can iteratively improve the code, e.g. via debugging or refinements, until it works correctly. With statically typed language you have to first make it compile and fix all the errors at once. Generic data structures and methods are much easier to use than specialized.
> Safety: Each data carries it's type at run-time
With a statically typed language, this is not necessary for safety, since the compiler has already checked that the types are correct.
> there are no overflow
Do you mean integer overflow? This is completely orthogonal to the static/dynamic typing distinction.
> or NULL ptr problems as in statically typed languages
This is also completely orthogonal to the static/dynamic typing distinction. Remember that C and C++ do not constitute the entirety of statically typed languages.
> E.g. arithmetic is exact
What does this even mean?
> Memory Safety.
Again, C and C++ do not constitute the entirety of statically typed languages.
Consensus is that static type checking did not help in ensuring memory and concurrency safety (sans the 2 or 3 weird safe languages nobody uses or knows about). The compiler cannot ensure these safeties when the language and VM is too poor to ensure it. I only know ATS, Pony, Idris, Agda and a few more who can ensure proper compile-time safety. Of course static type aficionados are in denial on this point. This is the argument mostly from the LISP community. For the static folks their type system is good enough. Fine for them. Other languages just do it better.
As history has shown dynamically typed languages can easily ensure much more safeties. Esp. arithmetic safeties, with overflows, from int to bigint, from ops to rational, from double to bigfloat, ... This is not at all orthogonal to static/dynamic typing distinction, as the static type systems forbid that. Did you see any union typed arithmetic? Most dynamic languages have that.
> NULL ptr problems completely orthogonal ...
Of course not. I only know a few NULL safe statically typed languages nobody uses. Dynamically typed langs check for these issues in the runtime, thus are safe.
> E.g. arithmetic is exact. What does this even mean?
Oh my. Hope you will never be allowed to work in finance. I know nobody cares about getting numbers right, but speed is not everything. Avoiding underflows and overflows, guaranteeing exact arithmetic with proper type promotions. Ever heard of bigint or rationals? The world doesn't consist only of int, double and decimal. And with e.g. SBCL you have speed and safety.
> Memory Safety. C and C++ ...
But mostly. Add the next 3: Java, Rust, Go from which Rust is also not memory safe.
(I personally would also disagree with your second point, but that is more a matter of opinion.)
I think there's also no consensus that forcing you to run code to (maybe, if you happen to have chosen the right input values) find errors that could be caught statically really makes it easier to develop.