I don’t think anyone ever hated type safety, I think they hated verbose syntax and unfortunately conflated the two.
Now we’re finding a happy medium with compiler type inference and people are like, wait what?
I don’t think anyone ever hated type safety, I think they hated verbose syntax and unfortunately conflated the two.
Now we’re finding a happy medium with compiler type inference and people are like, wait what?
For example, functions that return a different type depending on the values passed in are a useful pattern, but not allowed in staticly typed languages, except those with dependent types (Idris) or runtime downcasting (Go). There's always a way to acheive the same thing, but usually at the cost of safety or much more verbosity.
This is actually, IMHO, one way Go strikes a happy balance between static and dynamic typing. It provides a (runtime) safe and low-verbosity way to write dynamically-typed code, i.e. `interface{}`. Rust is slated to get something similar with `impl Trait` values.
Look at this verbose OCaml:
type my_return_type = AFloat of float | AnInt of int | AString of string;;
let my_fun n =
if n < 0 then AString "negative"
else if n == 0 then AFloat 0.0
else AnInt n
# my_fun (-4);;
- : my_return_type = AString "negative"
# my_fun 0;;
- : my_return_type = AFloat 0.
# my_fun 42;;
- : my_return_type = AnInt 42
(But yes, to use these values you have to do pattern matching, and if you're in a FUD mood, that is "runtime downcasting" and incurs a "cost of safety".)In a dependently typed language, you could reduce verbosity at the use site as well as avoid the extra runtime branch.
Since Go 1.9 was released with its new Type Aliases feature a few months ago, the verbosity is even lower. By putting `type any = interface{}` somewhere in your package, you can just write `any` instead of the verbose `interface{}` everywhere you want some dynamic typing.