You can read more about pros and cons of statically and dynamically type languages [1]
[1] http://programmers.stackexchange.com/questions/122205/what-i...
You can read more about pros and cons of statically and dynamically type languages [1]
[1] http://programmers.stackexchange.com/questions/122205/what-i...
For example, Elixir is a more "strict" dynamic language than your usual Python/Ruby/Javascript. Data is immutable. There is no monkey patching. Most state changes happen explicitly via process communication. The macro system is compile-time which means nothing will pull the carpet under your feet at runtime.
Also long-term productivity is about actually maintaining your system in production. And Elixir leverages 3 decades of experience on that, using a runtime designed to build systems that self-heal and are fault-tolerant (I slightly explore this here: http://blog.plataformatec.com.br/2015/06/elixir-in-times-of-...).
I don't want to give a yes or a no answer, I would just like to point out the line is much blurrier than that. It doesn't matter which type system you use, your code is going to have bugs or unexpected situations will arise, specially when we are talking about network. So knowing that your system system can heal itself is quite comforting.
Those are two complementary aspects. It is one of the reasons I would love to see a statically typed language succeed in the Erlang VM.
They're both statically typed, but the type systems obviously aren't equal. I would argue that stricter types are in fact one of the main things that helps me be more productive in languages with MLish type systems compared to C which lacks e.g. generics and proper sum types.
That said, I find Elixir very interesting for the exact reasons you said.
That was his point.
Elixir/Erlang aren't your typical dynamic language. Elixir is compiled and has pattern matching. I catch a ton of bugs at compile time in Elixir that I would never catch in Ruby/Python/JS until runtime. Examples of these are misspelled variables/bindings/function names and pattern match that will never actually match. Those are really, really common time wasters all taken care of at compile time.
Now what types of errors in Go really hurt you? Race conditions at runtime. I have to be way more careful about that to where it was costing me a lot of time in very concurrent programs. Eventually you develop a paranoia. Go has better tooling to help with this now, but concurrency and a language that prefers pointers just doesn't mix well. In Elixir I don't worry about this because everything is immutable. Now that GOMAXPROCS defaults to NumCPU I think a lot of programs that looked race condition-free probably aren't.
As far as runtime goes, Elixir and Go are at the same mercy but Elixir has much better debubbing capabilities than Go thanks to Erlang.
If you want something that gets you closer to static types and you have the discipline to keep up with running it and maintaining your type annotations, there's always dialyzer.[0].
It's an entirely different level of statically-verifiable correctness.
For example, if I have a function that returns {foo}, and I change it to return {foo, bar}, then a pattern match on its return value that does {Foo} -> ... will fail at runtime, and the compiler won't pick it up, right?
In a statically type language (such as Go), changing the number (or type) of return values will result in compilation errors until all callers have been updated.
Another example is instead of shuffling a bunch of bare UUID objects around (or strings, for that matter) in a system where lots of different things have a UUID, I can make a simple reference type for the IDs of different entities. This way, calling a function that takes the UUID of one type of entity with that of another can be a type error that's caught by the compiler instead of a logic error that's caught by a unit test. This is cumbersome at best to do in Java or C, and obviously impossible in Python or Ruby, but in ML-inspired languages it's simply the most natural way to work.
It might add some additional complexity in the first writing of the code, but in return you eliminate whole classes of problems forever. It's not just the initial writing that benefits (at some cost, admittedly), but all future changes won't have those problems either. In the case the types themselves need to change to account for expanded functionality or whatever, you again pay some cost in complexity, but in return every place the new type would cause problems you get a nice error.
The other thing to keep in mind is that whether or not these type are codified in the language they're there conceptually. Just because you have to write them down doesn't necessarily add complexity but is more like forced documentation that can be used to eliminate who classes of problems. It's difficult to see how this wouldn't intrinsically be better than so-called dynamic typing.
I'd dare say that diaylizer (Elixir's optional but easy to use type system) would lead to more maintainable code than Go's forced type system in the long run.
Orthogonal to all this is that I'm underwhelmed by Go's type system :/ If I was going to shoot for a language whose type system really helped me (in the ways I need/want help) it wouldn't be Go. It's pretty slick for some things (aesthetics aside) though.
I also agree that good type systems can reduce some forms of complexity (while often introducing another, but that's a different discussion).