Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

- I accidentally pass in 3 params instead of 4 to a function (with static typing this does not compile)

In Erlang this will also not compile, unless you have a 3 parameter version of the function, in which case static typing will not help you.

- I forgot to handle an edge case (I can use a discriminated unions for example to handle all cases explicitly)

You also forgot to write a test it sounds like. And if it affects your production code, you also forgot to think through your supervisor restart strategy.

- I did not check if something was null and pass it in to a function (does not happen in most ML languages)

Null isn't a special thing in Erlang. You can have the atom 'null' or 'undefined' or whatever, but that's an intentional assignment you create. And given the single assignment immutable nature of Erlang, you won't accidentally be setting/leaving things set to 'null'.



I am not GP.

> unless you have a 3 parameter version of the function, in which case static typing will not help you

I half disagree. Let's say we go with the above scenario. If you have a three parameter function, static typing adds a check that the input parameter types need to match, if they don't, the program will not compile. Additionally, the returned type of the function may also not match, which would also be caught by the compiler, and depending on when the developer is writing the code, maybe immediately by the developer noticing that the type signature of the function does not match what they expect.

With dynamic typing, those checks have to happen at runtime or as a human written test. But if the compiler is smart enough to do it automatically, why not use that?

> You also forgot to write a test it sounds like. And if it affects your production code, you also forgot to think through your supervisor restart strategy.

Programming languages like F# have exhaustive pattern matching, which obviates the need for testing on whether all cases of a union type have been matched, because if they haven't, the compiler will emit a warning or error depending on one's language server settings. Whichever setting is used, the developer immediately knows they are missing a pattern match case at compile time.

>ngiven the single assignment immutable nature of Erlang, you won't accidentally be setting/leaving things set to 'null'.

This is similar to ml languages like F#. They are also immutable by default. F# calls it "unit".


I was specifically responding to "calling a 4 parameter function with 3 parameters". In the case you have a 3 parameter function, and pass in the wrong type, static typing -may- help you...but most languages that allow that that are statically typed allow for function overloading (since functions are then defined not by name and # of args, but name and types of args). If you overload the 3 param variant, static typing can't help ensure you pick the right one, just one that exists. That was my point; you still have to write proper tests, and that not only has the benefit of ensuring you're calling the right function, but that it also does what you want.

Re: testing - regardless of whether you have static typing or not, you should be exhaustively testing every pattern you match on, to ensure you're doing the right thing. If you don't, you don't care about the behavior in those cases - in most languages that's a problem, in Erlang it's a "if that happens, supervisor restarts", and you focus your effort on ensuring restarts put you back into a good state (which you do anyway, ergo, no additional work unless you choose to invest it).

Erlang is a little unique in this regard; it's not that it doesn't have error handling and that static typing might not be a benefit, it's that proper focus should be on the supervisor strategy and "what happens when things go wrong". Of course things that reduce how often things go wrong are helpful (for log consumability if nothing else), but they don't buy you that much if you're doing things correctly; the whole 'correctness' mechanism is separate and distinct from those concerns (whereas most other languages it is not).


Running Dialyxer in VSCode usually tells me if I pass in the incorrect arguments. Sometimes it’s a chore figuring out precisely what isn’t working given the complex typing dialyzer uses (essentially unions). In F# I spent a lot of time trying to make the compiler happy. Some odd invariant that the error didn’t explain well. So there are trade offs both ways. I like the Elixir way, just enough typing to help catch dumb mistakes but dynamic enough that I don’t have to convince the compiler to do something.


> You also forgot to write a test it sounds like. And if it affects your production code, you also forgot to think through your supervisor restart strategy.

With a statically typed language I (or my teammates, or people who write libraries I use) cannot forget to write a test for something like that because the type system ensures that it is caught. I don't have to worry about someone forgetting to write tests, and I don't have to wait until they've got a suitably large test suite to be certain of the guarantees the code can make.


Passing the wrong type in in a dynamic language doesn't matter -unless it leads to the wrong behavior-. If you aren't testing the behavior, dynamic or static language, you're missing a test case. If you ARE testing the behavior, then dynamic or static doesn't matter; the function works when passed that type of data.


> Passing the wrong type in in a dynamic language doesn't matter -unless it leads to the wrong behavior.

At which point, it really matters and then you spend more time and effort checking and fixing incorrect types. My application crashing because some deep dependency wanted an integer instead of a string, and neglected to tell me is an annoying experience that slows me down, and having to write messy code to validate everything ends up getting in the way of actual business logic. Wildly sending variables into functions and just hoping it won't crash or behave incorrectly and then relying on devs writing comprehensive-enough tests to cover everything produces fragile code in my opinion. Writing and maintaining boilerplate tests just to ensure basic behaviour (before we even get to testing the actual functionality) instead of relying on a type system to simply prevent those issues from ever occurring in the first place seems like a mistake to me.


>> I accidentally pass in 3 params instead of 4 to a function (with static typing this does not compile)

> In Erlang this will also not compile, unless you have a 3 parameter version of the function, in which case static typing will not help you.

This is only true if the function you are calling is part of the same module (and is not called in module:func(Args)-form). If it's not, Erlang will happily compile it and you'll have to rely on xref to catch the error.

This is one of the compromises it takes to get hot code reload.


Have you written code in an ML flavored statically typed language? If not then I highly recommend experiencing it. Your post (especially that second reasoning) reminds me of my pre-ML days when I used to be rabidly anti-static typing.

In theory what you say is equivalent, but in practice, thinking about these things at the design phase is far more easier than to handle them with testing (which is pretty forgiving if you miss things).

https://i.redd.it/2uxj8u6yx9121.png


I'm not rabidly anti-static typing. If anything, I -prefer- it. I use Dialyzer and type specs when writing production Erlang code. I actually -wish- Erlang had better static typing options.

But I recognize that as -personal preference- when it comes to Erlang. It allows me (and my teammates) to be explicit, and the machine helps me (us) be consistent in my explicitness, even when, again, via experience, I know it doesn't really effect how reliable the code is. Reliability in Erlang comes from testing, and proper supervisor patterns and reasoning. Static typing might reduce the number of supervisor restarts, but it doesn't reduce my test surface, nor the need to ensure arbitrary restarts get my system back to a good state. Even when using Dialyzer, it didn't push the needle on how reliable the system was. It just changed the characteristics of writing/reading the code; a bit more work to write, a bit less work to read.


I am totally with you. I was just saying that for me personally some static type checking would really help, not particularly with Erlang but with other duck typing languages.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: