My problem is that both [Swift and Kotlin] have doubled down on strong static typing. Both seem to be intent on closing every single type hole in their parent languages.
But before you run out of fingers and toes, you have created languages that contain dozens of keywords, hundreds of constraints, a tortuous syntax, and a reference manual that reads like a law book. Indeed, to become an expert in these languages, you must become a language lawyer (a term that was invented during the C++ era.)
Why are these languages adopting all these features? Because programmers are not testing their code. And because programmers are not testing their code, we now have languages that force us to put the word
openin front of every class we want to derive from. We now have languages that force us to adorn every function, all the way up the calling tree, with
try!. We now have languages that are so constraining, and so over-specified, that you have to design the whole system up front before you can code any of it.
All these constraints, that these languages are imposing, presume that the programmer has perfect knowledge of the system; before the system is written.
Not in total agreement with the post, but quite a lot of agreement.
A type system is only as static as the code it describes. If you can change code, you can change types! The machine can even help you.
I don’t think it’s an either/or situation at all: we can have a solid type system and write “manual” tests.
A type checker actually does testing for you. It’s not a replacement for TDD, but it allows you to completely get rid of a whole bunch of tests.
In Swift, once you change
footo return an
Int?, the compiler will now show an error for each time you call
foo. This makes it easy to make that change, because until you have reviewed every single call to
foo, the program simply won’t compile. I think of the compile errors as a todo-list, not as a speed bump.
I’m pro testing but I think this matches my thoughts exactly, almost anything you can do to get errors earlier in dev process is worth it.
I like both testing and types. The problem is that sometimes types get in the way. It would be nice to be able to do some work in a more dynamic style and then nail things down before shipping. That is the promise of type inference, but it’s not the reality of developing in Swift today.
Update (2017-01-12): Isaiah:
i wish i could have both. static typing is really useful sometimes. really a burden other times.
My main problem with Swift has always been this: far too pedantic about types and complete lack of a dynamic runtime.
Update (2017-01-13): Mark Bernstein:
Reading this debate, I was startled to realize one thing I’d overlooked: I almost never make type errors. I make plenty of errors – for me, programming is always about correcting errors – but type errors are once in a blue moon affairs.
I wonder if strong typing is a solution to a problem we don’t really have, or whether I’m just Doing It Wrong.
I concur. I think Swift’s optionals solve a real problem. The stronger typing, e.g. for collections, can make calling APIs more concise and help with auto-completion, but I don’t see this preventing many errors for me.
Update (2017-01-14): Robert C. Martin:
To be clear, and at the risk of being repetitive, that blog was not an indictment of static typing. I rather enjoy static typing. I’ve spent the last 30 years working in statically typed languages and have gotten rather used to them.
My intent, with that blog, was to complain about how far the pendulum has swung. I consider the static typing of Swift and Kotlin to have swung too far in the statically type-checked direction. They have, IMHO, passed the point where the tradeoff between expressiveness and constraint is profitable.
You might therefore say that the type system is a kind of “test” that fails for all inappropriate invocations of
f. I might concede that point except for one thing – the way
fis called has nothing to do with the required behavior of the system. Rather it is a test of an arbitrary constraint imposed by the programmer. A constraint that was likely over specified from the point of view of the system requirements.
So what the type system is checking is not the external behavior of the program. It is checking only the internal consistency of the program text.
Stay up-to-date by subscribing to the Comments RSS Feed for this post.