For my $0.02 - it depends where you want to put the onus

Statically typed languages put the onus on the caller to transform the data into the shape(s) required.

Dynamically typed languages put the onus on the called to handle anything.

That is, in a dynamically typed environment your function has to defensively code for every possible type it could be handed.

Nobody writes dynamically typed functions that can be called with any possible type.

It's not about that at all. Static types give you errors reliably at compile time instead of randomly at runtime, better documentation of what the code expects (people writing dynamically typed languages eventually resort to type comments), working IDE support, reliable refactoring and better code, all of which results in faster development.

The cost is a more complex language, occasionally difficult-to-write types, and very occasionally impossible-to-write types. But those are very very minor in comparison to the pros.

> (people writing dynamically typed languages eventually resort to type comments)

This has never been an issue in Elixir, because instead of a comment, you'd just improve the pattern matching in the function definition.

    def blah(%{students: [%{firstname: firstname, lastname: lastname}|[]], count: cnt}) when is_int(cnt):
      fullname = firstname <> lastname
Is a valid function declaration, which specifies that blah takes a dictionary that contains at least 2 keys, :count, who's value is an integer, and :students, who's value is a length-1 list who's first element is a dictionary that contains the keys :firstname and :lastname

is_int is doing the work of a type checker?

I mean I'm not an Elixer guy (not at all) so it's a bit opaque to me how that's not an enforcement of specific types (albeit the firstname, lastname can be anything?)

Once we get into the function itself, if two incompatible types, say a string and a filehandle.. (just random attempt, you may, if you choose, point to why the two types must have some alignment), what happens - the function dies?

That's my core issue with dynamic typing, you might argue that the function's explosion has a restricted blast radius, but that's not the point, the point is that the function was called, and was unable to compute whatever, and that's a bug.