I'd been a C/C++ programmer for about 10 years! I guess I just forgot that compilers can catch typos if you let them.
I know exactly the feeling, but I don't think it's just the types that give it but that it's compiled. I similarly moved on from ruby after 5 years but to Elixir and was similarly surprised to (re-) learn that a simple compile step catches so many braindead typos, misnamed variables, not imported function calls, and the like.
Types go above and beyond this, but I think there's a huge step up just going from interpreted to compiled.
The feedback loop is within your editor, that’s a step before the app console!
Before that, there was the Rhino and Nashorn ones, which although JavaScript based, did the job.
These days Kotlin is also pretty good. Perhaps not quite as fast to prototype but there’s little need for converting afterwards.
I wouldn’t necessarily recommend it, but I have written 500-line Python programs without executing/testing any functions along the way, that “just worked” the first time I ran them with no serious bugs. And not because I am especially clever or have an amazing memory or unusual attention to detail, but just because the code is easy to make clear and straightforward.
(But this was just with basic data types and a few standard library modules; dealing with other people’s poorly documented / confusing APIs makes this gets a lot harder.)
I inherited legacy Python projects at work and I'm shocked by the time I'm wasting fighting with the lack of types. Most of the time I have no idea (and my IDE neither) what methods and properties are available on variables and function parameters. And what's the most insane to me: I'm sitting next to people with LOT of experience in Python and I see them losing as much time as me when maintaining and debugging some basic piece of code they have written not even 2 weeks ago.
If I am really this lost with a piece of code in Python or Ruby, I usually start an integration test with an added line to call the debugger.
With introspection you can then easily see what methods a given object has.
> And what's the most insane to me: I'm sitting next to people with LOT of experience in Python and I see them losing as much time as me when maintaining and debugging some basic piece of code they have written not even 2 weeks ago.
That is insane. What kind of code coverage do you have and what kind of tests?
It is true that you have to write more tests in a dynamic language than in a static typed language but as tests often convey the information of what was intended to be done much better than code, I don't consider this a drawback.
But if the tests are lacking, you are at a much greater loss than with static typed languages.
With VS and C#, I can hit ctrl+space and get a list of absolutely everything that's in the contextually relevant public API. So much faster than introspection. If I'm using an object initializer to instantiate something, I can hit ctrl+space inside the object initializer to get a list of all the available public properties -- no typing the names required. No having to remember the order of arguments of methods, or even their types. Autocomplete means I can usually get away with somewhere between zero and three keypresses to get exactly what I want highlighted in the intellisense.
Forget efficiency via vim/emacs keybindings. Static typing + a strong intellisense/intellisense clone lets me code literally at the speed of my thoughts most of the time. I end up feeling like I'm stuck in molasses the few times I have to write some JS.
> It is true that you have to write more tests in a dynamic language than in a static typed language but as tests often convey the information of what was intended to be done much better than code, I don't consider this a drawback.
I understand your point, but for me, the extra tests I write in dynamic langs just end up making me feel like I've duplicated the work of the static checker in other languages, and in a non-reusable way.
For instance if features need to be demonstrated or prototyped on a test env. for some time before they are green lighted to be fully baked, loosely typed languages are ideal. You get the speed of prototyping, and all the heavy cost comes after the main parts have been validated.
It's less painful than having to do prototypes after prototypes in a more rigid language.
But of course this advantage disappears when working more in small waterfall iterations, where everything is basically set in stone from the start.