Erlang's niche is distributed systems anyway, an area where static typing is at odds more often than not. I mean, you can guarantee the executable you are working on is exempt of typing errors, but it's just a small component of the overall architecture. What about data you are receiving? What if some remote client is using an older version of your software? What if the web service you are calling changed its API recently?
I use Elm, which is as statically-typed as possible for a client webapp, but I know I can never guarantee that JSON data I receive from remote servers is of the expected type.
I find static typing is extremely useful in the case where you're receiving JSON though - I write the server side and we use Scala. For us we write the type we expect, validate the input as soon as it hits the server (in the controller), fail immediately if it doesn't validate and if it does validate then we're dealing with that type in all the rest of the code. Obviously that's not going to handle receiving a shape of data that you don't expect, but you'll error immediately and I find it really robust in practice.
Dynamic languages do this with schema validation. It can be more expressive, checking value ranges or string formats, multi field conditional constraints, and so on. And allows better& customizable diagnostics.
Edit: also, versioning, cross language sharing, use in generative testing, api client code generation and other metaprogramming uses. And documentation generation, eg swagger
See e.g. JSON schema, which has a wide language support and tooling (even some IDEs support it for validation while you're writing a compliant document)
> Erlang's niche is distributed systems anyway, an area where static typing is at odds more often than not.
I've worked on a lot of distributed systems, and I don't see what this has to do with anything. Yes, static typing doesn't prevent you from doing any of the things you mentioned like changing your API out from under someone, but it's not supposed to. It Does however prevent certain classes of mistake in the individual service or executable, which is still a laudable goal in and of itself. It's not a silver bullet, but it's no less useful in distributed systems than it is anywhere else.
Also, are we talking about strong typing or static typing? The OP said one thing and this reply says another. Either way, both are nice in distributed systems too.
I've come to believe that modern type systems are not primarily about types. They are mostly useful static code analysers. Sometimes you can use them to optimize the machine code generated by the compiler, but they are much more about enforcing constraints at compile time on the abstractions we build in code. System boundaries in distributed systems are just places where you have to declare and dynamically validate what other systems send in. Validating how you use those inputs according to your declared constraints at compile time is still very useful.
Static typing with uncontrolled input, whether user input or distributed systems running multiple versions, is handled via "Don't trust, verify!". Structures and inputs are validated at the ingress so that the rest of the code of you application can rely on static type checks. If the validation fails the entire request can be immediately rejected.
This is rediculous. If I'm dealing with something that completely terminates quickly, like the Python in Meson or Nix in Nixpkgs, maybe I can get away with not having static types and still get work done.
If I'm dealing with some complex long-lived distributed system, I don't have time for the bullshit errors no static type checking allows. I'm already waist-deep with real problems!
Also if you control the client and the server, do not just blindly follow Postel's law and except crappy data. Be rigid and lo, and behold, one side quickly excises all the bugs in the other.
Oh, come on, static typing does not prevent all type errors. Everything what arrives on the wire can blow your program up.
> Also if you control the client and the server, do not just blindly follow Postel's law and except crappy data.
But in real world, we do not livd in a bubble. Very often, we do not have the comfort of controlling the server and the client. We have keep edge cases in mind. Unexpected errors / cases happen.
I’m guilty of HN generalisation. It depends on the language implementation of type system. In Java - any null can blow your program out. Type system is not going to help. Golang, with interfaces and nil pointers can blow you out of the water.
So whenever something was expected to arrive from the wire, it does not parse correctly, depending on the parsing method, once you have that null, all bets are off. Type system gave up.
It all depends.
Another example is Java interfaces. Merely checking for an interface type does not prevent errors down the line. It does limit the amount of errors.
Sure, but now you're enforcing types manually instead of with a type system. What have you gained over not having a type system? In this case, nothing.
It's still enforced by the type system. The type-safe deserialization libraries nowadays use 'result' types to indicate success or failure. The compiler forces you to handle both.
This seems like an overstatement since protobufs (for example) are a widely used way of describing a common data format for distributed systems and they do support static types. Though, common practice is to make all fields optional.
Types can also be very useful for security, to keep track of which runtime safety checks need to be done. For example, you can have a separate type for HTML strings that can be rendered without escaping.
I use Elm, which is as statically-typed as possible for a client webapp, but I know I can never guarantee that JSON data I receive from remote servers is of the expected type.